From e29097a6c7b3347147a3bfae66de92c95229c132 Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Wed, 18 May 2022 09:55:48 -0700 Subject: [PATCH] 1.3.6-3 Test Build - Refactor local uploads to go in bulk. --- app.json | 6 +- .../local-upload-progress.component.jsx | 240 +++++------------- .../screen-media-browser.component.jsx | 12 +- util/local-document-upload.utility.js | 78 +++--- 4 files changed, 121 insertions(+), 215 deletions(-) diff --git a/app.json b/app.json index 807f30e..8f402dc 100644 --- a/app.json +++ b/app.json @@ -4,19 +4,19 @@ "slug": "imexmobile", "version": "1.3.6", "extra": { - "expover": "2" + "expover": "3" }, "orientation": "default", "icon": "./assets/logo192noa.png", "ios": { "supportsTablet": true, "bundleIdentifier": "com.imex.imexmobile", - "buildNumber": "2", + "buildNumber": "3", "googleServicesFile": "./GoogleService-Info.plist" }, "android": { "package": "com.imex.imexmobile", - "versionCode": 1100007, + "versionCode": 1100008, "googleServicesFile": "./google-services.json" }, "splash": { diff --git a/components/local-upload-progress/local-upload-progress.component.jsx b/components/local-upload-progress/local-upload-progress.component.jsx index bed59d8..2718bfc 100644 --- a/components/local-upload-progress/local-upload-progress.component.jsx +++ b/components/local-upload-progress/local-upload-progress.component.jsx @@ -1,18 +1,16 @@ -import { useApolloClient } from "@apollo/client"; import * as MediaLibrary from "expo-media-library"; -import _ from "lodash"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { ActivityIndicator, Alert, Modal, - ScrollView, 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"; @@ -26,7 +24,6 @@ import { } from "../../redux/user/user.selectors"; import { formatBytes } from "../../util/document-upload.utility"; import { handleLocalUpload } from "../../util/local-document-upload.utility"; -import Toast from "react-native-toast-message"; const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, @@ -43,78 +40,54 @@ export function UploadProgress({ selectedCameraJobId, deleteAfterUpload, uploads, + setUploads, forceRerender, }) { const [progress, setProgress] = useState({ loading: false, uploadInProgress: false, speed: 0, - files: {}, //uri is the key, value is progress }); let filesToDelete = []; - const client = useApolloClient(); const { t } = useTranslation(); useEffect(() => { //Set the state of uploads to do. - - if (uploads) onDone(uploads); + if (uploads) { + beginUploads(uploads); + setUploads(null); + } }, [uploads]); - //if (!uploads) return null; - - function handleOnSuccess(id, asset, { duration }) { + function handleOnSuccess({ duration }) { //If it's not in production, show a toast with the time. Toast.show({ type: "success", - text1: `${duration} - Upload completed for ${asset.filename}.`, + text1: ` Upload completed in ${duration}.`, // // text2: duration, }); logImEXEvent("imexmobile_successful_upload"); - filesToDelete.push(asset); + setProgress({ + speed: 0, + percent: 1, + uploadInProgress: false, + }); + } + + function handleOnProgress({ percent, loaded }) { setProgress((progress) => ({ ...progress, - action: t("mediabrowser.labels.converting"), - files: { - ...progress.files, - [id]: { - ...progress.files[id], - percent: 1, - action: t("mediabrowser.labels.converting"), - }, - }, - // }); + speed: loaded - progress.loaded, + loaded: loaded, + percent, })); } - function handleOnProgress(uri, percent, loaded) { - setProgress((progress) => ({ - ...progress, - // speed: loaded - progress.files[uri].loaded, - action: - percent === 1 - ? t("mediabrowser.labels.converting") - : t("mediabrowser.labels.uploading"), - files: { - ...progress.files, - [uri]: { - ...progress.files[uri], - percent, - speed: loaded - progress.files[uri].loaded, - action: - percent === 1 - ? t("mediabrowser.labels.converting") - : t("mediabrowser.labels.uploading"), - loaded: loaded, - }, - }, - })); - } - function handleOnError(id, error) { + function handleOnError({ assetid, error }) { logImEXEvent("imexmobile_upload_documents_error"); Toast.show({ type: "error", @@ -122,52 +95,27 @@ export function UploadProgress({ text2: (error && error.message) || JSON.stringify(error), autoHide: false, }); - setProgress((progress) => ({ - ...progress, - action: t("mediabrowser.labels.converting"), - files: { - ...progress.files, - [id]: { - ...progress.files[id], - percent: 1, - action: t("mediabrowser.labels.converting"), - }, - }, - // }); - })); } - const onDone = async (data) => { + const beginUploads = async (data) => { //Validate to make sure the totals for the file sizes do not exceed the total on the job. setProgress({ - files: _.keyBy(data, "id"), - loading: true, + percent: 0, + loaded: 0, uploadInProgress: true, }); - //Sequentially await the proms. - - // for (const file of data) { - // await CreateUploadProm(file); - // } - - for (var i = 0; i < data.length + 4; i = i + 4) { - let proms = []; - if (data[i]) { - proms.push(CreateUploadProm(data[i])); - } - if (data[i + 1]) { - proms.push(CreateUploadProm(data[i + 1])); - } - if (data[i + 2]) { - proms.push(CreateUploadProm(data[i + 2])); - } - if (data[i + 3]) { - proms.push(CreateUploadProm(data[i + 3])); - } - - await Promise.all(proms); - } + await handleLocalUpload({ + files: data, + onError: ({ assetid, error }) => handleOnError({ assetid, error }), + onProgress: ({ percent, loaded }) => + handleOnProgress({ percent, loaded }), + onSuccess: ({ duration }) => handleOnSuccess({ duration }), + context: { + jobid: + selectedCameraJobId !== "temp" ? selectedCameraJobId : "temporary", + }, + }); if (deleteAfterUpload) { try { @@ -190,91 +138,55 @@ export function UploadProgress({ setProgress({ loading: false, speed: 0, - action: null, - uploadInProgress: false, - files: {}, //uri is the key, value is progress }); forceRerender(); }; - const CreateUploadProm = async (p) => { - let filename; - filename = p.filename || p.uri.split("/").pop(); - - await handleLocalUpload({ - ev: { - filename, - mediaId: p.id, - onError: (error) => handleOnError(p.id, error), - onProgress: ({ percent, loaded }) => - handleOnProgress(p.id, percent, loaded), - onSuccess: ({ duration }) => handleOnSuccess(p.id, p, { duration }), - file: p, - }, - context: { - bodyshop: bodyshop, - jobid: - selectedCameraJobId !== "temp" ? selectedCameraJobId : "temporary", - }, - }); - - //Set the state to mark that it's done. - setProgress((progress) => ({ - ...progress, - action: null, - speed: 0, - files: { - ...progress.files, - [p.id]: { - ...progress.files[p.id], - action: null, - }, - }, - })); - }; - return ( {}} + onRequestClose={() => { + Alert.alert("Cancel?", "Do you want to abort the upload?", [ + { + text: "Yes", + onPress: () => { + setUploads(null); + setProgress(null); + }, + }, + { text: "No" }, + ]); + }} > - - {progress.loading && } - - - {Object.keys(progress.files).map((key) => ( - - - {progress.files[key].filename} - - - - {progress.files[key].speed !== 0 && - progress.files[key].speed && - !isNaN(progress.files[key].speed) ? ( - {`${formatBytes(progress.files[key].speed)}/sec`} - ) : null} - - - ))} - + + + + + {`${formatBytes( + progress.speed + )}/sec`} + ); } const styles = StyleSheet.create({ - modal: { + modalContainer: { + display: "flex", flex: 1, - marginTop: 80, - marginBottom: 60, + justifyContent: "center", + }, + modal: { + // flex: 1, + display: "flex", marginLeft: 20, marginRight: 20, backgroundColor: "white", @@ -289,26 +201,4 @@ const styles = StyleSheet.create({ shadowRadius: 4, elevation: 5, }, - centeredView: { - flex: 1, - // justifyContent: "center", - // alignItems: "center", - marginTop: 22, - }, - progressItem: { - display: "flex", - flexDirection: "row", - alignItems: "center", - marginBottom: 12, - marginLeft: 12, - marginRight: 12, - }, - progressText: { - flex: 1, - }, - progressBarContainer: { - flex: 3, - marginLeft: 12, - marginRight: 12, - }, }); diff --git a/components/screen-media-browser/screen-media-browser.component.jsx b/components/screen-media-browser/screen-media-browser.component.jsx index edd33f2..6810a35 100644 --- a/components/screen-media-browser/screen-media-browser.component.jsx +++ b/components/screen-media-browser/screen-media-browser.component.jsx @@ -155,9 +155,17 @@ export function ImageBrowserScreen({ bodyshop, selectedCameraJobId }) { /> )} {bodyshop.uselocalmediaserver ? ( - + ) : ( - + )} ); diff --git a/util/local-document-upload.utility.js b/util/local-document-upload.utility.js index a380f99..0ffa0da 100644 --- a/util/local-document-upload.utility.js +++ b/util/local-document-upload.utility.js @@ -1,8 +1,7 @@ import axios from "axios"; -import * as ImageManipulator from "expo-image-manipulator"; -import * as MediaLibrary from "expo-media-library"; -import mime from "mime"; import { store } from "../redux/store"; +import mime from "mime"; +import * as MediaLibrary from "expo-media-library"; axios.interceptors.request.use( function (config) { @@ -29,9 +28,14 @@ axios.interceptors.response.use( } ); -export const handleLocalUpload = async ({ ev, context }) => { - const { onError, onSuccess, onProgress, filename, mediaId } = ev; - const { jobid, invoice_number, vendorid, callbackAfterUpload } = context; +export const handleLocalUpload = async ({ + files, + onError, + onSuccess, + onProgress, + context, +}) => { + const { jobid } = context; const bodyshop = store.getState().user.bodyshop; try { var options = { @@ -41,26 +45,22 @@ export const handleLocalUpload = async ({ ev, context }) => { }, onUploadProgress: (e) => { if (onProgress) - onProgress({ percent: (e.loaded / e.total) * 100, loaded: e.loaded }); + onProgress({ percent: e.loaded / e.total, loaded: e.loaded }); }, }; const formData = new FormData(); formData.append("jobid", jobid); - if (invoice_number) { - formData.append("invoice_number", invoice_number); - formData.append("vendorid", vendorid); - } - const imageData = await MediaLibrary.getAssetInfoAsync(mediaId); - const mimeType = mime.getType(imageData.uri); + // const imageData = await MediaLibrary.getAssetInfoAsync(mediaId); + // const mimeType = mime.getType(imageData.uri); - //let thumb; - let fileData = { - uri: null, - type: null, - name: null, - }; + // //let thumb; + // let fileData = { + // uri: null, + // type: null, + // name: null, + // }; // if (mimeType === "image/heic") { // try { // thumb = await ImageManipulator.manipulateAsync(imageData.uri, [], { @@ -80,25 +80,37 @@ export const handleLocalUpload = async ({ ev, context }) => { // onError && onError(error.message); // } // } else { - fileData = { - uri: imageData.localUri || imageData.uri, - type: mimeType, - name: filename, - }; + // fileData = { + // uri: imageData.localUri || imageData.uri, + // type: mimeType, + // name: filename, + // }; //} - formData.append("file", fileData); + const filesList = []; + for (const file of files) { + const imageData = await MediaLibrary.getAssetInfoAsync(file.id); + const mimeType = mime.getType(imageData.uri); + filesList.push({ + uri: imageData.localUri || imageData.uri, + type: mimeType, + name: imageData.filename, + }); + formData.append("file", { + uri: imageData.localUri || imageData.uri, + type: mimeType, + name: imageData.filename, + }); + } + + //formData.append("file", files); formData.append("skip_thumbnail", true); try { const imexMediaServerResponse = await axios.post( - `${bodyshop.localmediaserverhttp}/${ - invoice_number ? "bills" : "jobs" - }/upload`, + `${bodyshop.localmediaserverhttp}/jobs/upload`, formData, - { - ...options, - } + options ); if (imexMediaServerResponse.status !== 200) { @@ -113,10 +125,6 @@ export const handleLocalUpload = async ({ ev, context }) => { duration: imexMediaServerResponse.headers["x-response-time"], }); } - - if (callbackAfterUpload) { - callbackAfterUpload(); - } } catch (error) { console.log("Error uploading documents:", error); onError && onError(error.message);