import {RouteProp} from '@react-navigation/native'; import {StackNavigationProp} from '@react-navigation/stack'; import React, {FC, useEffect, useState} from 'react'; import { Alert, Image, ImageSourcePropType, Keyboard, KeyboardAvoidingView, Platform, StyleSheet, Text, TouchableOpacity, TouchableWithoutFeedback, View, } from 'react-native'; import {openContactForm} from 'react-native-contacts'; 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 {MentionInputControlled, SearchBackground} from '../../components'; import {CaptionScreenHeader} from '../../components/'; import TaggLoadingIndicator from '../../components/common/TaggLoadingIndicator'; import {TAGG_LIGHT_BLUE_2} from '../../constants'; import { ERROR_SOMETHING_WENT_WRONG_REFRESH, ERROR_UPLOAD, } from '../../constants/strings'; import {MainStackParams} from '../../routes'; import { handlePresignedURL, handleVideoUpload, patchMoment, postMoment, postMomentTags, } from '../../services'; import { loadUserMoments, updateProfileCompletionStage, } from '../../store/actions'; import {RootState} from '../../store/rootReducer'; import {MomentTagType} from '../../types'; import {normalize, StatusBarHeight} from '../../utils'; import {mentionPartTypes} from '../../utils/comments'; /** * Upload Screen to allow users to upload posts to Tagg */ type CaptionScreenRouteProp = RouteProp; type CaptionScreenNavigationProp = StackNavigationProp< MainStackParams, 'CaptionScreen' >; interface CaptionScreenProps { route: CaptionScreenRouteProp; navigation: CaptionScreenNavigationProp; } const CaptionScreen: React.FC = ({route, navigation}) => { const {title, screenType, selectedTags, 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( selectedTags ? selectedTags : [], ); const [taggedUsersText, setTaggedUsersText] = useState(''); const mediaUri = moment ? moment.moment_url : route.params.media!.uri; // TODO: change this once moment refactor is done const isMediaAVideo = moment ? !( moment.moment_url.endsWith('.jpg') || moment.moment_url.endsWith('.JPG') || moment.moment_url.endsWith('.png') || moment.moment_url.endsWith('.PNG') ) : route.params.media?.isVideo ?? false; useEffect(() => { setTags(selectedTags ? selectedTags : []); }, [selectedTags]); 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); } } 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 = () => { setLoading(false); setTimeout(() => { Alert.alert(moment ? ERROR_SOMETHING_WENT_WRONG_REFRESH : ERROR_UPLOAD); }, 500); }; const handleSuccess = () => { setLoading(false); if (moment) { setLoading(false); navigation.goBack(); } else { navigateToProfile(); setTimeout(() => { if (isMediaAVideo) { Alert.alert( 'Beautiful, the Moment was uploaded successfully! Check back in a bit and refresh to see it!', ); } else { Alert.alert(''); } }, 500); } }; const formattedTags = () => { return tags.map((tag) => ({ x: Math.floor(tag.x), y: Math.floor(tag.y), z: Math.floor(tag.z), user_id: tag.user.id, })); }; const handleShare = async () => { setLoading(true); if (moment || !title) { handleFailed(); return; } let profileCompletionStage; let momentId; // separate upload logic for image/video if (isMediaAVideo) { const presignedURLResponse = await handlePresignedURL(title); if (!presignedURLResponse) { handleFailed(); return; } momentId = presignedURLResponse.moment_id; const fileHash = presignedURLResponse.response_url.fields.key; if (fileHash !== null && fileHash !== '' && fileHash !== undefined) { await handleVideoUpload(mediaUri, presignedURLResponse); } else { handleFailed(); } } else { const momentResponse = await postMoment(mediaUri, caption, title, userId); if (!momentResponse) { handleFailed(); return; } profileCompletionStage = momentResponse.profile_completion_stage; momentId = momentResponse.moment_id; } if (momentId) { const momentTagResponse = await postMomentTags(momentId, formattedTags()); if (!momentTagResponse) { handleFailed(); return; } } if (!isMediaAVideo) { dispatch(loadUserMoments(userId)); } if (profileCompletionStage) { dispatch(updateProfileCompletionStage(profileCompletionStage)); } handleSuccess(); }; const handleDoneEditing = async () => { setLoading(true); if (moment?.moment_id) { const success = await patchMoment( moment.moment_id, caption, formattedTags(), ); if (success) { dispatch(loadUserMoments(userId)); handleSuccess(); } else { handleFailed(); } } }; const SelectableItem: FC<{ text: string; imageUri: ImageSourcePropType; onPress: () => void; }> = ({text, imageUri, onPress}) => ( {text} {taggedUsersText} ); return ( {loading && }