diff --git a/client/src/components/documents-upload/documents-upload.container.jsx b/client/src/components/documents-upload/documents-upload.container.jsx index 0b0fe4615..b63fe8f0a 100644 --- a/client/src/components/documents-upload/documents-upload.container.jsx +++ b/client/src/components/documents-upload/documents-upload.container.jsx @@ -1,17 +1,9 @@ -import { useMutation } from "@apollo/react-hooks"; -import { notification } from "antd"; -import axios from "axios"; -import React, { useRef } from "react"; -import { useTranslation } from "react-i18next"; -import Resizer from "react-image-file-resizer"; +import React from "react"; import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; -import { INSERT_NEW_DOCUMENT } from "../../graphql/documents.queries"; -import { - selectBodyshop, - selectCurrentUser, -} from "../../redux/user/user.selectors"; +import { selectBodyshop, selectCurrentUser } from "../../redux/user/user.selectors"; import DocumentsUploadComponent from "./documents-upload.component"; +import { handleUpload } from "./documents-upload.utility"; const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, @@ -27,137 +19,18 @@ export function DocumentsUploadContainer({ callbackAfterUpload, onChange, }) { - const { t } = useTranslation(); - const [insertNewDocument] = useMutation(INSERT_NEW_DOCUMENT); - const UploadRef = useRef(null); - - const handleUpload = (ev) => { - const { onError, onSuccess, onProgress } = ev; - //If PDF, upload directly. - //If JPEG, resize and upload. - //TODO If this is just an invoice job? Where to put it? - let key = `${bodyshop.id}/${jobId}/${ev.file.name}`; - if (ev.file.type.includes("image")) { - Resizer.imageFileResizer( - ev.file, - 2500, - 2500, - "JPEG", - 75, - 0, - (uri) => { - let file = new File([uri], ev.file.name, {}); - file.uid = ev.file.uid; - uploadToS3(key, file.type, file, onError, onSuccess, onProgress); - }, - "blob" - ); - } else { - uploadToS3(key, ev.file.type, ev.file, onError, onSuccess, onProgress); - } - }; - - const uploadToS3 = ( - fileName, - fileType, - file, - onError, - onSuccess, - onProgress - ) => { - let timestamp = Math.floor(Date.now() / 1000); - let public_id = fileName; - let tags = `${bodyshop.textid},${ - tagsArray ? tagsArray.map((tag) => `${tag},`) : "" - }`; - let eager = "w_200,h_200,c_thumb"; - axios - .post("/media/sign", { - eager: eager, - public_id: public_id, - tags: tags, - timestamp: timestamp, - }) - .then((response) => { - var signature = response.data; - var options = { - headers: { "X-Requested-With": "XMLHttpRequest" }, - onUploadProgress: (e) => { - onProgress({ percent: (e.loaded / e.total) * 100 }); - }, - }; - const formData = new FormData(); - formData.append("file", file); - formData.append("eager", eager); - 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); - - axios - .post( - `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/upload`, - formData, - options - ) - .then((response) => { - console.log("response", response); - - insertNewDocument({ - variables: { - docInput: [ - { - jobid: jobId, - uploaded_by: currentUser.email, - key: fileName, - invoiceid: invoiceId, - type: fileType, - }, - ], - }, - }).then((r) => { - onSuccess({ - uid: r.data.insert_documents.returning[0].id, - name: r.data.insert_documents.returning[0].name, - status: "done", - key: r.data.insert_documents.returning[0].key, - }); - notification["success"]({ - message: t("documents.successes.insert"), - }); - if (callbackAfterUpload) { - callbackAfterUpload(); - } - if (onChange) { - //Used in a form. - onChange(UploadRef.current.state.fileList); - } - }); - }) - .catch((error) => { - onError(error); - notification["error"]({ - message: t("documents.errors.insert", { - message: JSON.stringify(error), - }), - }); - }); - }) - .catch((error) => { - console.log("error", error); - notification["error"]({ - message: t("documents.errors.getpresignurl", { - message: JSON.stringify(error), - }), - }); - }); - }; - return ( + handleUpload(ev, { + bodyshop: bodyshop, + uploaded_by: currentUser.email, + jobId: jobId, + invoiceId: invoiceId, + tagsArray: tagsArray, + callback: callbackAfterUpload, + }) + } /> ); } diff --git a/client/src/components/documents-upload/documents-upload.utility.js b/client/src/components/documents-upload/documents-upload.utility.js new file mode 100644 index 000000000..4f5fda5e2 --- /dev/null +++ b/client/src/components/documents-upload/documents-upload.utility.js @@ -0,0 +1,161 @@ +import { notification } from "antd"; +import axios from "axios"; +import Resizer from "react-image-file-resizer"; +import { client } from "../../App/App.container"; +import { INSERT_NEW_DOCUMENT } from "../../graphql/documents.queries"; +import i18n from "i18next"; + +//Context: currentUserEmail, bodyshop, jobid, invoiceid +export const handleUpload = (ev, context) => { + console.log("ev", ev); + const { onError, onSuccess, onProgress } = ev; + const { bodyshop, jobId } = context; + //If PDF, upload directly. + //If JPEG, resize and upload. + //TODO If this is just an invoice job? Where to put it? + let key = `${bodyshop.id}/${jobId}/${ev.file.name}`; + if (ev.file.type.includes("image")) { + Resizer.imageFileResizer( + ev.file, + 2500, + 2500, + "JPEG", + 75, + 0, + (uri) => { + let file = new File([uri], ev.file.name, {}); + file.uid = ev.file.uid; + uploadToS3( + key, + file.type, + file, + onError, + onSuccess, + onProgress, + context + ); + }, + "blob" + ); + } else { + uploadToS3( + key, + ev.file.type, + ev.file, + onError, + onSuccess, + onProgress, + context + ); + } +}; + +export const uploadToS3 = ( + fileName, + fileType, + file, + onError, + onSuccess, + onProgress, + context +) => { + const { + bodyshop, + jobId, + invoiceId, + uploaded_by, + callback, + tagsArray, + } = context; + + let timestamp = Math.floor(Date.now() / 1000); + let public_id = fileName; + let tags = `${bodyshop.textid},${ + tagsArray ? tagsArray.map((tag) => `${tag},`) : "" + }`; + let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS; + axios + .post("/media/sign", { + eager: eager, + public_id: public_id, + tags: tags, + timestamp: timestamp, + }) + .then((response) => { + var signature = response.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("eager", eager); + 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); + + axios + .post( + `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/upload`, + formData, + options + ) + .then((response) => { + console.log("Upload Response", response); + client + .mutate({ + mutation: INSERT_NEW_DOCUMENT, + variables: { + docInput: [ + { + jobid: jobId, + uploaded_by: uploaded_by, + key: fileName, + invoiceid: invoiceId, + type: fileType, + }, + ], + }, + }) + .then((r) => { + if (!!onSuccess) + onSuccess({ + uid: r.data.insert_documents.returning[0].id, + name: r.data.insert_documents.returning[0].name, + status: "done", + key: r.data.insert_documents.returning[0].key, + }); + notification["success"]({ + message: i18n.t("documents.successes.insert"), + }); + if (callback) { + callback(); + } + // if (onChange) { + // //Used in a form. + // onChange(UploadRef.current.state.fileList); + // } + }); + }) + .catch((error) => { + if (!!onError) onError(error); + notification["error"]({ + message: i18n.t("documents.errors.insert", { + message: JSON.stringify(error), + }), + }); + }); + }) + .catch((error) => { + console.log("error", error); + notification["error"]({ + message: i18n.t("documents.errors.getpresignurl", { + message: JSON.stringify(error), + }), + }); + }); +}; diff --git a/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx b/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx index 534b86335..752d7a38d 100644 --- a/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx +++ b/client/src/components/invoice-detail-edit/invoice-detail-edit.container.jsx @@ -38,7 +38,7 @@ export function InvoiceDetailEditContainer({ bodyshop }) { }, [form, search.invoiceid]); if (error) return ; - if (!!!search.invoiceid) return
{t("invoices.labels.noneseleced")}
; + if (!!!search.invoiceid) return
{t("invoices.labels.noneselected")}
; return (
({ toggleModalVisible: () => dispatch(toggleModalVisible("invoiceEnter")), @@ -22,19 +24,23 @@ function InvoiceEnterModalContainer({ invoiceEnterModal, toggleModalVisible, bodyshop, + currentUser, }) { const [form] = Form.useForm(); const { t } = useTranslation(); const [enterAgain, setEnterAgain] = useState(false); const [insertInvoice] = useMutation(INSERT_NEW_INVOICE); + const [loading, setLoading] = useState(false); const handleFinish = (values) => { + setLoading(true); + const { upload, ...remainingValues } = values; insertInvoice({ variables: { invoice: [ - Object.assign({}, values, { + Object.assign({}, remainingValues, { invoicelines: { - data: values.invoicelines.map((i) => { + data: remainingValues.invoicelines.map((i) => { return { ...i, joblineid: i.joblineid === "noline" ? null : i.joblineid, @@ -46,6 +52,27 @@ function InvoiceEnterModalContainer({ }, }) .then((r) => { + const invoiceId = r.data.insert_invoices.returning[0].id; + console.log("invoiceId", invoiceId); + ///////////////////////// + if (upload && upload.length > 0) { + //insert Each of the documents? + upload.forEach((u) => { + handleUpload( + { file: u.originFileObj }, + { + bodyshop: bodyshop, + uploaded_by: currentUser.email, + jobId: values.jobid, + invoiceId: invoiceId, + tagsArray: null, + callback: null, + } + ); + }); + } + /////////////////////////// + setLoading(false); notification["success"]({ message: t("invoices.successes.created"), }); @@ -60,6 +87,7 @@ function InvoiceEnterModalContainer({ setEnterAgain(false); }) .catch((error) => { + setLoading(false); setEnterAgain(false); notification["error"]({ message: t("invoices.errors.creating", { @@ -89,12 +117,13 @@ function InvoiceEnterModalContainer({ footer={ - {invoiceEnterModal.context && invoiceEnterModal.context.id ? null : ( + @@ -180,7 +196,6 @@ export default function InvoiceFormComponent({ "local_tax_rate", ]); let totals; - console.log("values", values); if ( !!values.total && !!values.invoicelines && @@ -234,6 +249,10 @@ export default function InvoiceFormComponent({ return null; }} + + ); } diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index c5022acd9..e775eea52 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -381,7 +381,7 @@ "invoice_total": "Invoice Total Amount", "local_tax": "Local Tax", "new": "New Invoice", - "noneselected": "No invoice selected.F", + "noneselected": "No invoice selected.", "state_tax": "State Tax", "subtotal": "Subtotal" },