import { notification } from "antd"; import axios from "axios"; import i18n from "i18next"; import { logImEXEvent } from "../../firebase/firebase.utils"; import { INSERT_NEW_DOCUMENT } from "../../graphql/documents.queries"; import { axiosAuthInterceptorId } from "../../utils/CleanAxios"; import client from "../../utils/GraphQLClient"; import exifr from "exifr"; //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 = (ev, context) => { console.log("Handling Upload", ev); logImEXEvent("document_upload", { filetype: ev.file.type }); const { onError, onSuccess, onProgress } = ev; const { bodyshop, jobId } = context; const fileName = ev.file.name || ev.filename; let key = `${bodyshop.id}/${jobId}/${fileName.replace( /\.[^/.]+$/, "" )}-${new Date().getTime()}`; let extension = fileName.split(".").pop(); uploadToCloudinary( key, extension, ev.file.type, ev.file, onError, onSuccess, onProgress, context ); }; export const uploadToCloudinary = async ( key, extension, fileType, file, onError, onSuccess, onProgress, context ) => { const { bodyshop, jobId, billId, uploaded_by, callback, tagsArray } = 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; //Get the signed url. console.log("fileType", fileType); const upload_preset = fileType.startsWith("video") ? "incoming_upload_video" : "incoming_upload"; const signedURLResponse = await axios.post("/media/sign", { public_id: public_id, tags: tags, timestamp: timestamp, upload_preset: upload_preset, }); if (signedURLResponse.status !== 200) { console.log("Error Getting Signed URL", signedURLResponse.statusText); if (!!onError) onError(signedURLResponse.statusText); notification["error"]({ message: i18n.t("documents.errors.getpresignurl", { message: signedURLResponse.statusText, }), }); return; } //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) * 100 }); }, }; const formData = new FormData(); formData.append("file", file); formData.append("upload_preset", upload_preset); formData.append("api_key", process.env.REACT_APP_CLOUDINARY_API_KEY); formData.append("public_id", public_id); formData.append("tags", tags); formData.append("timestamp", timestamp); formData.append("signature", signature); const cloudinaryUploadResponse = await cleanAxios.post( `${process.env.REACT_APP_CLOUDINARY_ENDPOINT_API}/${DetermineFileType( fileType )}/upload`, formData, { ...options, } ); console.log("Upload Response", cloudinaryUploadResponse.data); if (cloudinaryUploadResponse.status !== 200) { console.log( "Error uploading to cloudinary.", cloudinaryUploadResponse.statusText ); if (!!onError) onError(cloudinaryUploadResponse.statusText); notification["error"]({ message: i18n.t("documents.errors.insert", { message: cloudinaryUploadResponse.statusText, }), }); return; } //Insert the document with the matching key. let takenat; if (fileType.includes("image")) { try { const exif = await exifr.parse(file); takenat = exif && exif.DateTimeOriginal; } catch (error) { console.log("Unable to parse image file for EXIF Data"); } } const documentInsert = await client.mutate({ mutation: INSERT_NEW_DOCUMENT, variables: { docInput: [ { ...(jobId ? { jobid: jobId } : {}), ...(billId ? { billid: billId } : {}), uploaded_by: uploaded_by, key: key, type: fileType, extension: cloudinaryUploadResponse.data.format || extension, bodyshopid: bodyshop.id, size: cloudinaryUploadResponse.data.bytes || file.size, takenat, }, ], }, }); 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.open({ type: "success", key: "docuploadsuccess", 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(documentInsert.errors), }), }); return; } }; //Also needs to be updated in media JS and mobile app. 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"; }