import React, {useEffect} from 'react'; import {Image, StyleSheet, Text, TouchableOpacity} from 'react-native'; import {View} from 'react-native-animatable'; import { cancelAnimation, Easing, useSharedValue, withTiming, } from 'react-native-reanimated'; import {useDispatch, useSelector} from 'react-redux'; import { TAGG_LIGHT_BLUE_2, TAGG_LIGHT_BLUE_3, TAGG_PURPLE, } from '../../constants'; import {checkMomentDoneProcessing} from '../../services'; import { handleImageMomentUpload, handleVideoMomentUpload, loadUserMoments, } from '../../store/actions'; import {setMomentUploadProgressBar} from '../../store/reducers'; import {RootState} from '../../store/rootReducer'; import {MomentUploadStatusType} from '../../types'; import {normalize, SCREEN_WIDTH, StatusBarHeight} from '../../utils'; import {GradientProgressBar} from '../common'; interface MomentUploadProgressBarProps {} const MomentUploadProgressBar: React.FC = ({}) => { const dispatch = useDispatch(); const {userId: loggedInUserId} = useSelector( (state: RootState) => state.user.user, ); const {momentUploadProgressBar} = useSelector( (state: RootState) => state.user, ); const progress = useSharedValue(0); const showLoading = momentUploadProgressBar?.status === MomentUploadStatusType.UploadingToS3 || momentUploadProgressBar?.status === MomentUploadStatusType.WaitingForDoneProcessing; let timeoutTimer: ReturnType | undefined; const cantainerHeight = momentUploadProgressBar?.status === MomentUploadStatusType.Error ? normalize(121) : normalize(84); const retryUpload = () => { if (!momentUploadProgressBar || !timeoutTimer) { return; } clearTimeout(timeoutTimer); const {type, uri, caption, category, tags} = momentUploadProgressBar.momentInfo; if (type === 'image') { dispatch(handleImageMomentUpload(uri, caption, category, tags)); } else { dispatch( handleVideoMomentUpload( uri, momentUploadProgressBar.originalVideoDuration ?? 30, caption, category, tags, ), ); } }; // WAITING_FOR_PROCESSING, check if done processing in a loop with a delay useEffect(() => { let doneProcessing = false; const checkDone = async () => { if ( momentUploadProgressBar && (await checkMomentDoneProcessing(momentUploadProgressBar!.momentId)) ) { doneProcessing = true; cancelAnimation(progress); // upload is done, but let's finish the progress bar animation in a velocity of 10%/s const finishProgressBarDuration = (1 - progress.value) * 10 * 1000; progress.value = withTiming(1, { duration: finishProgressBarDuration, easing: Easing.linear, }); // change status to Done 1s after the progress bar animation is done setTimeout(() => { dispatch({ type: setMomentUploadProgressBar.type, payload: { momentUploadProgressBar: { ...momentUploadProgressBar, status: MomentUploadStatusType.Done, }, }, }); }, finishProgressBarDuration); } }; if ( momentUploadProgressBar?.status === MomentUploadStatusType.WaitingForDoneProcessing ) { checkDone(); const timer = setInterval(async () => { if (!doneProcessing) { checkDone(); } }, 5 * 1000); // timeout if takes longer than 1 minute to process setTimeout(() => { clearInterval(timer); if (!doneProcessing) { console.error('Check for done processing timed out'); dispatch({ type: setMomentUploadProgressBar.type, payload: { momentUploadProgressBar: { ...momentUploadProgressBar, status: MomentUploadStatusType.Error, }, }, }); } }, 60 * 1000); return () => clearInterval(timer); } }, [momentUploadProgressBar?.status]); // UPLOADING_TO_S3, begin progress bar animation useEffect(() => { if ( momentUploadProgressBar?.status === MomentUploadStatusType.UploadingToS3 ) { // e.g. 30s video => 30 * 3 = 60s const videoDuration = momentUploadProgressBar.originalVideoDuration ?? 30; const durationInSeconds = videoDuration * 3; progress.value = withTiming(1, { duration: durationInSeconds * 1000, easing: Easing.out(Easing.quad), }); } }, [momentUploadProgressBar?.status]); // ERROR, dismiss progress bar after some time, but allow retry useEffect(() => { if (momentUploadProgressBar?.status === MomentUploadStatusType.Error) { progress.value = 0; timeoutTimer = setTimeout(() => { dispatch({ type: setMomentUploadProgressBar.type, payload: { momentUploadProgressBar: undefined, }, }); }, 5000); } }, [momentUploadProgressBar?.status]); // DONE, reload user moments useEffect(() => { if (momentUploadProgressBar?.status === MomentUploadStatusType.Done) { dispatch(loadUserMoments(loggedInUserId)); } }, [momentUploadProgressBar?.status]); // DONE, clear and dismiss progress bar after some time useEffect(() => { if (momentUploadProgressBar?.status === MomentUploadStatusType.Done) { progress.value = 0; // clear this component after a duration setTimeout(() => { dispatch({ type: setMomentUploadProgressBar.type, payload: { momentUploadProgressBar: undefined, }, }); }, 5000); } }, [momentUploadProgressBar?.status]); if (!momentUploadProgressBar) { return null; } return ( {showLoading && ( <> Uploading Moment... )} {momentUploadProgressBar.status === MomentUploadStatusType.Done && ( Beautiful, the Moment was uploaded successfully! )} {momentUploadProgressBar.status === MomentUploadStatusType.Error && ( Unable to upload Moment. Please retry Retry )} ); }; const styles = StyleSheet.create({ background: { position: 'absolute', zIndex: 999, backgroundColor: 'white', width: '100%', alignItems: 'center', }, container: { justifyContent: 'center', marginTop: StatusBarHeight, }, text: { fontSize: normalize(14), fontWeight: 'bold', lineHeight: 17, marginVertical: 12, width: '80%', }, bar: { width: SCREEN_WIDTH * 0.9, }, redBackground: { backgroundColor: '#EA574C', }, row: { flexDirection: 'row', alignItems: 'center', }, column: { flexDirection: 'column', alignItems: 'center', justifyContent: 'space-evenly', flex: 1, }, whiteText: { color: 'white', fontSize: normalize(14), fontWeight: 'bold', lineHeight: 17, marginVertical: 12, }, x: { width: normalize(26), height: normalize(26), marginRight: 10, }, retryButton: { backgroundColor: '#A2352C', borderRadius: 6, height: normalize(37), width: '90%', justifyContent: 'center', alignItems: 'center', }, retryText: { color: 'white', fontWeight: 'bold', letterSpacing: 2, fontSize: normalize(15), }, }); export default MomentUploadProgressBar;