aboutsummaryrefslogtreecommitdiff
path: root/src/screens/profile/CaptionScreen.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/screens/profile/CaptionScreen.tsx')
-rw-r--r--src/screens/profile/CaptionScreen.tsx409
1 files changed, 245 insertions, 164 deletions
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx
index 912865ae..38c6d8f0 100644
--- a/src/screens/profile/CaptionScreen.tsx
+++ b/src/screens/profile/CaptionScreen.tsx
@@ -1,9 +1,10 @@
import {RouteProp} from '@react-navigation/native';
import {StackNavigationProp} from '@react-navigation/stack';
-import React, {Fragment, useEffect, useState} from 'react';
+import React, {FC, useEffect, useMemo, useState} from 'react';
import {
Alert,
Image,
+ ImageSourcePropType,
Keyboard,
KeyboardAvoidingView,
Platform,
@@ -13,20 +14,25 @@ import {
TouchableWithoutFeedback,
View,
} from 'react-native';
-import {MentionInputControlled} from '../../components';
-import {Button, normalize} from 'react-native-elements';
+import {Button} from 'react-native-elements';
import Video from 'react-native-video';
import {useDispatch, useSelector} from 'react-redux';
import FrontArrow from '../../assets/icons/front-arrow.svg';
-import {SearchBackground} from '../../components';
+import {
+ MentionInputControlled,
+ SearchBackground,
+ TaggSquareButton,
+} from '../../components';
import {CaptionScreenHeader} from '../../components/';
import TaggLoadingIndicator from '../../components/common/TaggLoadingIndicator';
import {TAGG_LIGHT_BLUE_2} from '../../constants';
import {
+ ERROR_NO_MOMENT_CATEGORY,
ERROR_SOMETHING_WENT_WRONG_REFRESH,
ERROR_UPLOAD,
SUCCESS_PIC_UPLOAD,
} from '../../constants/strings';
+import * as RootNavigation from '../../RootNavigation';
import {MainStackParams} from '../../routes';
import {
handlePresignedURL,
@@ -41,7 +47,7 @@ import {
} from '../../store/actions';
import {RootState} from '../../store/rootReducer';
import {MomentTagType} from '../../types';
-import {SCREEN_WIDTH, StatusBarHeight} from '../../utils';
+import {isIPhoneX, normalize, SCREEN_WIDTH, StatusBarHeight} from '../../utils';
import {mentionPartTypes} from '../../utils/comments';
import {Trimmer, VideoPlayer} from 'react-native-video-processing';
@@ -49,28 +55,29 @@ import {Trimmer, VideoPlayer} from 'react-native-video-processing';
* Upload Screen to allow users to upload posts to Tagg
*/
type CaptionScreenRouteProp = RouteProp<MainStackParams, 'CaptionScreen'>;
+
type CaptionScreenNavigationProp = StackNavigationProp<
MainStackParams,
'CaptionScreen'
>;
+
interface CaptionScreenProps {
route: CaptionScreenRouteProp;
navigation: CaptionScreenNavigationProp;
}
const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
- const {title, screenType, selectedTags, moment} = route.params;
+ // moment is only present when editing
+ const {moment} = route.params;
const {
user: {userId},
} = useSelector((state: RootState) => state.user);
const dispatch = useDispatch();
const [caption, setCaption] = useState(moment ? moment.caption : '');
const [loading, setLoading] = useState(false);
- const [tags, setTags] = useState<MomentTagType[]>(
- selectedTags ? selectedTags : [],
- );
- const [aspectRatio, setAspectRatio] = useState<number>(1);
- const [taggedList, setTaggedList] = useState<string>('');
+ const [tags, setTags] = useState<MomentTagType[]>([]);
+ const [taggedUsersText, setTaggedUsersText] = useState('');
+ const [momentCategory, setMomentCategory] = useState<string | undefined>();
const mediaUri = moment ? moment.moment_url : route.params.media!.uri;
// console.log('mediaUri', mediaUri);
// TODO: change this once moment refactor is done
@@ -84,48 +91,68 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
: route.params.media?.isVideo ?? false;
useEffect(() => {
- setTags(selectedTags ? selectedTags : []);
- }, [selectedTags]);
+ setTags(route.params.selectedTags ?? []);
+ }, [route.params.selectedTags]);
useEffect(() => {
- const getTaggedUsersListString = () => {
- let listString = '';
- for (let i = 0; i < tags.length; i++) {
- if (listString.length < 21) {
- listString = listString.concat(`@${tags[i].user.username} `);
- } else {
- break;
- }
+ setMomentCategory(route.params.selectedCategory);
+ }, [route.params.selectedCategory]);
+
+ useEffect(() => {
+ let listString = '';
+ // Append non-truncated usernames together and no more than 21 characters total
+ // e.g. "@ivan.tagg"
+ // e.g. "@ivan.tagg @foobar . . ."
+ for (const tag of tags) {
+ const usernameStr = `@${tag.user.username} `;
+ if (listString.length + usernameStr.length > 21) {
+ listString = listString.concat('. . .');
+ break;
+ } else {
+ listString = listString.concat(usernameStr);
}
- setTaggedList(listString);
- };
- getTaggedUsersListString();
+ }
+ setTaggedUsersText(listString);
}, [tags]);
- const navigateToProfile = () => {
- //Since the logged In User is navigating to own profile, useXId is not required
- navigation.navigate('Profile', {
- screenType,
- userXId: undefined,
- });
- };
-
- const handleFailed = () => {
+ const handleFailed = (noCategory = false) => {
setLoading(false);
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: true,
+ });
setTimeout(() => {
- Alert.alert(moment ? ERROR_SOMETHING_WENT_WRONG_REFRESH : ERROR_UPLOAD);
+ if (noCategory) {
+ Alert.alert(ERROR_NO_MOMENT_CATEGORY);
+ } else {
+ Alert.alert(moment ? ERROR_SOMETHING_WENT_WRONG_REFRESH : ERROR_UPLOAD);
+ }
}, 500);
};
const handleSuccess = () => {
setLoading(false);
- if (moment) {
- setLoading(false);
- navigation.goBack();
- } else {
- navigateToProfile();
+ navigation.dangerouslyGetParent()?.setOptions({
+ tabBarVisible: true,
+ });
+ if (!moment) {
+ // if posting, pop all screens until at camera screen (default upload screen)
+ // then switch to the profile tab
+ navigation.popToTop();
+ RootNavigation.navigate('ProfileTab');
setTimeout(() => {
- Alert.alert(SUCCESS_PIC_UPLOAD);
+ if (isMediaAVideo) {
+ Alert.alert(
+ 'Beautiful, the Moment was uploaded successfully! Check back in a bit and refresh to see it!',
+ );
+ } else {
+ Alert.alert(SUCCESS_PIC_UPLOAD);
+ }
}, 500);
+ } else {
+ // if editing, simply go back to profile screen
+ navigation.navigate('Profile', {
+ userXId: undefined,
+ screenType: route.params.screenType,
+ });
}
};
@@ -140,15 +167,15 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
const handleShare = async () => {
setLoading(true);
- if (moment || !title) {
- handleFailed();
+ if (moment || !momentCategory) {
+ handleFailed(true);
return;
}
let profileCompletionStage;
let momentId;
// separate upload logic for image/video
if (isMediaAVideo) {
- const presignedURLResponse = await handlePresignedURL(title);
+ const presignedURLResponse = await handlePresignedURL(momentCategory);
if (!presignedURLResponse) {
handleFailed();
return;
@@ -161,7 +188,12 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
handleFailed();
}
} else {
- const momentResponse = await postMoment(mediaUri, caption, title, userId);
+ const momentResponse = await postMoment(
+ mediaUri,
+ caption,
+ momentCategory,
+ userId,
+ );
if (!momentResponse) {
handleFailed();
return;
@@ -176,19 +208,22 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
return;
}
}
- dispatch(loadUserMoments(userId));
+ if (!isMediaAVideo) {
+ dispatch(loadUserMoments(userId));
+ }
if (profileCompletionStage) {
dispatch(updateProfileCompletionStage(profileCompletionStage));
}
handleSuccess();
};
- const handleDoneEditing = async () => {
+ const handleSubmitEditChanges = async () => {
setLoading(true);
- if (moment?.moment_id) {
+ if (moment?.moment_id && momentCategory) {
const success = await patchMoment(
moment.moment_id,
caption,
+ momentCategory,
formattedTags(),
);
if (success) {
@@ -200,17 +235,46 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
}
};
- const [currentTime, setCurrentTime] = useState(0);
- const [startTime, setStartTime] = useState(0);
- // todo: update with vid times
- const [endTime, setEndTime] = useState(60);
+ const SelectableItem: FC<{
+ text: 'Tag Friends' | 'Category';
+ imageUri: ImageSourcePropType;
+ onPress: () => void;
+ }> = ({text, imageUri, onPress}) => {
+ return (
+ <TouchableOpacity
+ onPress={onPress}
+ style={styles.selectableItemContainer}>
+ <View style={styles.row}>
+ {text === 'Category' && !momentCategory && (
+ <Text style={styles.asteriskText}>* </Text>
+ )}
+ <Image style={styles.tagIcon} source={imageUri} />
+ <Text style={styles.selectableItemTitle}>{text}</Text>
+ </View>
+ <View style={styles.row}>
+ {text === 'Tag Friends' && (
+ <Text style={styles.itemInfoText}>{taggedUsersText}</Text>
+ )}
+ {text === 'Category' && (
+ <Text style={styles.itemInfoText}>{momentCategory}</Text>
+ )}
+ <FrontArrow
+ width={normalize(13)}
+ height={normalize(13)}
+ color={'white'}
+ />
+ </View>
+ </TouchableOpacity>
+ );
+ };
return (
<SearchBackground>
- {loading ? <TaggLoadingIndicator fullscreen /> : <Fragment />}
+ {loading && <TaggLoadingIndicator fullscreen />}
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
+ keyboardVerticalOffset={isIPhoneX() ? 40 : 30}
style={styles.flex}>
<View style={styles.contentContainer}>
<View style={styles.buttonsContainer}>
@@ -219,104 +283,84 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => {
buttonStyle={styles.button}
onPress={() => navigation.goBack()}
/>
- <Button
- title={moment ? 'Done' : 'Share'}
- titleStyle={styles.shareButtonTitle}
- buttonStyle={styles.button}
- onPress={moment ? handleDoneEditing : handleShare}
- />
</View>
- <CaptionScreenHeader
- style={styles.header}
- {...{title: moment ? moment.moment_category : title ?? ''}}
- />
- {isMediaAVideo ? (
- <View style={styles.mediaContainer}>
- {/* <VideoPlayer
- //style={styles.media}
- ref={(ref) => (this.videoPlayerRef = ref)}
- startTime={startTime} // seconds
- endTime={endTime} // seconds
- play={true} // default false
- replay={true} // should player play video again if it's ended
- //rotate={true} // use this prop to rotate video if it captured in landscape mode iOS only
- source={mediaUri}
- playerWidth={360} // iOS only
- playerHeight={680} // iOS only
- //resizeMode={VideoPlayer.Constants.resizeMode.CONTAIN}
- onChange={({nativeEvent}) =>
- setCurrentTime(nativeEvent.currentTime)
- } // get Current time on every second
- />
- <Trimmer
- source={mediaUri}
- height={50}
- width={350}
- onTrackerMove={(e) => setCurrentTime(e.currentTime)} // iOS only
- currentTime={currentTime} // use this prop to set tracker position iOS only
- themeColor={'white'} // iOS only
- showTrackerHandle={true}
- thumbWidth={10} // iOS only
- trackerColor={'green'} // iOS only
- onChange={(e) => {
- setStartTime(e.startTime);
- setEndTime(e.endTime);
- }}
- /> */}
+ <CaptionScreenHeader style={styles.header} title={'Moments'} />
+ <View style={styles.captionContainer}>
+ {isMediaAVideo ? (
<Video
+ style={styles.media}
+ source={{uri: mediaUri}}
+ repeat={true}
+ />
+ ) : (
+ <Image
+ style={styles.media}
source={{uri: mediaUri}}
- volume={1}
- style={[
- styles.media,
- {
- height: SCREEN_WIDTH / aspectRatio,
- },
- ]}
- repeat={false}
resizeMode={'contain'}
- onLoad={(response) => {
- const {width, height} = response.naturalSize;
- setAspectRatio(width / height);
- }}
/>
- </View>
- ) : (
- <Image
- style={styles.media}
- source={{uri: mediaUri}}
- resizeMode={'contain'}
+ )}
+ <MentionInputControlled
+ style={styles.text}
+ containerStyle={styles.flex}
+ placeholder="Write something....."
+ placeholderTextColor="white"
+ value={caption}
+ onChange={setCaption}
+ partTypes={mentionPartTypes('white', 'caption', true)}
/>
+ </View>
+ {useMemo(
+ () => (
+ <SelectableItem
+ text={'Category'}
+ imageUri={require('../../assets/images/images.png')}
+ onPress={() =>
+ navigation.navigate('ChoosingCategoryScreen', {})
+ }
+ />
+ ),
+ [momentCategory],
)}
- <MentionInputControlled
- containerStyle={styles.text}
- placeholder="Write something....."
- placeholderTextColor="gray"
- value={caption}
- onChange={setCaption}
- partTypes={mentionPartTypes('blue', 'caption')}
- />
- <TouchableOpacity
- onPress={() =>
- navigation.navigate('TagFriendsScreen', {
- media: {
- uri: mediaUri,
- isVideo: isMediaAVideo,
- },
- selectedTags: tags,
- })
- }
- style={styles.tagFriendsContainer}>
- <Image
- source={require('../../assets/icons/tagging/tag-icon.png')}
- style={styles.tagIcon}
+ {useMemo(
+ () => (
+ <SelectableItem
+ text={'Tag Friends'}
+ imageUri={require('../../assets/icons/tagging/tag-icon.png')}
+ onPress={() =>
+ navigation.navigate('TagFriendsScreen', {
+ media: {
+ uri: mediaUri,
+ isVideo: isMediaAVideo,
+ },
+ selectedTags: tags,
+ })
+ }
+ />
+ ),
+ [taggedUsersText],
+ )}
+ {momentCategory ? (
+ <TaggSquareButton
+ onPress={moment ? handleSubmitEditChanges : handleShare}
+ title={moment ? 'Update' : 'Post'}
+ buttonStyle={'large'}
+ buttonColor={'blue'}
+ labelColor={'white'}
+ style={styles.postButton}
+ labelStyle={styles.postText}
+ />
+ ) : (
+ <TaggSquareButton
+ disabled={true}
+ onPress={moment ? handleSubmitEditChanges : handleShare}
+ title={moment ? 'Update' : 'Post'}
+ buttonStyle={'large'}
+ buttonColor={'blue'}
+ labelColor={'white'}
+ style={[styles.postButton, styles.greyBackground]}
+ labelStyle={styles.postText}
/>
- <Text style={styles.tagFriendsTitle}>Tag Friends</Text>
- <Text numberOfLines={1} style={styles.taggedListContainer}>
- {taggedList}
- {taggedList.length > 21 ? '. . .' : ''}
- </Text>
- <FrontArrow width={12} height={12} color={'white'} />
- </TouchableOpacity>
+ )}
</View>
</KeyboardAvoidingView>
</TouchableWithoutFeedback>
@@ -342,53 +386,90 @@ const styles = StyleSheet.create({
color: TAGG_LIGHT_BLUE_2,
},
header: {
- marginVertical: 20,
+ marginTop: 20,
+ marginBottom: 30,
},
- media: {
- position: 'relative',
- width: SCREEN_WIDTH,
- aspectRatio: 1,
- marginBottom: '3%',
- flex: 1,
+ captionContainer: {
+ flexDirection: 'row',
+ padding: normalize(15),
+ marginBottom: normalize(35),
+ borderColor: 'white',
+ borderTopWidth: 1,
+ borderBottomWidth: 1,
+ zIndex: 1,
},
- mediaContainer: {
- width: SCREEN_WIDTH,
- aspectRatio: 1,
+ media: {
+ height: normalize(150),
+ aspectRatio: 9 / 16,
},
text: {
- position: 'relative',
- backgroundColor: 'white',
- width: '100%',
- paddingHorizontal: '2%',
- paddingVertical: '1%',
- height: 60,
+ color: 'white',
+ fontSize: normalize(12),
+ lineHeight: 14,
+ fontWeight: '500',
+ height: normalize(150),
+ marginLeft: normalize(15),
},
flex: {
flex: 1,
},
- tagFriendsTitle: {
+ selectableItemTitle: {
color: 'white',
- fontSize: normalize(12),
+ fontSize: normalize(14),
lineHeight: normalize(16.71),
letterSpacing: normalize(0.3),
fontWeight: '600',
},
- tagFriendsContainer: {
+ selectableItemContainer: {
marginHorizontal: '5%',
- marginTop: '3%',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
+ marginBottom: normalize(42),
+ },
+ asteriskText: {
+ color: TAGG_LIGHT_BLUE_2,
+ fontWeight: 'bold',
+ fontSize: normalize(15),
+ height: 15,
+ alignSelf: 'center',
},
- taggedListContainer: {
+ itemInfoText: {
color: 'white',
width: 150,
fontSize: normalize(10),
lineHeight: normalize(11),
letterSpacing: normalize(0.3),
textAlign: 'right',
+
+ marginRight: 5,
+ },
+ tagIcon: {
+ width: normalize(20),
+ height: normalize(20),
+ marginRight: 15,
+ },
+ row: {
+ flexDirection: 'row',
+ },
+ greyBackground: {
+ backgroundColor: '#C4C4C4',
+ },
+ postButton: {
+ width: SCREEN_WIDTH * 0.8,
+ height: normalize(37),
+ justifyContent: 'center',
+ alignItems: 'center',
+ borderRadius: 6,
+ alignSelf: 'center',
+ },
+ postText: {
+ color: 'white',
+ fontWeight: 'bold',
+ fontSize: normalize(15),
+ lineHeight: 18,
+ letterSpacing: 2,
},
- tagIcon: {width: 20, height: 20},
});
export default CaptionScreen;