diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index d6de7fd77..c6fbd2117 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -37640,6 +37640,27 @@ + + production_by_technician + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + purchases_by_cost_center_detail false diff --git a/client/package.json b/client/package.json index 3cf72787b..34ae41cea 100644 --- a/client/package.json +++ b/client/package.json @@ -78,7 +78,8 @@ "workbox-range-requests": "^6.4.2", "workbox-routing": "^6.4.2", "workbox-strategies": "^6.4.2", - "workbox-streams": "^6.4.2" + "workbox-streams": "^6.4.2", + "yauzl": "^2.10.0" }, "scripts": { "analyze": "source-map-explorer 'build/static/js/*.js'", diff --git a/client/src/components/global-search/global-search.component.jsx b/client/src/components/global-search/global-search.component.jsx index 4135f8dc7..ebd4bdd8d 100644 --- a/client/src/components/global-search/global-search.component.jsx +++ b/client/src/components/global-search/global-search.component.jsx @@ -172,8 +172,7 @@ export default function GlobalSearch() { options={options} onSearch={handleSearch} placeholder={t("general.labels.globalsearch")} - > - - + allowClear + > ); } diff --git a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx index a1be3e834..5f63fe12c 100644 --- a/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx +++ b/client/src/components/jobs-documents-gallery/jobs-document-gallery.download.component.jsx @@ -5,45 +5,124 @@ import { useTranslation } from "react-i18next"; import { logImEXEvent } from "../../firebase/firebase.utils"; import cleanAxios from "../../utils/CleanAxios"; import formatBytes from "../../utils/formatbytes"; +import yauzl from "yauzl"; +import { useTreatments } from "@splitsoftware/splitio-react"; -export default function JobsDocumentsDownloadButton({ +import { connect } from "react-redux"; +import { createStructuredSelector } from "reselect"; +import { selectBodyshop } from "../../redux/user/user.selectors"; +const mapStateToProps = createStructuredSelector({ + bodyshop: selectBodyshop, +}); +const mapDispatchToProps = (dispatch) => ({ + //setUserLanguage: language => dispatch(setUserLanguage(language)) +}); +export default connect( + mapStateToProps, + mapDispatchToProps +)(JobsDocumentsDownloadButton); + +export function JobsDocumentsDownloadButton({ + bodyshop, galleryImages, identifier, }) { const { t } = useTranslation(); const [download, setDownload] = useState(null); + const { Direct_Media_Download } = useTreatments( + ["Direct_Media_Download"], + {}, + bodyshop.imexshopid + ); const imagesToDownload = [ ...galleryImages.images.filter((image) => image.isSelected), // ...galleryImages.other.filter((image) => image.isSelected), ]; - const handleDownload = () => { - logImEXEvent("jobs_documents_download"); - axios - .post("/media/download", { - ids: imagesToDownload.map((_) => _.key), - }) - .then((r) => { - // window.open(r.data); - downloadAs( - r.data, - `${identifier || "documents"}.zip`, - (progressEvent) => { - setDownload((currentDownloadState) => { - return { - downloaded: progressEvent.loaded || 0, - speed: - (progressEvent.loaded || 0) - - ((currentDownloadState && currentDownloadState.downloaded) || - 0), - }; - }); - }, - () => setDownload(null) - ); - }); - }; + function downloadProgress(progressEvent) { + setDownload((currentDownloadState) => { + return { + downloaded: progressEvent.loaded || 0, + speed: + (progressEvent.loaded || 0) - + ((currentDownloadState && currentDownloadState.downloaded) || 0), + }; + }); + } + const handleDownload = async () => { + logImEXEvent("jobs_documents_download"); + + const zipUrl = await axios({ + url: "/media/download", + method: "POST", + //responseType: "arraybuffer", // Important + data: { ids: imagesToDownload.map((_) => _.key) }, + }); + + const theDownloadedZip = await cleanAxios({ + url: zipUrl.data, + method: "GET", + responseType: "arraybuffer", + onDownloadProgress: downloadProgress, + }); + setDownload(null); + if (Direct_Media_Download.treatment === "on") { + try { + const parentDir = await window.showDirectoryPicker({ + id: "media", + startIn: "downloads", + }); + + const directory = await parentDir.getDirectoryHandle(identifier, { + create: true, + }); + + yauzl.fromBuffer( + Buffer.from(theDownloadedZip.data), + {}, + (err, zipFile) => { + if (err) throw err; + zipFile.on("entry", (entry) => { + zipFile.openReadStream(entry, async (readErr, readStream) => { + if (readErr) { + zipFile.close(); + throw readErr; + } + if (err) throw err; + let fileSystemHandle = await directory.getFileHandle( + entry.fileName, + { + create: true, + } + ); + const writable = await fileSystemHandle.createWritable(); + readStream.on("data", async function (chunk) { + await writable.write(chunk); + }); + readStream.on("end", async function () { + await writable.close(); + }); + }); + }); + } + ); + } catch (e) { + console.log(e); + standardMediaDownload(theDownloadedZip.data); + } + } else { + standardMediaDownload(theDownloadedZip.data); + } + + function standardMediaDownload(bufferData) { + const a = document.createElement("a"); + const url = window.URL.createObjectURL(new Blob([bufferData])); + a.href = url; + a.download = `${identifier || "documents"}.zip`; + a.click(); + } + }; return ( <>