From b45ed8ad175e20d374604b87460f2905b58286cd Mon Sep 17 00:00:00 2001 From: Patrick Fic <> Date: Tue, 9 Mar 2021 15:36:35 -0800 Subject: [PATCH] IO-750 Resolve overwriting images on iOS Upload --- .../screen-media-browser.component.jsx | 220 ++++++++++-------- .../screen-splash/screen-splash.component.jsx | 3 - .../upload-progress.component.jsx | 25 +- package.json | 1 + util/document-upload.utility.js | 8 +- yarn.lock | 2 +- 6 files changed, 143 insertions(+), 116 deletions(-) diff --git a/components/screen-media-browser/screen-media-browser.component.jsx b/components/screen-media-browser/screen-media-browser.component.jsx index 365b625..2846395 100644 --- a/components/screen-media-browser/screen-media-browser.component.jsx +++ b/components/screen-media-browser/screen-media-browser.component.jsx @@ -6,7 +6,6 @@ import { H3 } from "native-base"; import React, { useCallback, useState } from "react"; import { useTranslation } from "react-i18next"; import { StyleSheet, Text, View } from "react-native"; -import { SafeAreaView } from "react-native-safe-area-context"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { @@ -21,6 +20,9 @@ import { handleUpload } from "../../util/document-upload.utility"; import CameraSelectJob from "../camera-select-job/camera-select-job.component"; import UploadDeleteSwitch from "../upload-delete-switch/upload-delete-switch.component"; import UploadProgress from "../upload-progress/upload-progress.component"; +import plimit from "p-limit"; + +const limit = plimit(2); const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, @@ -38,6 +40,7 @@ export function ImageBrowserScreen({ }) { const { t } = useTranslation(); const [uploads, setUploads] = useState({}); + function handleOnProgress(uri, percent) { setUploads((prevUploads) => ({ ...prevUploads, [uri]: { percent } })); } @@ -47,13 +50,15 @@ export function ImageBrowserScreen({ setTick((tick) => tick + 1); }, []); async function handleOnSuccess(uri, id) { - console.log("onSucces!", uri); - + console.log("Succesful upload!", uri); if (deleteAfterUpload) { - const result = await MediaLibrary.deleteAssetsAsync([id]); - console.log("result :>> ", result); + try { + const result = await MediaLibrary.deleteAssetsAsync([id]); + console.log("Delete result :>> ", result); + } catch (error) { + console.log("Unable to delete picture.", error); + } } - console.log("Omitting", uri); setUploads((prevUploads) => _.omit(prevUploads, uri)); } @@ -61,21 +66,32 @@ export function ImageBrowserScreen({ console.log("Assets :>> ", data); const actions = []; data.forEach(function (p) { - const uri = p.uri.split("/").pop(); + let filename; + //Appears to work for android. + //iOS provides the filename, android doe snot. + filename = p.filename || p.uri.split("/").pop(); + + //File name for ios + actions.push( - handleUpload( - { - uri: p.uri, - onError: handleOnError, - onProgress: ({ percent }) => handleOnProgress(uri, percent), - onSuccess: () => handleOnSuccess(uri, p.id), - }, - { - bodyshop: bodyshop, - jobId: selectedCameraJobId !== "temp" ? selectedCameraJobId : null, - uploaded_by: currentUser.email, - photo: p, - } + limit( + handleUpload( + { + //iOS provides the file name. Android does not. + uri: p.uri, + filename, + onError: handleOnError, + onProgress: ({ percent }) => handleOnProgress(filename, percent), + onSuccess: () => handleOnSuccess(filename, p.id), + }, + { + bodyshop: bodyshop, + jobId: + selectedCameraJobId !== "temp" ? selectedCameraJobId : null, + uploaded_by: currentUser.email, + photo: p, + } + ) ) ); }); @@ -85,93 +101,91 @@ export function ImageBrowserScreen({ }; return ( - - - - - {!selectedCameraJobId && ( - -

{t("mediabrowser.labels.selectjobassetselector")}

-
- )} - {selectedCameraJobId && ( - { - forceRerender(); - }, - doneFunction: onDone, + + + + {!selectedCameraJobId && ( + +

{t("mediabrowser.labels.selectjobassetselector")}

+
+ )} + {selectedCameraJobId && ( + { + forceRerender(); }, + doneFunction: onDone, + }, - noAssets: { - Component: function NoAsset() { - return ( - - - - {t("mediabrowser.labels.nomedia")} - - - ); - }, + alignItems: "center", + justifyContent: "center", + }} + > + + + {t("mediabrowser.labels.nomedia")} + +
+ ); }, - }} - /> - )} - -
-
+ }, + }} + /> + )} + + ); } diff --git a/components/screen-splash/screen-splash.component.jsx b/components/screen-splash/screen-splash.component.jsx index 56e9eb6..f832652 100644 --- a/components/screen-splash/screen-splash.component.jsx +++ b/components/screen-splash/screen-splash.component.jsx @@ -27,8 +27,5 @@ const localStyles = StyleSheet.create({ middleAlign: { alignItems: "center", }, - content: { - paddingBottom: 150, - }, logo: { width: 100, height: 100, margin: 20 }, }); diff --git a/components/upload-progress/upload-progress.component.jsx b/components/upload-progress/upload-progress.component.jsx index b56853c..c2ee11f 100644 --- a/components/upload-progress/upload-progress.component.jsx +++ b/components/upload-progress/upload-progress.component.jsx @@ -1,9 +1,15 @@ +import { Ionicons } from "@expo/vector-icons"; import React from "react"; -import { ScrollView, StyleSheet, Text, View } from "react-native"; +import { + ScrollView, + StyleSheet, + Text, + TouchableOpacity, + View, +} from "react-native"; import * as Progress from "react-native-progress"; - -export default function UploadProgress({ uploads }) { - console.log("uploads :>> ", uploads); +import _ from "lodash"; +export default function UploadProgress({ uploads, setUploads }) { return ( @@ -19,6 +25,13 @@ export default function UploadProgress({ uploads }) { color={uploads[key].percent === 1 ? "green" : "blue"} /> + + setUploads((prevUploads) => _.omit(prevUploads, key)) + } + > + + ))} @@ -35,12 +48,14 @@ const styles = StyleSheet.create({ flexDirection: "row", alignItems: "center", marginBottom: 12, + marginLeft: 12, + marginRight: 12, }, progressText: { flex: 1, }, progressBarContainer: { - flex: 1, + flex: 3, marginLeft: 12, marginRight: 12, }, diff --git a/package.json b/package.json index 5461847..dcbe3ee 100644 --- a/package.json +++ b/package.json @@ -38,6 +38,7 @@ "lodash": "^4.17.20", "luxon": "^1.25.0", "native-base": "^2.13.15", + "p-limit": "^3.1.0", "react": "16.13.1", "react-dom": "16.13.1", "react-i18next": "^11.8.2", diff --git a/util/document-upload.utility.js b/util/document-upload.utility.js index 5362333..e19b2ae 100644 --- a/util/document-upload.utility.js +++ b/util/document-upload.utility.js @@ -10,13 +10,13 @@ var cleanAxios = axios.create(); cleanAxios.interceptors.request.eject(axiosAuthInterceptorId); export const handleUpload = async (ev, context) => { - const { onError, onSuccess, onProgress } = ev; + const { uri, filename, onError, onSuccess, onProgress } = ev; const { bodyshop, jobId } = context; - const newFile = await (await fetch(ev.uri)).blob(); + const newFile = await (await fetch(uri)).blob(); let extension = ev.uri.split(".").pop(); - let key = `${bodyshop.id}/${jobId}/${newFile.data.name.replace( + let key = `${bodyshop.id}/${jobId}/${(filename || newFile.data.name).replace( /\.[^/.]+$/, "" )}`; @@ -123,7 +123,7 @@ export const uploadToCloudinary = async ( ); // console.log("Cloudinary Upload Response", cloudinaryUploadResponse.data); } catch (error) { - console.log("CLOUDINARY error", error, cloudinaryUploadResponse); + console.log("CLOUDINARY error", error.response, cloudinaryUploadResponse); return { success: false, error: error }; } diff --git a/yarn.lock b/yarn.lock index bc03e4f..2f40c25 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6918,7 +6918,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==