diff options
Diffstat (limited to 'src/screens/profile/CaptionScreen.tsx')
-rw-r--r-- | src/screens/profile/CaptionScreen.tsx | 361 |
1 files changed, 249 insertions, 112 deletions
diff --git a/src/screens/profile/CaptionScreen.tsx b/src/screens/profile/CaptionScreen.tsx index e77f40c2..383737e7 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,19 +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, @@ -40,34 +47,36 @@ 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 {TrimmerPlayer} from '../../components/moments/trimmer'; /** * 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 [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; // TODO: change this once moment refactor is done const isMediaAVideo = moment @@ -80,48 +89,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, + }); } }; @@ -136,15 +165,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; @@ -157,7 +186,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; @@ -172,19 +206,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) { @@ -196,12 +233,46 @@ const CaptionScreen: React.FC<CaptionScreenProps> = ({route, navigation}) => { } }; + 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}> @@ -210,60 +281,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={'Moments'} /> + <View style={styles.captionContainer}> + {isMediaAVideo ? ( + <Video + style={styles.media} + source={{uri: mediaUri}} + repeat={true} + /> + ) : ( + <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> - <CaptionScreenHeader - style={styles.header} - {...{title: moment ? moment.moment_category : title ?? ''}} - /> - {isMediaAVideo ? ( - <TrimmerPlayer - source={mediaUri} - styles={styles.media} - hideTrimmer={true} + {useMemo( + () => ( + <SelectableItem + text={'Category'} + imageUri={require('../../assets/images/images.png')} + onPress={() => + navigation.navigate('ChoosingCategoryScreen', {}) + } + /> + ), + [momentCategory], + )} + {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} /> ) : ( - <Image - style={styles.media} - source={{uri: mediaUri}} - resizeMode={'contain'} + <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} /> )} - <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} - /> - <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> @@ -290,48 +385,90 @@ const styles = StyleSheet.create({ color: TAGG_LIGHT_BLUE_2, }, header: { - marginVertical: 20, + marginTop: 20, + marginBottom: 30, + }, + captionContainer: { + flexDirection: 'row', + padding: normalize(15), + marginBottom: normalize(35), + borderColor: 'white', + borderTopWidth: 1, + borderBottomWidth: 1, + zIndex: 1, }, media: { - position: 'relative', - width: SCREEN_WIDTH, - aspectRatio: 1, - marginBottom: '3%', + 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), }, - taggedListContainer: { + asteriskText: { + color: TAGG_LIGHT_BLUE_2, + fontWeight: 'bold', + fontSize: normalize(15), + height: 15, + alignSelf: 'center', + }, + 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; |