import * as MediaLibrary from 'expo-media-library'; import React, { useEffect, useState } from 'react'; import { ActivityIndicator, Alert, Modal, StyleSheet, Text, View, } from 'react-native'; import { ProgressBar } from 'react-native-paper'; import Toast from 'react-native-toast-message'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import { logImEXEvent } from '../../firebase/firebase.analytics'; import { selectCurrentCameraJobId, selectDeleteAfterUpload, } from '../../redux/app/app.selectors'; import * as Sentry from '@sentry/react-native'; import { formatBytes } from '../../util/document-upload.utility'; import { handleLocalUpload } from '../../util/local-document-upload.utility'; const mapStateToProps = createStructuredSelector({ selectedCameraJobId: selectCurrentCameraJobId, deleteAfterUpload: selectDeleteAfterUpload, }); export default connect(mapStateToProps, null)(UploadProgress); export function UploadProgress({ selectedCameraJobId, deleteAfterUpload, uploads, setUploads, forceRerender, }) { const [progress, setProgress] = useState({ loading: false, uploadInProgress: false, speed: 0, }); useEffect(() => { //Set the state of uploads to do. if (uploads) { beginUploads(uploads); setUploads(null); } }, [uploads]); async function handleOnSuccess({ duration, data }) { //If it's not in production, show a toast with the time. Toast.show({ type: 'success', text1: ` Upload completed in ${duration}.`, // // text2: duration, }); if (deleteAfterUpload) { try { await MediaLibrary.deleteAssetsAsync(data); const album = await MediaLibrary.createAlbumAsync( 'ImEX Mobile Deleted', data.pop(), false ); //Move the rest. if (data.length > 0) { const moveResult = await MediaLibrary.addAssetsToAlbumAsync( data, album, false ); } const deleteResult = await MediaLibrary.deleteAlbumsAsync(album); } catch (error) { console.log('Unable to delete picture.', error); Sentry.Native.captureException(error); } } logImEXEvent('imexmobile_successful_upload'); forceRerender(); setProgress({ ...progress, speed: 0, percent: 1, uploadInProgress: false }); } function handleOnProgress({ percent, loaded }) { setProgress((progress) => ({ ...progress, speed: loaded - progress.loaded, loaded: loaded, percent, })); } function handleOnError({ assetid, error }) { logImEXEvent('imexmobile_upload_documents_error'); Toast.show({ type: 'error', text1: 'Unable to upload documents.', text2: error, autoHide: false, }); setProgress({ speed: 0, percent: 1, uploadInProgress: false, }); } const beginUploads = async (data) => { //Validate to make sure the totals for the file sizes do not exceed the total on the job. setProgress({ percent: 0, loaded: 0, uploadInProgress: true, start: new Date(), average: 0, }); await handleLocalUpload({ files: data, onError: ({ assetid, error }) => handleOnError({ assetid, error }), onProgress: ({ percent, loaded }) => handleOnProgress({ percent, loaded }), onSuccess: ({ duration }) => handleOnSuccess({ duration, data }), context: { jobid: selectedCameraJobId !== 'temp' ? selectedCameraJobId : 'temporary', }, }); }; return ( { Alert.alert('Cancel?', 'Do you want to abort the upload?', [ { text: 'Yes', onPress: () => { setUploads(null); setProgress(null); }, }, { text: 'No' }, ]); }} > {`${formatBytes( progress.speed )}/sec`} {`Avg. ${formatBytes( progress.loaded / ((new Date() - progress.start) / 1000) )}/sec`} {`Total Uploaded ${formatBytes(progress.loaded)}`} {`Duration ${( (new Date() - progress.start) / 1000 ).toFixed(1)} sec`} ); } const styles = StyleSheet.create({ modalContainer: { display: 'flex', flex: 1, justifyContent: 'center', }, modal: { // flex: 1, display: 'flex', marginLeft: 20, marginRight: 20, backgroundColor: 'white', borderRadius: 20, padding: 18, shadowColor: '#000', shadowOffset: { width: 0, height: 2, }, shadowOpacity: 0.25, shadowRadius: 4, elevation: 5, }, });