Added separate documents display for non-images. BOD-420

This commit is contained in:
Patrick Fic
2020-10-02 13:35:29 -07:00
parent e2c3d7f4de
commit 1dea9deca3
10 changed files with 232 additions and 88 deletions

View File

@@ -1,4 +1,4 @@
<babeledit_project be_version="2.7.1" version="1.2">
<babeledit_project version="1.2" be_version="2.7.1">
<!--
BabelEdit project file
@@ -8470,6 +8470,48 @@
<folder_node>
<name>labels</name>
<children>
<concept_node>
<name>confirmdelete</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>doctype</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>upload</name>
<definition_loaded>false</definition_loaded>
@@ -16624,6 +16666,48 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>documents-images</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>documents-other</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>duplicateconfirm</name>
<definition_loaded>false</definition_loaded>

View File

@@ -35,7 +35,7 @@ export function DocumentsUploadComponent({
callback: callbackAfterUpload,
})
}
accept="audio/*,video/*,image/*"
accept="audio/*, video/*, image/*, .pdf, .doc, .docx, .xls, .xlsx"
showUploadList={false}
>
<Button type="primary">

View File

@@ -17,9 +17,7 @@ export const handleUpload = (ev, context) => {
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.replace(/\.[^/.]+$/, "")}`;
uploadToCloudinary(
key,
@@ -30,41 +28,6 @@ export const handleUpload = (ev, context) => {
onProgress,
context
);
// 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;
// uploadToCloudinary(
// key,
// file.type,
// file,
// onError,
// onSuccess,
// onProgress,
// context
// );
// },
// "blob"
// );
// } else {
// uploadToCloudinary(
// key,
// ev.file.type,
// ev.file,
// onError,
// onSuccess,
// onProgress,
// context
// );
// }
};
export const uploadToCloudinary = async (
@@ -84,12 +47,11 @@ export const uploadToCloudinary = async (
let tags = `${bodyshop.textid},${
tagsArray ? tagsArray.map((tag) => `${tag},`) : ""
}`;
let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS;
// let eager = process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS;
//Get the signed url.
const signedURLResponse = await axios.post("/media/sign", {
// eager: eager,
public_id: public_id,
tags: tags,
timestamp: timestamp,
@@ -117,15 +79,9 @@ export const uploadToCloudinary = async (
};
const formData = new FormData();
formData.append("file", file);
//formData.append("eager", eager);
// if (fileType.includes("image")) {
console.log("Applying lower quality transforms.");
formData.append("upload_preset", "incoming_upload");
// formData.append("quality", "auto");
// formData.append("width", "500");
// formData.append("height", "500");
// formData.append("crop", "limit");
// }
formData.append("api_key", process.env.REACT_APP_CLOUDINARY_API_KEY);
formData.append("public_id", public_id);
formData.append("tags", tags);

View File

@@ -6,7 +6,10 @@ import { logImEXEvent } from "../../firebase/firebase.utils";
export default function JobsDocumentsDownloadButton({ galleryImages }) {
const { t } = useTranslation();
const imagesToDownload = galleryImages.filter((image) => image.isSelected);
const imagesToDownload = [
...galleryImages.images.filter((image) => image.isSelected),
...galleryImages.other.filter((image) => image.isSelected),
];
const handleDownload = () => {
logImEXEvent("jobs_documents_download");

View File

@@ -1,6 +1,7 @@
import { Space } from "antd";
import { Collapse, Space } from "antd";
import React, { useEffect, useState } from "react";
import Gallery from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import DocumentsUploadComponent from "../documents-upload/documents-upload.component";
import JobsDocumentsDownloadButton from "./jobs-document-gallery.download.component";
import JobsDocumentsDeleteButton from "./jobs-documents-gallery.delete.component";
@@ -12,27 +13,55 @@ function JobsDocumentsComponent({
billId,
billsCallback,
}) {
const [galleryImages, setgalleryImages] = useState([]);
const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
const { t } = useTranslation();
useEffect(() => {
setgalleryImages(
data.reduce((acc, value) => {
acc.push({
src: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${value.key}`,
thumbnail: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${value.key}`,
tags: value.type.includes("pdf")
? [{ value: "PDF", title: "PDF" }]
: [],
thumbnailHeight: 200,
thumbnailWidth: 200,
isSelected: false,
key: value.key,
id: value.id,
});
let documents = data.reduce(
(acc, value) => {
if (value.type.includes("image")) {
acc.images.push({
src: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${value.key}`,
thumbnail: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${value.key}`,
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
key: value.key,
id: value.id,
});
} else {
acc.other.push({
src: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${value.key}`,
thumbnail: `${process.env.REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${value.key}`,
tags: [
{ value: "PDF", title: t("documents.labels.doctype") },
...(value.bill
? [
{
value: value.bill.vendor.name,
title: t("vendors.fields.name"),
},
{ value: value.bill.date, title: t("bills.fields.date") },
{
value: value.bill.invoice_number,
title: t("bills.fields.invoice_number"),
},
]
: []),
],
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
key: value.key,
id: value.id,
});
}
return acc;
}, [])
},
{ images: [], other: [] }
);
}, [data, setgalleryImages]);
setgalleryImages(documents);
}, [data, setgalleryImages, t]);
return (
<div className="clearfix">
@@ -49,17 +78,55 @@ function JobsDocumentsComponent({
deletionCallback={billsCallback || refetch}
/>
</Space>
<Gallery
images={galleryImages}
onSelectImage={(index, image) => {
setgalleryImages(
galleryImages.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
)
);
}}
/>
<Collapse
style={{ marginTop: "2rem" }}
defaultActiveKey={["images", "other"]}
bordered="false"
>
<Collapse.Panel key="images" header={t("jobs.labels.documents-images")}>
<Gallery
images={galleryImages.images}
backdropClosesModal={true}
onClickImage={(props) => {
window.open(
props.target.src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index, image) => {
setgalleryImages({
...galleryImages,
images: galleryImages.images.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Collapse.Panel>
<Collapse.Panel key="other" header={t("jobs.labels.documents-other")}>
<Gallery
images={galleryImages.other}
backdropClosesModal={true}
enableLightbox={false}
onClickThumbnail={(index) => {
window.open(
galleryImages.other[index].src,
"_blank",
"toolbar=0,location=0,menubar=0"
);
}}
onSelectImage={(index) => {
setgalleryImages({
...galleryImages,
other: galleryImages.other.map((g, idx) =>
index === idx ? { ...g, isSelected: !g.isSelected } : g
),
});
}}
/>
</Collapse.Panel>
</Collapse>
</div>
);
}

View File

@@ -1,10 +1,11 @@
import { Button, notification } from "antd";
import { Button, notification, Popconfirm } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import axios from "axios";
import { useMutation } from "@apollo/react-hooks";
import { DELETE_DOCUMENT } from "../../graphql/documents.queries";
import { logImEXEvent } from "../../firebase/firebase.utils";
import { QuestionCircleOutlined } from "@ant-design/icons";
import { axiosAuthInterceptorId } from "../../App/App.container";
//Context: currentUserEmail, bodyshop, jobid, invoiceid
@@ -18,7 +19,10 @@ export default function JobsDocumentsDeleteButton({
}) {
const { t } = useTranslation();
const [deleteDocument] = useMutation(DELETE_DOCUMENT);
const imagesToDelete = galleryImages.filter((image) => image.isSelected);
const imagesToDelete = [
...galleryImages.images.filter((image) => image.isSelected),
...galleryImages.other.filter((image) => image.isSelected),
];
const [loading, setLoading] = useState(false);
const handleDelete = () => {
logImEXEvent("job_documents_delete", { count: imagesToDelete.length });
@@ -76,12 +80,18 @@ export default function JobsDocumentsDeleteButton({
};
return (
<Button
<Popconfirm
disabled={imagesToDelete.length < 1}
loading={loading}
onClick={handleDelete}
icon={<QuestionCircleOutlined style={{ color: "red" }} />}
onConfirm={handleDelete}
title={t("documents.labels.confirmdelete")}
okText={t("general.actions.delete")}
okButtonProps={{ type: "danger" }}
cancelText={t("general.actions.cancel")}
>
{t("documents.actions.delete")}
</Button>
<Button disabled={imagesToDelete.length < 1} loading={loading}>
{t("documents.actions.delete")}
</Button>
</Popconfirm>
);
}

View File

@@ -2,11 +2,23 @@ import gql from "graphql-tag";
export const GET_DOCUMENTS_BY_JOB = gql`
query GET_DOCUMENTS_BY_JOB($jobId: uuid!) {
documents(where: { jobid: { _eq: $jobId } }) {
documents(
where: { jobid: { _eq: $jobId } }
order_by: { updated_at: desc }
) {
id
name
key
type
bill {
id
invoice_number
date
vendor {
id
name
}
}
}
}
`;

View File

@@ -561,6 +561,8 @@
"nodocuments": "There are no documents."
},
"labels": {
"confirmdelete": "Are you sure you want to delete these documents. This CANNOT be undone.",
"doctype": "Document Type",
"upload": "Upload"
},
"successes": {
@@ -1018,6 +1020,8 @@
},
"difference": "Difference",
"documents": "Documents",
"documents-images": "Images",
"documents-other": "Other Documents",
"duplicateconfirm": "Are you sure you want to duplicate this job? Some elements of this job will not be duplicated.",
"employeeassignments": "Employee Assignments",
"existing_jobs": "Existing Jobs",

View File

@@ -561,6 +561,8 @@
"nodocuments": "No hay documentos"
},
"labels": {
"confirmdelete": "",
"doctype": "",
"upload": "Subir"
},
"successes": {
@@ -1018,6 +1020,8 @@
},
"difference": "",
"documents": "documentos",
"documents-images": "",
"documents-other": "",
"duplicateconfirm": "",
"employeeassignments": "",
"existing_jobs": "Empleos existentes",

View File

@@ -561,6 +561,8 @@
"nodocuments": "Il n'y a pas de documents."
},
"labels": {
"confirmdelete": "",
"doctype": "",
"upload": "Télécharger"
},
"successes": {
@@ -1018,6 +1020,8 @@
},
"difference": "",
"documents": "Les documents",
"documents-images": "",
"documents-other": "",
"duplicateconfirm": "",
"employeeassignments": "",
"existing_jobs": "Emplois existants",