From 7d82fb8f0433baa61c203efbf4e31841fcb5528a Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Thu, 27 May 2021 20:16:50 -0700
Subject: [PATCH 01/24] Added Crisp scripts.
---
client/src/App/App.container.jsx | 21 ++++++++++++++++++++-
client/src/redux/user/user.sagas.js | 8 ++++++++
2 files changed, 28 insertions(+), 1 deletion(-)
diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx
index 1f5298da2..590e31678 100644
--- a/client/src/App/App.container.jsx
+++ b/client/src/App/App.container.jsx
@@ -3,11 +3,12 @@ import { ConfigProvider } from "antd";
import enLocale from "antd/es/locale/en_US";
import LogRocket from "logrocket";
import moment from "moment";
-import React from "react";
+import React, { useEffect } from "react";
import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component";
import client from "../utils/GraphQLClient";
import App from "./App";
import { useTranslation } from "react-i18next";
+import JiraSupportComponent from "../components/jira-support-widget/jira-support-widget.component";
moment.locale("en-US");
if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
@@ -15,6 +16,23 @@ if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp");
export default function AppContainer() {
const { t } = useTranslation();
+ useEffect(() => {
+ // Include the Crisp code here, without the tags
+ window.$crisp = [];
+ window.CRISP_WEBSITE_ID = "36724f62-2eb0-4b29-9cdd-9905fb99913e";
+
+ var d = document;
+ var s = d.createElement("script");
+
+ s.src = "https://client.crisp.chat/l.js";
+ s.async = 1;
+ d.getElementsByTagName("head")[0].appendChild(s);
+
+ return () => {
+ d.getElementsByTagName("head")[0].removeChild(s);
+ };
+ }, []);
+
return (
+
);
diff --git a/client/src/redux/user/user.sagas.js b/client/src/redux/user/user.sagas.js
index cbeba03af..c467aceed 100644
--- a/client/src/redux/user/user.sagas.js
+++ b/client/src/redux/user/user.sagas.js
@@ -164,6 +164,12 @@ export function* onSignInSuccess() {
export function* signInSuccessSaga({ payload }) {
LogRocket.identify(payload.email);
+ try {
+ window.$crisp.push(["set", "user:email", [payload.email]]);
+ window.$crisp.push(["set", "user:nickname", [payload.displayName]]);
+ } catch (error) {
+ console.log("Error updating Crisp settings.", error);
+ }
// if (!payload.email.includes("@imex.")) yield put(setInstanceId(payload.uid));
analytics.setUserId(payload.email);
@@ -220,6 +226,8 @@ export function* SetAuthLevelFromShopDetails({ payload }) {
try {
const userEmail = yield select((state) => state.user.currentUser.email);
+ window.$crisp.push(["set", "user:company", [payload.shopname]]);
+
const authRecord = payload.associations.filter(
(a) => a.useremail === userEmail
);
From 5da8c77b3a73acda41376e3da4d6f2b0ec30469e Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Thu, 27 May 2021 21:13:36 -0700
Subject: [PATCH 02/24] Added error handling to Crisp.
---
.../error-boundary/error-boundary.component.jsx | 17 +++++++++++++++++
client/src/redux/user/user.sagas.js | 6 +++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/client/src/components/error-boundary/error-boundary.component.jsx b/client/src/components/error-boundary/error-boundary.component.jsx
index cef01e299..0eca73dea 100644
--- a/client/src/components/error-boundary/error-boundary.component.jsx
+++ b/client/src/components/error-boundary/error-boundary.component.jsx
@@ -57,6 +57,23 @@ ${this.state.error.stack}
if (this.state.hasErrored === true) {
logImEXEvent("error_boundary_rendered", { error, info });
+ window.$crisp.push([
+ "set",
+ "session:event",
+ [
+ [
+ [
+ "error_boundary",
+ {
+ error: this.state.error.message,
+ stack: this.state.error.stack,
+ },
+ "red",
+ ],
+ ],
+ ],
+ ]);
+
return (
Date: Fri, 28 May 2021 18:18:09 -0700
Subject: [PATCH 03/24] WIP Photo Editor
---
bodyshop_translations.babel | 26 ++++++
client/package.json | 1 +
client/src/App/App.jsx | 8 ++
.../document-editor.component.jsx | 93 +++++++++++++++++++
.../document-editor.container.jsx | 33 +++++++
.../documents-upload.utility.js | 6 +-
.../job-documents.utility.js | 14 +++
.../jobs-documents-gallery.component.jsx | 28 +-----
client/src/graphql/documents.queries.js | 15 +++
client/src/translations/en_us/common.json | 3 +
client/src/translations/es/common.json | 3 +
client/src/translations/fr/common.json | 3 +
client/yarn.lock | 5 +
13 files changed, 213 insertions(+), 25 deletions(-)
create mode 100644 client/src/components/document-editor/document-editor.component.jsx
create mode 100644 client/src/components/document-editor/document-editor.container.jsx
create mode 100644 client/src/components/jobs-documents-gallery/job-documents.utility.js
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index abc4f8118..57326a1e9 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -12377,6 +12377,32 @@
+
+ errors
+
+
+ notfound
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
+
+
itemtypes
diff --git a/client/package.json b/client/package.json
index 57f1b5afd..d7d61881b 100644
--- a/client/package.json
+++ b/client/package.json
@@ -29,6 +29,7 @@
"jsreport-browser-client-dist": "^1.3.0",
"libphonenumber-js": "^1.9.17",
"logrocket": "^1.2.0",
+ "markerjs2": "^2.8.1",
"moment-business-days": "^1.2.0",
"phone": "^2.4.21",
"preval.macro": "^5.0.0",
diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx
index 89d96e27c..cbf096f8f 100644
--- a/client/src/App/App.jsx
+++ b/client/src/App/App.jsx
@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { Route, Switch } from "react-router-dom";
import { createStructuredSelector } from "reselect";
+import DocumentEditorContainer from "../components/document-editor/document-editor.container";
import ErrorBoundary from "../components/error-boundary/error-boundary.component";
//Component Imports
import LoadingSpinner from "../components/loading-spinner/loading-spinner.component";
@@ -118,6 +119,13 @@ export function App({ checkUserSession, currentUser, online, setOnline }) {
component={TechPageContainer}
/>
+
+
+
);
diff --git a/client/src/components/document-editor/document-editor.component.jsx b/client/src/components/document-editor/document-editor.component.jsx
new file mode 100644
index 000000000..ba5748d32
--- /dev/null
+++ b/client/src/components/document-editor/document-editor.component.jsx
@@ -0,0 +1,93 @@
+//import "tui-image-editor/dist/tui-image-editor.css";
+import { Spin } from "antd";
+import * as markerjs2 from "markerjs2";
+import React, { useEffect, useRef } from "react";
+import { useState } from "react";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import {
+ selectBodyshop,
+ selectCurrentUser,
+} from "../../redux/user/user.selectors";
+import { handleUpload } from "../documents-upload/documents-upload.utility";
+import { GenerateSrcUrl } from "../jobs-documents-gallery/job-documents.utility";
+
+const mapStateToProps = createStructuredSelector({
+ currentUser: selectCurrentUser,
+ bodyshop: selectBodyshop,
+});
+const mapDispatchToProps = (dispatch) => ({
+ //setUserLanguage: language => dispatch(setUserLanguage(language))
+});
+
+export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
+ const imgRef = useRef(null);
+ const [loading, setLoading] = useState(false);
+ const markerArea = useRef(null);
+ const triggerUpload = async (dataUrl) => {
+ setLoading(true);
+ handleUpload(
+ {
+ filename: `${document.key.split("/").pop()}-${Date.now()}.jpg`,
+ file: await b64toBlob(dataUrl),
+ onSuccess: () => setLoading(false),
+ onError: () => setLoading(false),
+ },
+ {
+ bodyshop: bodyshop,
+ uploaded_by: currentUser.email,
+ jobId: document.jobid,
+ //billId: billId,
+ tagsArray: ["edited"],
+ //callback: callbackAfterUpload,
+ }
+ );
+ };
+
+ useEffect(() => {
+ if (imgRef.current !== null) {
+ // create a marker.js MarkerArea
+ markerArea.current = new markerjs2.MarkerArea(imgRef.current);
+ // attach an event handler to assign annotated image back to our image element
+ markerArea.current.addCloseEventListener((closeEvent) => {
+ console.log("Close Event", closeEvent);
+ });
+
+ markerArea.current.addRenderEventListener((dataUrl) => {
+ triggerUpload(dataUrl);
+ });
+ // launch marker.js
+
+ markerArea.current.renderAtNaturalSize = true;
+ markerArea.current.renderImageType = "image/jpeg";
+ markerArea.current.renderImageQuality = 1;
+ //markerArea.current.settings.displayMode = "inline";
+ markerArea.current.show();
+ }
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ }, [imgRef.current, triggerUpload]);
+
+ async function b64toBlob(url) {
+ const res = await fetch(url);
+ return await res.blob();
+ }
+
+ return (
+
+
+
+
+
+ );
+}
+
+export default connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(DocumentEditorComponent);
diff --git a/client/src/components/document-editor/document-editor.container.jsx b/client/src/components/document-editor/document-editor.container.jsx
new file mode 100644
index 000000000..7e19b98d4
--- /dev/null
+++ b/client/src/components/document-editor/document-editor.container.jsx
@@ -0,0 +1,33 @@
+import { useQuery } from "@apollo/client";
+import { Modal, Result } from "antd";
+import queryString from "query-string";
+import React from "react";
+import { useLocation } from "react-router";
+import { GET_DOCUMENT_BY_PK } from "../../graphql/documents.queries";
+import AlertComponent from "../alert/alert.component";
+import LoadingSpinner from "../loading-spinner/loading-spinner.component";
+import DocumentEditor from "./document-editor.component";
+import { useTranslation } from "react-i18next";
+
+export default function DocumentEditorContainer() {
+ //Get the image details for the image to be saved.
+ //Get the document id from the search string.
+ const { documentId } = queryString.parse(useLocation().search);
+ const { t } = useTranslation();
+
+ const { loading, error, data } = useQuery(GET_DOCUMENT_BY_PK, {
+ variables: { documentId },
+ skip: !documentId,
+ });
+
+ if (loading) return ;
+ if (error) return ;
+
+ if (!data.documents_by_pk)
+ return ;
+ return (
+
+
+
+ );
+}
diff --git a/client/src/components/documents-upload/documents-upload.utility.js b/client/src/components/documents-upload/documents-upload.utility.js
index 5856d985e..72893ef88 100644
--- a/client/src/components/documents-upload/documents-upload.utility.js
+++ b/client/src/components/documents-upload/documents-upload.utility.js
@@ -21,8 +21,10 @@ export const handleUpload = (ev, context) => {
const { onError, onSuccess, onProgress } = ev;
const { bodyshop, jobId } = context;
- let key = `${bodyshop.id}/${jobId}/${ev.file.name.replace(/\.[^/.]+$/, "")}`;
- let extension = ev.file.name.split(".").pop();
+ const fileName = ev.file.name || ev.filename;
+
+ let key = `${bodyshop.id}/${jobId}/${fileName.replace(/\.[^/.]+$/, "")}`;
+ let extension = fileName.split(".").pop();
uploadToCloudinary(
key,
extension,
diff --git a/client/src/components/jobs-documents-gallery/job-documents.utility.js b/client/src/components/jobs-documents-gallery/job-documents.utility.js
new file mode 100644
index 000000000..8dde8cc66
--- /dev/null
+++ b/client/src/components/jobs-documents-gallery/job-documents.utility.js
@@ -0,0 +1,14 @@
+import { DetermineFileType } from "../documents-upload/documents-upload.utility";
+
+export const GenerateSrcUrl = (value) => {
+ return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
+ value.type
+ )}/upload/${value.key}${value.extension ? `.${value.extension}` : ""}`;
+};
+
+export const GenerateThumbUrl = (value) =>
+ `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
+ value.type
+ )}/upload/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${
+ value.key
+ }`;
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
index e4c3d0eba..ed27f08cb 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
@@ -5,6 +5,7 @@ import Gallery from "react-grid-gallery";
import { useTranslation } from "react-i18next";
import DocumentsUploadComponent from "../documents-upload/documents-upload.component";
import { DetermineFileType } from "../documents-upload/documents-upload.utility";
+import { GenerateSrcUrl, GenerateThumbUrl } from "./job-documents.utility";
import JobsDocumentsDownloadButton from "./jobs-document-gallery.download.component";
import JobsDocumentsGalleryReassign from "./jobs-document-gallery.reassign.component";
import JobsDocumentsDeleteButton from "./jobs-documents-gallery.delete.component";
@@ -29,16 +30,8 @@ function JobsDocumentsComponent({
const fileType = DetermineFileType(value.type);
if (value.type.startsWith("image")) {
acc.images.push({
- src: `${
- process.env.REACT_APP_CLOUDINARY_ENDPOINT
- }/${DetermineFileType(value.type)}/upload/${value.key}${
- value.extension ? `.${value.extension}` : ""
- }`,
- thumbnail: `${
- process.env.REACT_APP_CLOUDINARY_ENDPOINT
- }/${DetermineFileType(value.type)}/upload/${
- process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
- }/${value.key}`,
+ src: GenerateSrcUrl(value),
+ thumbnail: GenerateThumbUrl(value),
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
@@ -52,28 +45,17 @@ function JobsDocumentsComponent({
} else {
let thumb;
switch (fileType) {
- case "video":
- thumb = `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${fileType}/upload/${process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${value.key}`;
- break;
case "raw":
thumb = `${window.location.origin}/file.png`;
break;
default:
- thumb = `${
- process.env.REACT_APP_CLOUDINARY_ENDPOINT
- }/${fileType}/upload/${
- process.env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
- }/${value.key}${value.extension ? `.${value.extension}` : ""}`;
+ thumb = GenerateThumbUrl(value);
break;
}
const fileName = value.key.split("/").pop();
acc.other.push({
- src: `${
- process.env.REACT_APP_CLOUDINARY_ENDPOINT
- }/${fileType}/upload/${value.key}${
- value.extension ? `.${value.extension}` : ""
- }`,
+ src: GenerateSrcUrl(value),
thumbnail: thumb,
tags: [
{
diff --git a/client/src/graphql/documents.queries.js b/client/src/graphql/documents.queries.js
index d0c11f914..f9cc8877b 100644
--- a/client/src/graphql/documents.queries.js
+++ b/client/src/graphql/documents.queries.js
@@ -1,5 +1,20 @@
import { gql } from "@apollo/client";
+export const GET_DOCUMENT_BY_PK = gql`
+ query GET_DOCUMENT_BY_PK($documentId: uuid!) {
+ documents_by_pk(id: $documentId) {
+ id
+ name
+ key
+ type
+ size
+ takenat
+ extension
+ jobid
+ }
+ }
+`;
+
export const GET_DOCUMENTS_BY_JOB = gql`
query GET_DOCUMENTS_BY_JOB($jobId: uuid!) {
jobs_by_pk(id: $jobId) {
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 164bdd128..e2ffadc03 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -792,6 +792,9 @@
"submitticket": "Submit a Support Ticket",
"view": "View"
},
+ "errors": {
+ "notfound": "No record was found."
+ },
"itemtypes": {
"contract": "CC Contract",
"courtesycar": "Courtesy Car",
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 4fae2a134..606c03ce3 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -792,6 +792,9 @@
"submitticket": "",
"view": ""
},
+ "errors": {
+ "notfound": ""
+ },
"itemtypes": {
"contract": "",
"courtesycar": "",
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index 63fde29b6..f7ee47e50 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -792,6 +792,9 @@
"submitticket": "",
"view": ""
},
+ "errors": {
+ "notfound": ""
+ },
"itemtypes": {
"contract": "",
"courtesycar": "",
diff --git a/client/yarn.lock b/client/yarn.lock
index e6fdbac30..2283b5afb 100644
--- a/client/yarn.lock
+++ b/client/yarn.lock
@@ -8302,6 +8302,11 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
+markerjs2@^2.8.1:
+ version "2.8.1"
+ resolved "https://registry.yarnpkg.com/markerjs2/-/markerjs2-2.8.1.tgz#33c455cc1edd8fa9a5e5b39ed782dcd1b923c917"
+ integrity sha512-M9AflvjOD5aIcBM0HZWW6u1h/NRdzfq73B9ILv1YehF88PeF0tYT5HIsi9PaSJ6EUOR/vWysZN08f3EyDCJixw==
+
material-colors@^1.2.1:
version "1.2.6"
resolved "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz"
From c28d4c15a09d144617bce1d076f78aba5ed0e242 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 31 May 2021 10:45:06 -0700
Subject: [PATCH 04/24] IO-1144 Image Editor Changes.
---
bodyshop_translations.babel | 42 +++++++++++
.../document-editor.component.jsx | 70 ++++++++++++-------
.../document-editor.container.jsx | 40 +++++++++--
.../jobs-documents-gallery.component.jsx | 47 ++++++++++++-
client/src/translations/en_us/common.json | 4 +-
client/src/translations/es/common.json | 2 +
client/src/translations/fr/common.json | 2 +
7 files changed, 172 insertions(+), 35 deletions(-)
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index 57326a1e9..b4512fbe2 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -11040,6 +11040,27 @@
+
+ uploading
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
usage
false
@@ -11087,6 +11108,27 @@
+
+ edituploaded
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
insert
false
diff --git a/client/src/components/document-editor/document-editor.component.jsx b/client/src/components/document-editor/document-editor.component.jsx
index ba5748d32..cb12c1aec 100644
--- a/client/src/components/document-editor/document-editor.component.jsx
+++ b/client/src/components/document-editor/document-editor.component.jsx
@@ -1,8 +1,8 @@
//import "tui-image-editor/dist/tui-image-editor.css";
-import { Spin } from "antd";
+import { Result } from "antd";
import * as markerjs2 from "markerjs2";
-import React, { useEffect, useRef } from "react";
-import { useState } from "react";
+import React, { useCallback, useEffect, useRef, useState } from "react";
+import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import {
@@ -11,6 +11,7 @@ import {
} from "../../redux/user/user.selectors";
import { handleUpload } from "../documents-upload/documents-upload.utility";
import { GenerateSrcUrl } from "../jobs-documents-gallery/job-documents.utility";
+import LoadingSpinner from "../loading-spinner/loading-spinner.component";
const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser,
@@ -23,37 +24,49 @@ const mapDispatchToProps = (dispatch) => ({
export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
const imgRef = useRef(null);
const [loading, setLoading] = useState(false);
+ const [uploaded, setuploaded] = useState(false);
const markerArea = useRef(null);
- const triggerUpload = async (dataUrl) => {
- setLoading(true);
- handleUpload(
- {
- filename: `${document.key.split("/").pop()}-${Date.now()}.jpg`,
- file: await b64toBlob(dataUrl),
- onSuccess: () => setLoading(false),
- onError: () => setLoading(false),
- },
- {
- bodyshop: bodyshop,
- uploaded_by: currentUser.email,
- jobId: document.jobid,
- //billId: billId,
- tagsArray: ["edited"],
- //callback: callbackAfterUpload,
- }
- );
- };
+ const { t } = useTranslation();
+
+ const triggerUpload = useCallback(
+ async (dataUrl) => {
+ setLoading(true);
+ handleUpload(
+ {
+ filename: `${document.key.split("/").pop()}-${Date.now()}.jpg`,
+ file: await b64toBlob(dataUrl),
+ onSuccess: () => {
+ setLoading(false);
+ setuploaded(true);
+ },
+ onError: () => setLoading(false),
+ },
+ {
+ bodyshop: bodyshop,
+ uploaded_by: currentUser.email,
+ jobId: document.jobid,
+ //billId: billId,
+ tagsArray: ["edited"],
+ //callback: callbackAfterUpload,
+ }
+ );
+ },
+ [bodyshop, currentUser, document]
+ );
useEffect(() => {
if (imgRef.current !== null) {
// create a marker.js MarkerArea
markerArea.current = new markerjs2.MarkerArea(imgRef.current);
+ console.log(`markerArea.current`, markerArea.current);
// attach an event handler to assign annotated image back to our image element
markerArea.current.addCloseEventListener((closeEvent) => {
console.log("Close Event", closeEvent);
});
markerArea.current.addRenderEventListener((dataUrl) => {
+ imgRef.current.src = dataUrl;
+ markerArea.current.close();
triggerUpload(dataUrl);
});
// launch marker.js
@@ -65,7 +78,7 @@ export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
markerArea.current.show();
}
// eslint-disable-next-line react-hooks/exhaustive-deps
- }, [imgRef.current, triggerUpload]);
+ }, [triggerUpload]);
async function b64toBlob(url) {
const res = await fetch(url);
@@ -74,7 +87,7 @@ export function DocumentEditorComponent({ currentUser, bodyshop, document }) {
return (
-
+ {!loading && !uploaded && (
-
+ )}
+ {loading &&
}
+ {uploaded && (
+
+ )}
);
}
diff --git a/client/src/components/document-editor/document-editor.container.jsx b/client/src/components/document-editor/document-editor.container.jsx
index 7e19b98d4..3819f27f8 100644
--- a/client/src/components/document-editor/document-editor.container.jsx
+++ b/client/src/components/document-editor/document-editor.container.jsx
@@ -1,29 +1,55 @@
import { useQuery } from "@apollo/client";
-import { Modal, Result } from "antd";
+import { Result } from "antd";
import queryString from "query-string";
-import React from "react";
+import React, { useEffect } from "react";
+import { useTranslation } from "react-i18next";
+import { connect } from "react-redux";
import { useLocation } from "react-router";
+import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
import { GET_DOCUMENT_BY_PK } from "../../graphql/documents.queries";
+import { setBodyshop } from "../../redux/user/user.actions";
import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import DocumentEditor from "./document-editor.component";
-import { useTranslation } from "react-i18next";
-export default function DocumentEditorContainer() {
+const mapDispatchToProps = (dispatch) => ({
+ setBodyshop: (bs) => dispatch(setBodyshop(bs)),
+});
+
+export default connect(null, mapDispatchToProps)(DocumentEditorContainer);
+
+export function DocumentEditorContainer({ setBodyshop }) {
//Get the image details for the image to be saved.
//Get the document id from the search string.
const { documentId } = queryString.parse(useLocation().search);
const { t } = useTranslation();
+ const {
+ loading: loadingShop,
+ error: errorShop,
+ data: dataShop,
+ } = useQuery(QUERY_BODYSHOP, {
+ fetchPolicy: "network-only",
+ });
+
+ useEffect(() => {
+ if (dataShop) setBodyshop(dataShop.bodyshops[0]);
+ }, [dataShop, setBodyshop]);
const { loading, error, data } = useQuery(GET_DOCUMENT_BY_PK, {
variables: { documentId },
skip: !documentId,
});
- if (loading) return ;
- if (error) return ;
+ if (loading || loadingShop) return ;
+ if (error || errorShop)
+ return (
+
+ );
- if (!data.documents_by_pk)
+ if (!data || !data.documents_by_pk)
return ;
return (
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
index ed27f08cb..c975388f2 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
@@ -1,5 +1,5 @@
-import { FileExcelFilled } from "@ant-design/icons";
-import { Card, Col, Row, Space } from "antd";
+import { FileExcelFilled, EditFilled, SyncOutlined } from "@ant-design/icons";
+import { Card, Col, Row, Space, Button } from "antd";
import React, { useEffect, useState } from "react";
import Gallery from "react-grid-gallery";
import { useTranslation } from "react-i18next";
@@ -23,6 +23,25 @@ function JobsDocumentsComponent({
}) {
const [galleryImages, setgalleryImages] = useState({ images: [], other: [] });
const { t } = useTranslation();
+ const [index, setIndex] = useState(0);
+
+ const onCurrentImageChange = (index) => {
+ setIndex(index);
+ };
+
+ useEffect(() => {
+ console.log("Added event listening for reteching.");
+ window.addEventListener("storage", (ev) => {
+ if (ev.key === "refetch" && ev.newValue === true) {
+ refetch && refetch();
+ localStorage.setItem("refetch", false);
+ }
+ });
+
+ return () => {
+ window.removeEventListener("storage");
+ };
+ }, [refetch]);
useEffect(() => {
let documents = data.reduce(
@@ -101,6 +120,9 @@ function JobsDocumentsComponent({
+
{
+ console.log(`Clicked`);
+ const newWindow = window.open(
+ `${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`,
+ "_blank",
+ "noopener,noreferrer"
+ );
+ if (newWindow) newWindow.opener = null;
+ }}
+ >
+
+ ,
+ ]}
onClickImage={(props) => {
window.open(
props.target.src,
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index e2ffadc03..c2f2d2791 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -6,7 +6,7 @@
},
"errors": {
"deleting": "Error encountered while deleting allocation. {{message}}",
- "saving": "Error while allocating. {{message}}",
+ "saving": "Error while allocating. {{message}}",
"validation": "Please ensure all fields are entered correctly. "
},
"fields": {
@@ -701,10 +701,12 @@
"upload": "Upload",
"upload_limitexceeded": "Uploading all selected documents will exceed the job storage limit for your shop. ",
"upload_limitexceeded_title": "Unable to upload document(s)",
+ "uploading": "Uploading...",
"usage": "of job storage used. ({{used}} / {{total}})"
},
"successes": {
"delete": "Document(s) deleted successfully.",
+ "edituploaded": "Edited document uploaded successfully. Please close this window and refresh the documents list.",
"insert": "Uploaded document successfully. ",
"updated": "Document updated successfully. "
}
diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json
index 606c03ce3..5cba0da9a 100644
--- a/client/src/translations/es/common.json
+++ b/client/src/translations/es/common.json
@@ -701,10 +701,12 @@
"upload": "Subir",
"upload_limitexceeded": "",
"upload_limitexceeded_title": "",
+ "uploading": "",
"usage": ""
},
"successes": {
"delete": "Documento eliminado con éxito.",
+ "edituploaded": "",
"insert": "Documento cargado con éxito.",
"updated": ""
}
diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json
index f7ee47e50..c480fc6cb 100644
--- a/client/src/translations/fr/common.json
+++ b/client/src/translations/fr/common.json
@@ -701,10 +701,12 @@
"upload": "Télécharger",
"upload_limitexceeded": "",
"upload_limitexceeded_title": "",
+ "uploading": "",
"usage": ""
},
"successes": {
"delete": "Le document a bien été supprimé.",
+ "edituploaded": "",
"insert": "Document téléchargé avec succès.",
"updated": ""
}
From af6bb18db225a7b6934d22fd3e843e445990726c Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 31 May 2021 10:50:28 -0700
Subject: [PATCH 05/24] IO-1138 Additional offline check.
---
client/src/App/App.jsx | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx
index cbf096f8f..fbaedfd0a 100644
--- a/client/src/App/App.jsx
+++ b/client/src/App/App.jsx
@@ -40,8 +40,12 @@ const mapDispatchToProps = (dispatch) => ({
export function App({ checkUserSession, currentUser, online, setOnline }) {
useEffect(() => {
+ if (!navigator.onLine) {
+ setOnline(false);
+ }
+
checkUserSession();
- }, [checkUserSession]);
+ }, [checkUserSession, setOnline]);
//const b = Grid.useBreakpoint();
// console.log("Breakpoints:", b);
From afb0c85e9f8437c715aa679e7aa1ea843ad00c9a Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Mon, 31 May 2021 10:56:13 -0700
Subject: [PATCH 06/24] IO-1167 IO-775 Minor bug fixes.
---
.../accounting-payments-table.component.jsx | 13 +++-------
.../job-detail-lines/job-lines.component.jsx | 8 +++++--
.../jobs-documents-gallery.component.jsx | 24 +++++++++----------
3 files changed, 21 insertions(+), 24 deletions(-)
diff --git a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
index 35308356e..f2a72dd92 100644
--- a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
+++ b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
@@ -5,7 +5,7 @@ import { Link } from "react-router-dom";
import { logImEXEvent } from "../../firebase/firebase.utils";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { DateFormatter, DateTimeFormatter } from "../../utils/DateFormatter";
-import { alphaSort } from "../../utils/sorters";
+import { alphaSort, dateSort } from "../../utils/sorters";
import PaymentExportButton from "../payment-export-button/payment-export-button.component";
import PaymentsExportAllButton from "../payments-export-all-button/payments-export-all-button.component";
@@ -41,19 +41,12 @@ export default function AccountingPayablesTableComponent({
title: t("payments.fields.date"),
dataIndex: "date",
key: "date",
- sorter: (a, b) => alphaSort(a.date, b.date),
+ sorter: (a, b) => dateSort(a.date, b.date),
sortOrder:
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
render: (text, record) => {record.date},
},
- {
- title: t("payments.fields.date"),
- dataIndex: "date",
- key: "date",
- sorter: (a, b) => alphaSort(a.date, b.date),
- sortOrder:
- state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
- },
+
{
title: t("jobs.fields.owner"),
dataIndex: "owner",
diff --git a/client/src/components/job-detail-lines/job-lines.component.jsx b/client/src/components/job-detail-lines/job-lines.component.jsx
index cd88da672..67e8381c9 100644
--- a/client/src/components/job-detail-lines/job-lines.component.jsx
+++ b/client/src/components/job-detail-lines/job-lines.component.jsx
@@ -22,6 +22,7 @@ import { createStructuredSelector } from "reselect";
import { DELETE_JOB_LINE_BY_PK } from "../../graphql/jobs-lines.queries";
import { selectJobReadOnly } from "../../redux/application/application.selectors";
import { setModalContext } from "../../redux/modals/modals.actions";
+import { selectTechnician } from "../../redux/tech/tech.selectors";
import { onlyUnique } from "../../utils/arrayHelper";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { alphaSort } from "../../utils/sorters";
@@ -37,6 +38,7 @@ import PartsOrderModalContainer from "../parts-order-modal/parts-order-modal.con
const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser
jobRO: selectJobReadOnly,
+ technician: selectTechnician,
});
const mapDispatchToProps = (dispatch) => ({
@@ -48,6 +50,7 @@ const mapDispatchToProps = (dispatch) => ({
export function JobLinesComponent({
jobRO,
+ technician,
setPartsOrderContext,
loading,
refetch,
@@ -364,7 +367,8 @@ export function JobLinesComponent({
disabled={
(job && !job.converted) ||
(selectedLines.length > 0 ? false : true) ||
- jobRO
+ jobRO ||
+ technician
}
onClick={() => {
setPartsOrderContext({
@@ -399,7 +403,7 @@ export function JobLinesComponent({
);
}
diff --git a/client/src/components/jobs-documents-gallery/job-documents.utility.js b/client/src/components/jobs-documents-gallery/job-documents.utility.js
index 054c51063..49ac4fbef 100644
--- a/client/src/components/jobs-documents-gallery/job-documents.utility.js
+++ b/client/src/components/jobs-documents-gallery/job-documents.utility.js
@@ -2,7 +2,7 @@ import { DetermineFileType } from "../documents-upload/documents-upload.utility"
export const GenerateSrcUrl = (value) => {
let extension = value.extension;
- if (extension && extension.includes("heic")) extension = "jpg";
+ if (extension && extension.toLowerCase().includes("heic")) extension = "jpg";
return `${process.env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
value.type
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
index 4a543401c..2b29a7b3c 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
@@ -166,7 +166,6 @@ function JobsDocumentsComponent({
zIndex: "5",
}}
onClick={() => {
- console.log(`Clicked`);
const newWindow = window.open(
`${window.location.protocol}//${window.location.host}/edit?documentId=${galleryImages.images[index].id}`,
"_blank",
diff --git a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
index 9ae6695e5..436229c0c 100644
--- a/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
+++ b/client/src/components/parts-order-list-table/parts-order-list-table.component.jsx
@@ -237,6 +237,11 @@ export function PartsOrderListTableComponent({
{record.deliver_by}
),
},
+ {
+ title: t("parts_orders.fields.orderedby"),
+ dataIndex: "orderedby",
+ key: "orderedby",
+ },
{
title: t("general.labels.actions"),
dataIndex: "actions",
@@ -336,6 +341,7 @@ export function PartsOrderListTableComponent({
/>
),
},
+
{
title: t("general.labels.actions"),
dataIndex: "actions",
diff --git a/client/src/components/parts-order-modal/parts-order-modal.component.jsx b/client/src/components/parts-order-modal/parts-order-modal.component.jsx
index 81c289d95..03f6d4edd 100644
--- a/client/src/components/parts-order-modal/parts-order-modal.component.jsx
+++ b/client/src/components/parts-order-modal/parts-order-modal.component.jsx
@@ -73,6 +73,7 @@ export default function PartsOrderModalComponent({
Date: Wed, 2 Jun 2021 09:00:18 -0700
Subject: [PATCH 19/24] IO-1116 Notes Multiline display
---
.../job-detail-cards/job-detail-cards.notes.component.jsx | 2 +-
client/src/components/jobs-notes/jobs.notes.component.jsx | 3 +++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/client/src/components/job-detail-cards/job-detail-cards.notes.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.notes.component.jsx
index 39b27c5f6..57fdec9ba 100644
--- a/client/src/components/job-detail-cards/job-detail-cards.notes.component.jsx
+++ b/client/src/components/job-detail-cards/job-detail-cards.notes.component.jsx
@@ -29,7 +29,7 @@ export default function JobDetailCardsNotesComponent({ loading, data }) {
bordered
dataSource={data.notes}
renderItem={(item) => (
-
+
{item.critical ? (
) : null}
diff --git a/client/src/components/jobs-notes/jobs.notes.component.jsx b/client/src/components/jobs-notes/jobs.notes.component.jsx
index e8354b026..2f3459211 100644
--- a/client/src/components/jobs-notes/jobs.notes.component.jsx
+++ b/client/src/components/jobs-notes/jobs.notes.component.jsx
@@ -57,6 +57,9 @@ export function JobNotesComponent({
dataIndex: "text",
key: "text",
ellipsis: true,
+ render: (text, record) => (
+ {text}
+ ),
},
{
From 9d4f98d3ee5213656ed87b7ce9fea544fd8de1fd Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 2 Jun 2021 09:07:29 -0700
Subject: [PATCH 20/24] IO-1167 Resolve sorting on payments table.
---
.../accounting-payments-table.component.jsx | 2 +-
.../job-payments/job-payments.component.jsx | 18 +++++++++---------
client/src/graphql/jobs.queries.js | 1 +
3 files changed, 11 insertions(+), 10 deletions(-)
diff --git a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
index f2a72dd92..94ca9e50b 100644
--- a/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
+++ b/client/src/components/accounting-payments-table/accounting-payments-table.component.jsx
@@ -54,7 +54,7 @@ export default function AccountingPayablesTableComponent({
ellipsis: true,
sorter: (a, b) => alphaSort(a.job.ownr_ln, b.job.ownr_ln),
sortOrder:
- state.sortedInfo.columnKey === "ownr_ln" && state.sortedInfo.order,
+ state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
render: (text, record) => {
return record.job.owner ? (
diff --git a/client/src/components/job-payments/job-payments.component.jsx b/client/src/components/job-payments/job-payments.component.jsx
index eae8bc76e..fd2558492 100644
--- a/client/src/components/job-payments/job-payments.component.jsx
+++ b/client/src/components/job-payments/job-payments.component.jsx
@@ -8,8 +8,8 @@ import { selectJobReadOnly } from "../../redux/application/application.selectors
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
-import { DateTimeFormatter } from "../../utils/DateFormatter";
-import { alphaSort } from "../../utils/sorters";
+import { DateFormatter } from "../../utils/DateFormatter";
+import { alphaSort, dateSort } from "../../utils/sorters";
import { TemplateList } from "../../utils/TemplateConstants";
import DataLabel from "../data-label/data-label.component";
import PrintWrapperComponent from "../print-wrapper/print-wrapper.component";
@@ -40,14 +40,14 @@ export function JobPayments({
});
const columns = [
{
- title: t("payments.fields.created_at"),
- dataIndex: "created_at",
- key: "created_at",
+ title: t("payments.fields.date"),
+ dataIndex: "date",
+ key: "date",
+ sorter: (a, b) => dateSort(a.date, b.date),
+
sortOrder:
- state.sortedInfo.columnKey === "created_at" && state.sortedInfo.order,
- render: (text, record) => (
- {record.created_at}
- ),
+ state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
+ render: (text, record) => {record.date},
},
{
title: t("payments.fields.payer"),
diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js
index 0ae54a202..62ba766cb 100644
--- a/client/src/graphql/jobs.queries.js
+++ b/client/src/graphql/jobs.queries.js
@@ -565,6 +565,7 @@ export const GET_JOB_BY_PK = gql`
stripeid
transactionid
memo
+ date
}
cccontracts {
id
From 9dfff36edf26ab046b81b1446c60264499e0f5e8 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 2 Jun 2021 09:13:42 -0700
Subject: [PATCH 21/24] IO-1174 Adjust bill delete export log FK
---
.../down.yaml | 12 ++++++++++++
.../up.yaml | 10 ++++++++++
2 files changed, 22 insertions(+)
create mode 100644 hasura/migrations/1622650359491_set_fk_public_exportlog_billid/down.yaml
create mode 100644 hasura/migrations/1622650359491_set_fk_public_exportlog_billid/up.yaml
diff --git a/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/down.yaml b/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/down.yaml
new file mode 100644
index 000000000..4cbdba134
--- /dev/null
+++ b/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/down.yaml
@@ -0,0 +1,12 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: |-
+ alter table "public"."exportlog" drop constraint "exportlog_billid_fkey",
+ add constraint "exportlog_billid_fkey"
+ foreign key ("billid")
+ references "public"."bills"
+ ("id")
+ on update restrict
+ on delete restrict;
+ type: run_sql
diff --git a/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/up.yaml b/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/up.yaml
new file mode 100644
index 000000000..34ec41ec8
--- /dev/null
+++ b/hasura/migrations/1622650359491_set_fk_public_exportlog_billid/up.yaml
@@ -0,0 +1,10 @@
+- args:
+ cascade: false
+ read_only: false
+ sql: |-
+ alter table "public"."exportlog" drop constraint "exportlog_billid_fkey",
+ add constraint "exportlog_billid_fkey"
+ foreign key ("billid")
+ references "public"."bills"
+ ("id") on update cascade on delete cascade;
+ type: run_sql
From b897795c2726996f01f4b2e3295373a11b384e16 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 2 Jun 2021 10:08:51 -0700
Subject: [PATCH 22/24] Move MAPA/MASH to parts profit centers
---
server/job/job-costing.js | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/server/job/job-costing.js b/server/job/job-costing.js
index 179b96d4d..e9de9b5ff 100644
--- a/server/job/job-costing.js
+++ b/server/job/job-costing.js
@@ -265,11 +265,11 @@ function GenerateCostingData(job) {
acc.labor[laborProfitCenter].add(laborAmount);
if (val.mod_lbr_ty === "LAR") {
- if (!acc.labor[defaultProfits["MAPA"]])
- acc.labor[defaultProfits["MAPA"]] = Dinero();
+ if (!acc.parts[defaultProfits["MAPA"]])
+ acc.parts[defaultProfits["MAPA"]] = Dinero();
materialsHours.mapaHrs += val.mod_lb_hrs || 0;
- acc.labor[defaultProfits["MAPA"]] = acc.labor[
+ acc.parts[defaultProfits["MAPA"]] = acc.parts[
defaultProfits["MAPA"]
].add(
Dinero({
@@ -277,11 +277,11 @@ function GenerateCostingData(job) {
}).multiply(val.mod_lb_hrs || 0)
);
}
- if (!acc.labor[defaultProfits["MASH"]])
- acc.labor[defaultProfits["MASH"]] = Dinero();
+ if (!acc.parts[defaultProfits["MASH"]])
+ acc.parts[defaultProfits["MASH"]] = Dinero();
if (val.mod_lbr_ty !== "LAR") {
- acc.labor[defaultProfits["MASH"]] = acc.labor[
+ acc.parts[defaultProfits["MASH"]] = acc.parts[
defaultProfits["MASH"]
].add(
Dinero({
@@ -402,6 +402,7 @@ function GenerateCostingData(job) {
}).multiply(materialsHours.mapaHrs)
);
}
+
if (job.bodyshop.jc_hourly_rates && job.bodyshop.jc_hourly_rates.mash) {
if (
!billTotalsByCostCenters[
From 8427ea208bc65b40666fed85bf56b68ee0eb4145 Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 2 Jun 2021 10:48:01 -0700
Subject: [PATCH 23/24] IO-1169 Download only images.
---
.../jobs-document-gallery.download.component.jsx | 10 +++-------
.../jobs-documents-gallery.component.jsx | 7 +++++--
client/src/translations/en_us/common.json | 2 +-
3 files changed, 9 insertions(+), 10 deletions(-)
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 b172e0806..a1be3e834 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
@@ -14,11 +14,11 @@ export default function JobsDocumentsDownloadButton({
const [download, setDownload] = useState(null);
const imagesToDownload = [
...galleryImages.images.filter((image) => image.isSelected),
- ...galleryImages.other.filter((image) => image.isSelected),
+ // ...galleryImages.other.filter((image) => image.isSelected),
];
+
const handleDownload = () => {
logImEXEvent("jobs_documents_download");
-
axios
.post("/media/download", {
ids: imagesToDownload.map((_) => _.key),
@@ -27,12 +27,8 @@ export default function JobsDocumentsDownloadButton({
// window.open(r.data);
downloadAs(
r.data,
- `${identifier || "images"}.zip`,
+ `${identifier || "documents"}.zip`,
(progressEvent) => {
- const percentage = Math.round(
- (progressEvent.loaded * 100) / progressEvent.total
- );
- console.log(progressEvent, percentage);
setDownload((currentDownloadState) => {
return {
downloaded: progressEvent.loaded || 0,
diff --git a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
index 2b29a7b3c..500874293 100644
--- a/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
+++ b/client/src/components/jobs-documents-gallery/jobs-documents-gallery.component.jsx
@@ -56,6 +56,7 @@ function JobsDocumentsComponent({
isSelected: false,
key: value.key,
extension: value.extension,
+
id: value.id,
type: value.type,
size: value.size,
@@ -74,7 +75,8 @@ function JobsDocumentsComponent({
const fileName = value.key.split("/").pop();
acc.other.push({
- src: GenerateSrcUrl(value),
+ source: GenerateSrcUrl(value),
+ src: "",
thumbnail: thumb,
tags: [
{
@@ -100,6 +102,7 @@ function JobsDocumentsComponent({
thumbnailHeight: 225,
thumbnailWidth: 225,
isSelected: false,
+
extension: value.extension,
key: value.key,
id: value.id,
@@ -211,7 +214,7 @@ function JobsDocumentsComponent({
}}
onClickThumbnail={(index) => {
window.open(
- galleryImages.other[index].src,
+ galleryImages.other[index].source,
"_blank",
"toolbar=0,location=0,menubar=0"
);
diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json
index 999241966..c2da016f2 100644
--- a/client/src/translations/en_us/common.json
+++ b/client/src/translations/en_us/common.json
@@ -677,7 +677,7 @@
"documents": {
"actions": {
"delete": "Delete Selected Documents",
- "download": "Download Selected Documents",
+ "download": "Download Selected Images",
"reassign": "Reassign to another Job",
"selectallimages": "Select All Images",
"selectallotherdocuments": "Select All Other Documents"
From 786d76bb73e72c83d9c0228e1a71e2a05c65a31a Mon Sep 17 00:00:00 2001
From: Patrick Fic <>
Date: Wed, 2 Jun 2021 13:00:38 -0700
Subject: [PATCH 24/24] Upload documents with unique time stamp.
---
bodyshop_translations.babel | 21 +++++++++++++++++++
.../documents-upload.utility.js | 5 ++++-
.../components/header/header.component.jsx | 10 +++++++++
client/src/translations/en_us/common.json | 1 +
client/src/translations/es/common.json | 1 +
client/src/translations/fr/common.json | 1 +
6 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel
index afae10463..96ddb91b6 100644
--- a/bodyshop_translations.babel
+++ b/bodyshop_translations.babel
@@ -24030,6 +24030,27 @@
+
+ help
+ false
+
+
+
+
+
+ en-US
+ false
+
+
+ es-MX
+ false
+
+
+ fr-CA
+ false
+
+
+
home
false
diff --git a/client/src/components/documents-upload/documents-upload.utility.js b/client/src/components/documents-upload/documents-upload.utility.js
index 72893ef88..abc0315f1 100644
--- a/client/src/components/documents-upload/documents-upload.utility.js
+++ b/client/src/components/documents-upload/documents-upload.utility.js
@@ -23,7 +23,10 @@ export const handleUpload = (ev, context) => {
const fileName = ev.file.name || ev.filename;
- let key = `${bodyshop.id}/${jobId}/${fileName.replace(/\.[^/.]+$/, "")}`;
+ let key = `${bodyshop.id}/${jobId}/${fileName.replace(
+ /\.[^/.]+$/,
+ ""
+ )}-${new Date().getTime()}`;
let extension = fileName.split(".").pop();
uploadToCloudinary(
key,
diff --git a/client/src/components/header/header.component.jsx b/client/src/components/header/header.component.jsx
index 33dc0f069..c361a93a3 100644
--- a/client/src/components/header/header.component.jsx
+++ b/client/src/components/header/header.component.jsx
@@ -20,6 +20,7 @@ import Icon, {
ToolFilled,
UnorderedListOutlined,
UserOutlined,
+ QuestionCircleFilled,
} from "@ant-design/icons";
import { Layout, Menu } from "antd";
import React from "react";
@@ -284,6 +285,15 @@ function Header({
{t("menus.header.shop_csi")}
+ {
+ window.open("https://help.imex.online/", "_blank");
+ }}
+ icon={}
+ >
+ {t("menus.header.help")}
+