import axios from "axios"; import env from "../env"; import { client } from "../graphql/client"; import { INSERT_NEW_DOCUMENT } from "../graphql/documents.queries"; import { axiosAuthInterceptorId } from "./CleanAxios"; import * as MediaLibrary from "expo-media-library"; import { gql } from "@apollo/client"; //Context: currentUserEmail, bodyshop, jobid, invoiceid //Required to prevent headers from getting set and rejected from Cloudinary. var cleanAxios = axios.create(); cleanAxios.interceptors.request.eject(axiosAuthInterceptorId); export const handleUpload = async (ev, context) => { const { filename, mediaId, onError, onSuccess, onProgress } = ev; const { bodyshop, jobId } = context; const imageData = await MediaLibrary.getAssetInfoAsync(mediaId); const newFile = await (await fetch(imageData.localUri)).blob(); let extension = imageData.localUri.split(".").pop(); let key = `${bodyshop.id}/${jobId}/${(filename || newFile.data.name).replace( /\.[^/.]+$/, "" )}-${new Date().getTime()}`; const res = await uploadToCloudinary( key, mediaId, imageData, extension, newFile.type, newFile, onError, onSuccess, onProgress, context ); return res; }; export const uploadToCloudinary = async ( key, mediaId, imageData, extension, fileType, file, onError, onSuccess, onProgress, context ) => { const { bodyshop, jobId, billId, uploaded_by, callback, tagsArray, photo } = context; //Set variables for getting the signed URL. let timestamp = Math.floor(Date.now() / 1000); let public_id = key; let tags = `${bodyshop.textid},${ tagsArray ? tagsArray.map((tag) => `${tag},`) : "" }`; // let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS; const upload_preset = fileType.startsWith("video") ? "incoming_upload_video" : "incoming_upload"; //Get the signed url. let signedURLResponse; try { signedURLResponse = await axios.post(`${env.API_URL}/media/sign`, { public_id: public_id, tags: tags, timestamp: timestamp, upload_preset: upload_preset, }); } catch (error) { console.log("ERROR GETTING SIGNED URL", error); return { success: false, error: error }; } if (signedURLResponse.status !== 200) { console.log("Error Getting Signed URL", signedURLResponse.statusText); if (onError) onError(signedURLResponse.statusText); return { success: false, error: signedURLResponse.statusText }; } //Build request to end to cloudinary. var signature = signedURLResponse.data; var options = { headers: { "X-Requested-With": "XMLHttpRequest" }, onUploadProgress: (e) => { if (onProgress) onProgress({ percent: e.loaded / e.total, loaded: e.loaded }); }, }; const formData = new FormData(); formData.append("file", { uri: imageData.localUri, type: fileType, name: file.data.name, }); formData.append("upload_preset", upload_preset); formData.append("api_key", env.REACT_APP_CLOUDINARY_API_KEY); formData.append("public_id", public_id); formData.append("tags", tags); formData.append("timestamp", timestamp); formData.append("signature", signature); //Upload request to Cloudinary let cloudinaryUploadResponse; try { cloudinaryUploadResponse = await cleanAxios.post( `${env.REACT_APP_CLOUDINARY_ENDPOINT_API}/${DetermineFileType( fileType )}/upload`, formData, { ...options, } ); // console.log("Cloudinary Upload Response", cloudinaryUploadResponse.data); } catch (error) { console.log("CLOUDINARY error", error.response, cloudinaryUploadResponse); return { success: false, error: error }; } if (cloudinaryUploadResponse.status !== 200) { console.log( "Error uploading to cloudinary.", cloudinaryUploadResponse.statusText, cloudinaryUploadResponse ); if (onError) onError(cloudinaryUploadResponse.statusText); return { success: false, error: cloudinaryUploadResponse.statusText }; } //Insert the document with the matching key. const documentInsert = await client.mutate({ mutation: INSERT_NEW_DOCUMENT, update: (cache, { data }) => { cache.modify({ fields: { documents: (existingDocs = []) => { const newDocRef = cache.writeFragment({ data: data.insert_documents.returning[0], fragment: gql` fragment newDoc on documents { id name key type takenat extension jobid } `, }); return [...existingDocs, newDocRef]; }, }, }); }, variables: { docInput: [ { ...(jobId ? { jobid: jobId } : {}), ...(billId ? { billid: billId } : {}), uploaded_by: uploaded_by, key: key, type: fileType, extension: extension, bodyshopid: bodyshop.id, size: cloudinaryUploadResponse.data.bytes || file.size, ...(imageData.creationTime ? { takenat: new Date(imageData.creationTime) } : {}), }, ], }, }); if (!documentInsert.errors) { if (onSuccess) onSuccess({ uid: documentInsert.data.insert_documents.returning[0].id, name: documentInsert.data.insert_documents.returning[0].name, status: "done", key: documentInsert.data.insert_documents.returning[0].key, }); // notification["success"]({ // message: i18n.t("documents.successes.insert"), // }); if (callback) { callback(); } } else { if (onError) onError(JSON.stringify(documentInsert.errors)); // notification["error"]({ // message: i18n.t("documents.errors.insert", { // message: JSON.stringify(JSON.stringify(documentInsert.errors)), // }), // }); return { success: false, error: JSON.stringify(documentInsert.errors), mediaId, }; } return { success: true, mediaId }; }; export function DetermineFileType(filetype) { if (!filetype) return "auto"; else if (filetype.startsWith("image")) return "image"; else if (filetype.startsWith("video")) return "video"; else if (filetype.startsWith("application/pdf")) return "image"; else if (filetype.startsWith("application")) return "raw"; return "auto"; } export function formatBytes(a, b = 2) { if (0 === a || !a) return "0 Bytes"; const c = 0 > b ? 0 : b, d = Math.floor(Math.log(a) / Math.log(1024)); return ( parseFloat((a / Math.pow(1024, d)).toFixed(c)) + " " + ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"][d] ); }