diff --git a/App.js b/App.js index 9c2dae3..8380d63 100644 --- a/App.js +++ b/App.js @@ -1,3 +1,4 @@ +import 'expo-dev-client'; import { ApolloProvider } from "@apollo/client"; import * as Sentry from "@sentry/react-native"; import "expo-asset"; @@ -26,7 +27,7 @@ Sentry.init({ enableInExpoDevelopment: true, // tracesSampleRate: 0.2, // integrations: [ - // new Sentry.Native.ReactNativeTracing({ + // new Sentry.ReactNativeTracing({ // tracingOrigins: ["localhost", "imex.online", "cloudinary.com", /^\//], // // ... other options // }), diff --git a/app.json b/app.json index bf08d6f..3e2d921 100644 --- a/app.json +++ b/app.json @@ -82,6 +82,12 @@ "isAccessMediaLocationEnabled": "true" } ], + [ + "expo-image-picker", + { + "photosPermission": "Allow $(PRODUCT_NAME) to access your photos and upload them to the system." + } + ], "expo-localization", "expo-font" ] diff --git a/components/job-documents/job-documents-local.component.jsx b/components/job-documents/job-documents-local.component.jsx index 1641809..181d31b 100644 --- a/components/job-documents/job-documents-local.component.jsx +++ b/components/job-documents/job-documents-local.component.jsx @@ -101,7 +101,7 @@ async function getPhotos({ bodyshop, jobid, setImages }) { setImages(normalizedImages); } catch (error) { - Sentry.Native.captureException(error); + Sentry.captureException(error); Toast.show({ type: "error", text1: `Error fetching photos.`, diff --git a/components/screen-media-browser/screen-media-browser.component.jsx b/components/screen-media-browser/screen-media-browser.component.jsx index a55fada..83e9e45 100644 --- a/components/screen-media-browser/screen-media-browser.component.jsx +++ b/components/screen-media-browser/screen-media-browser.component.jsx @@ -18,6 +18,9 @@ import JobSpaceAvailable from "../job-space-available/job-space-available.compon import UploadProgressLocal from "../upload-progress-local/upload-progress-local.component"; import UploadDeleteSwitch from "../upload-delete-switch/upload-delete-switch.component"; import UploadProgress from "../upload-progress/upload-progress.component"; +// import * as ImagePicker from "expo-image-picker"; +// import { Button } from "react-native-paper"; +// import * as MediaLibrary from "expo-media-library"; const mapStateToProps = createStructuredSelector({ selectedCameraJobId: selectCurrentCameraJobId, @@ -38,12 +41,29 @@ export function ImageBrowserScreen({ const { t } = useTranslation(); const [uploads, setUploads] = useState(null); const [tick, setTick] = useState(0); + // const [medialLibraryPermissionStatus, requestmediaLibraryPermission] = + // ImagePicker.useMediaLibraryPermissions(); + const forceRerender = useCallback(() => { setTick((tick) => tick + 1); }, []); const onDone = (data) => { logImEXEvent("imexmobile_upload_documents", { count: data.length }); + // const uploads = await Promise.all( + // data.map(async (item) => { + // let id = item.id || item.fileName; + // if (!item.id && item.uri) { + // id = await getAssetIdFromUri(item.uri, item.fileName); + // } + // return { + // ...item, + // localUri: item.uri, + // id, + // }; + // }) + // ); + // console.log("onDone", uploads); if (data.length !== 0) setUploads(data); }; @@ -73,25 +93,6 @@ export function ImageBrowserScreen({ [] ); - const widgetResize = useMemo( - () => ({ - width: 50, - compress: 0.7, - base64: false, - saveTo: "jpeg", - }), - [] - ); - - const _textStyle = { - color: "white", - }; - - const _buttonStyle = { - backgroundColor: "orange", - borderRadius: 5, - }; - const widgetNavigator = useMemo( () => ({ Texts: { @@ -134,6 +135,33 @@ export function ImageBrowserScreen({ [] ); + // const handleSelectPhotos = async () => { + // let result = await ImagePicker.launchImageLibraryAsync({ + // mediaTypes: ["images", "videos"], + // allowsMultipleSelection: true, + // // aspect: [4, 3], + // }); + // console.log("*** ~ handleSelectPhotos ~ result:", result); + + // if (!result.canceled) { + // const uploads = await Promise.all( + // result.assets.map(async (item) => { + // let id = item.id || item.fileName; + // if (!item.id && item.uri) { + // id = await getAssetIdFromUri(item.uri); + // } + // return { + // ...item, + // localUri: item.uri, + // id, + // }; + // }) + // ); + // console.log("Uploads from handleSelectPhotos", uploads); + // setUploads(uploads); + // } + // }; + return ( @@ -147,16 +175,6 @@ export function ImageBrowserScreen({ )} - { - // - } {!selectedCameraJobId && ( asset.uri === uri); + +// // Fallback: try to match by filename if not found and filename is available +// if (!found && filename) { +// found = page.assets.find((asset) => asset.filename === filename); +// } + +// after = page.endCursor; +// pageCount++; +// if (!after) break; +// } + +// return found ? found.id : null; +// } diff --git a/components/upload-progress-local/upload-progress-local.component.jsx b/components/upload-progress-local/upload-progress-local.component.jsx index 26393ca..3840823 100644 --- a/components/upload-progress-local/upload-progress-local.component.jsx +++ b/components/upload-progress-local/upload-progress-local.component.jsx @@ -79,7 +79,7 @@ export function UploadProgress({ const deleteResult = await MediaLibrary.deleteAlbumsAsync(album); } catch (error) { console.log("Unable to delete picture.", error); - Sentry.Native.captureException(error); + Sentry.captureException(error); } } diff --git a/components/upload-progress/upload-progress.component.jsx b/components/upload-progress/upload-progress.component.jsx index a8465a8..bcdfc74 100644 --- a/components/upload-progress/upload-progress.component.jsx +++ b/components/upload-progress/upload-progress.component.jsx @@ -132,10 +132,14 @@ export function UploadProgress({ const data = []; const totalOfUploads = await selectedFiles.reduce(async (acc, val) => { //Get the size of the file based on URI. - const info = await FileSystem.getInfoAsync(val.uri, { size: true }); - data.push({ ...info, ...val }); //Add in the size. - val.albumId && MediaLibrary.migrateAlbumIfNeededAsync(val.albumId); - return (await acc) + info.size; + if (acc.fileSize) { + return acc + acc.fileSize; + } else { + const info = await FileSystem.getInfoAsync(val.uri, { size: true }); + data.push({ ...info, ...val }); //Add in the size. + val.albumId && MediaLibrary.migrateAlbumIfNeededAsync(val.albumId); + return (await acc) + info.size; + } }, 0); if (selectedCameraJobId !== "temp") { @@ -231,7 +235,7 @@ export function UploadProgress({ } } catch (error) { console.log("Unable to delete picture.", error); - Sentry.Native.captureException(error); + Sentry.captureException(error); } } filesToDelete = []; diff --git a/package-lock.json b/package-lock.json index 011c448..d8b0fa3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34,6 +34,7 @@ "expo-file-system": "~18.0.10", "expo-font": "~13.0.3", "expo-image-manipulator": "~13.0.6", + "expo-image-picker": "~16.0.6", "expo-images-picker": "^2.5.1", "expo-localization": "~16.0.1", "expo-media-library": "~17.0.6", @@ -9506,6 +9507,18 @@ "expo": "*" } }, + "node_modules/expo-image-picker": { + "version": "16.0.6", + "resolved": "https://registry.npmjs.org/expo-image-picker/-/expo-image-picker-16.0.6.tgz", + "integrity": "sha512-HN4xZirFjsFDIsWFb12AZh19fRzuvZjj2ll17cGr19VNRP06S/VPQU3Tdccn5vwUzQhOBlLu704CnNm278boiQ==", + "license": "MIT", + "dependencies": { + "expo-image-loader": "~5.0.0" + }, + "peerDependencies": { + "expo": "*" + } + }, "node_modules/expo-images-picker": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/expo-images-picker/-/expo-images-picker-2.5.1.tgz", diff --git a/package.json b/package.json index a93a9fc..bde94ed 100644 --- a/package.json +++ b/package.json @@ -89,7 +89,8 @@ "redux-logger": "^3.0.6", "redux-persist": "^6.0.0", "redux-saga": "^1.3.0", - "reselect": "^5.1.1" + "reselect": "^5.1.1", + "expo-image-picker": "~16.0.6" }, "devDependencies": { "@babel/core": "^7.26.8", diff --git a/redux/user/user.sagas.js b/redux/user/user.sagas.js index ed55de2..c81017e 100644 --- a/redux/user/user.sagas.js +++ b/redux/user/user.sagas.js @@ -108,7 +108,7 @@ export function* onSignInSuccess() { export function* signInSuccessSaga({ payload }) { try { // Analytics.setUserId(payload.email);//JF:commenting out the firebase analytics portion - //Sentry.Native.setUser({ email: payload.email }); + //Sentry.setUser({ email: payload.email }); const shop = yield client.query({ query: QUERY_BODYSHOP }); logImEXEvent("imexmobile_sign_in_success", payload); @@ -123,7 +123,7 @@ export function* signInSuccessSaga({ payload }) { // ); } catch (error) { console.log("UH-OH. Couldn't get shop details.", error); - Sentry.Native.captureException(error); + Sentry.captureException(error); } } diff --git a/util/document-upload.utility.js b/util/document-upload.utility.js index 212fbfc..4bcbd3f 100644 --- a/util/document-upload.utility.js +++ b/util/document-upload.utility.js @@ -17,29 +17,30 @@ cleanAxios.interceptors.request.eject(axiosAuthInterceptorId); export const handleUpload = async (ev, context) => { const { mediaId, onError, onSuccess, onProgress } = ev; const { bodyshop, jobId } = context; + try { - const imageData = await MediaLibrary.getAssetInfoAsync(mediaId); - const newFile = await ( - await fetch(imageData.localUri || imageData.uri) - ).blob(); - let extension = imageData.localUri.split(".").pop(); + const imageData = await MediaLibrary.getAssetInfoAsync(mediaId); + const newFile = await ( + await fetch(imageData.localUri || imageData.uri) + ).blob(); + let extension = imageData.localUri.split(".").pop(); - //Default to Cloudinary in case of split treatment errors. - let destination = - splitClient?.getTreatment("Imgproxy") === "on" ? "imgproxy" : "cloudinary"; + //Default to Cloudinary in case of split treatment errors. + let destination = + splitClient?.getTreatment("Imgproxy") === "on" ? "imgproxy" : "cloudinary"; - let key = - destination === "imgproxy" - ? `${bodyshop.id}/${jobId}/${replaceAccents( + let key = + destination === "imgproxy" + ? `${bodyshop.id}/${jobId}/${replaceAccents( imageData.filename || imageData.uri.split("/").pop() ).replace(/[^A-Z0-9]+/gi, "_")}-${new Date().getTime()}.${extension}` - : `${bodyshop.id}/${jobId}/${( + : `${bodyshop.id}/${jobId}/${( imageData.filename || imageData.uri.split("/").pop() ).replace(/\.[^/.]+$/, "")}-${new Date().getTime()}`; - const res = - destination === "imgproxy" - ? await uploadToImgproxy( + const res = + destination === "imgproxy" + ? await uploadToImgproxy( key, mediaId, imageData, @@ -51,7 +52,7 @@ export const handleUpload = async (ev, context) => { onProgress, context ) - : await uploadToCloudinary( + : await uploadToCloudinary( key, mediaId, imageData, @@ -63,7 +64,18 @@ export const handleUpload = async (ev, context) => { onProgress, context ); - return res; + return res; + } catch (error) { + console.log("Error creating upload promise", error.message, error.stack); + if (onError) onError(error.message); + Sentry.captureException(error); + return { + success: false, + error: error.message, + stack: error.stack, + mediaId, + }; + } }; export const handleUploadImgproxy = async (ev, context) => { @@ -196,7 +208,7 @@ export const uploadToImgproxy = async ( stack: error.stack, mediaId, }; - Sentry.Native.captureException(error); + Sentry.captureException(error); } const documentInsert = await client.mutate({ @@ -270,7 +282,7 @@ export const uploadToCloudinary = async ( }); } catch (error) { console.log("ERROR GETTING SIGNED URL", error); - Sentry.Native.captureException(error); + Sentry.captureException(error); return { success: false, error: error }; } @@ -319,7 +331,7 @@ export const uploadToCloudinary = async ( ); } catch (error) { console.log("CLOUDINARY error", error.response, cloudinaryUploadResponse); - Sentry.Native.captureException(error); + Sentry.captureException(error); if (onError) onError(error.message); return { success: false, error: error }; diff --git a/util/local-document-upload.utility.js b/util/local-document-upload.utility.js index 36d724f..ad49097 100644 --- a/util/local-document-upload.utility.js +++ b/util/local-document-upload.utility.js @@ -96,14 +96,14 @@ export const handleLocalUpload = async ({ }); } } catch (error) { - Sentry.Native.captureException(error); + Sentry.captureException(error); console.log("Error uploading documents:", error.message); onError && onError({ error: error.message }); } } catch (error) { console.log("Uncaught error", error); - Sentry.Native.captureException(error); + Sentry.captureException(error); onError && onError({ error: error.message }); }