diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index a354ac876..1421c9116 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -33533,6 +33533,27 @@ + + removefrompartsqueue + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + returnpartsorder false @@ -44249,6 +44270,27 @@ + + notes + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + plate_no false diff --git a/client/package.json b/client/package.json index 216bf52b7..75a510373 100644 --- a/client/package.json +++ b/client/package.json @@ -4,54 +4,54 @@ "private": true, "proxy": "http://localhost:4000", "dependencies": { - "@apollo/client": "^3.5.10", + "@apollo/client": "^3.6.2", "@asseinfo/react-kanban": "^2.2.0", "@craco/craco": "^6.4.3", "@fingerprintjs/fingerprintjs": "^3.3.3", - "@sentry/react": "^6.19.6", - "@sentry/tracing": "^6.19.6", - "@splitsoftware/splitio-react": "^1.4.0", - "@stripe/react-stripe-js": "^1.7.1", - "@stripe/stripe-js": "^1.27.0", - "@tanem/react-nprogress": "^4.0.12", - "antd": "^4.19.5", + "@sentry/react": "^6.19.7", + "@sentry/tracing": "^6.19.7", + "@splitsoftware/splitio-react": "^1.4.1", + "@stripe/react-stripe-js": "^1.8.0", + "@stripe/stripe-js": "^1.29.0", + "@tanem/react-nprogress": "^5.0.0", + "antd": "^4.20.5", "apollo-link-logger": "^2.0.0", - "axios": "^0.26.1", + "axios": "^0.27.2", "craco-less": "^1.20.0", "dinero.js": "^1.9.1", - "dotenv": "^16.0.0", + "dotenv": "^16.0.1", "enquire-js": "^0.2.1", "env-cmd": "^10.1.0", "exifr": "^7.1.3", - "firebase": "^9.6.11", - "graphql": "^16.3.0", - "i18next": "^21.6.16", + "firebase": "^9.8.1", + "graphql": "^16.5.0", + "i18next": "^21.8.2", "i18next-browser-languagedetector": "^6.1.4", "jsoneditor": "^9.7.4", "jsreport-browser-client-dist": "^1.3.0", - "libphonenumber-js": "^1.9.51", - "logrocket": "^2.2.1", - "markerjs2": "^2.21.1", + "libphonenumber-js": "^1.9.53", + "logrocket": "^3.0.0", + "markerjs2": "^2.21.4", "moment-business-days": "^1.2.0", "moment-timezone": "^0.5.34", "normalize-url": "^7.0.3", - "phone": "^3.1.15", + "phone": "^3.1.17", "preval.macro": "^5.0.0", "prop-types": "^15.8.1", "query-string": "^7.1.1", "rc-queue-anim": "^2.0.0", "rc-scroll-anim": "^2.7.6", "react": "^17.0.2", - "react-big-calendar": "^0.38.2", + "react-big-calendar": "^0.40.1", "react-color": "^2.19.3", "react-cookie": "^4.1.1", "react-dom": "^17.0.2", - "react-drag-listview": "^0.1.9", + "react-drag-listview": "^0.2.0", "react-grid-gallery": "^0.5.5", "react-grid-layout": "^1.3.4", - "react-i18next": "^11.16.6", + "react-i18next": "^11.16.9", "react-icons": "^4.3.1", - "react-number-format": "^4.9.1", + "react-number-format": "^4.9.3", "react-redux": "^7.2.8", "react-resizable": "^3.0.4", "react-router-dom": "^5.3.0", @@ -60,28 +60,28 @@ "react-sublime-video": "^0.2.5", "react-virtualized": "^9.22.3", "recharts": "^2.1.9", - "redux": "^4.1.2", + "redux": "^4.2.0", "redux-persist": "^6.0.0", "redux-saga": "^1.1.3", "redux-state-sync": "^3.1.2", "reselect": "^4.1.5", - "sass": "^1.50.0", - "socket.io-client": "^4.4.1", + "sass": "^1.51.0", + "socket.io-client": "^4.5.0", "styled-components": "^5.3.5", "subscriptions-transport-ws": "^0.11.0", "web-vitals": "^2.1.4", - "workbox-background-sync": "^6.5.2", - "workbox-broadcast-update": "^6.5.2", - "workbox-cacheable-response": "^6.5.2", - "workbox-core": "^6.5.2", - "workbox-expiration": "^6.5.2", - "workbox-google-analytics": "^6.5.2", - "workbox-navigation-preload": "^6.5.2", - "workbox-precaching": "^6.5.2", - "workbox-range-requests": "^6.5.2", - "workbox-routing": "^6.5.2", - "workbox-strategies": "^6.5.2", - "workbox-streams": "^6.5.2", + "workbox-background-sync": "^6.5.3", + "workbox-broadcast-update": "^6.5.3", + "workbox-cacheable-response": "^6.5.3", + "workbox-core": "^6.5.3", + "workbox-expiration": "^6.5.3", + "workbox-google-analytics": "^6.5.3", + "workbox-navigation-preload": "^6.5.3", + "workbox-precaching": "^6.5.3", + "workbox-range-requests": "^6.5.3", + "workbox-routing": "^6.5.3", + "workbox-strategies": "^6.5.3", + "workbox-streams": "^6.5.3", "yauzl": "^2.10.0" }, "scripts": { @@ -118,11 +118,11 @@ "react-error-overlay": "6.0.9" }, "devDependencies": { - "@sentry/webpack-plugin": "^1.18.8", + "@sentry/webpack-plugin": "^1.18.9", "@testing-library/cypress": "^8.0.2", - "cypress": "^9.5.3", + "cypress": "^9.6.1", "eslint-plugin-cypress": "^2.12.1", - "react-error-overlay": "6.0.10", + "react-error-overlay": "6.0.11", "redux-logger": "^3.0.6", "source-map-explorer": "^2.5.2" } diff --git a/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx b/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx index 998f74125..ee684994b 100644 --- a/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx +++ b/client/src/components/jobs-detail-change-filehandler/jobs-detail-change-filehandler.component.jsx @@ -16,15 +16,18 @@ export function JobsDetailChangeFilehandler({ disabled, form, bodyshop }) { }; const menu = ( -
- - {bodyshop.md_filehandlers.map((est, idx) => ( - - {`${est.ins_ct_fn} ${est.ins_ct_ln}`} - - ))} - -
+ + {bodyshop.md_filehandlers.map((est, idx) => ( + + {`${est.ins_ct_fn} ${est.ins_ct_ln}`} + + ))} + ); return ( diff --git a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx index 7f5847f2c..763246908 100644 --- a/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx +++ b/client/src/components/jobs-detail-header/jobs-detail-header.component.jsx @@ -216,6 +216,22 @@ export function JobsDetailHeader({ job, bodyshop, disabled }) { + {job.vehicle && job.vehicle.notes && ( + + {job.vehicle.notes} + + )} + { + // job.vehicle && job.vehicle.v_paint_codes && ( + // + // + // {Object.keys(job.vehicle.v_paint_codes).map((key, idx) => ( + // {job.vehicle.v_paint_codes[key]} + // ))} + // + // + // ) + } diff --git a/client/src/components/jobs-notes/jobs-notes.container.jsx b/client/src/components/jobs-notes/jobs-notes.container.jsx index 2fbf5e965..f62a219cb 100644 --- a/client/src/components/jobs-notes/jobs-notes.container.jsx +++ b/client/src/components/jobs-notes/jobs-notes.container.jsx @@ -61,7 +61,9 @@ export function JobNotesContainer({ jobId, insertAuditTrail }) { jobId={jobId} loading={loading} data={data ? data.jobs_by_pk.notes : null} - relatedRos={data ? data.jobs_by_pk.vehicle.jobs : null} + relatedRos={ + data ? data.jobs_by_pk.vehicle && data.jobs_by_pk.vehicle.jobs : null + } refetch={refetch} deleteLoading={deleteLoading} handleNoteDelete={handleNoteDelete} diff --git a/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx index 6d29589a5..a5ff684f7 100644 --- a/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx +++ b/client/src/components/note-upsert-modal/note-upsert-modal.container.jsx @@ -72,13 +72,9 @@ export function NoteUpsertModalContainer({ toggleModalVisible(); } else { logImEXEvent("job_note_insert"); - const AdditionalNoteInserts = Object.keys(relatedros).filter( - (key) => relatedros[key] - ); - console.log( - "🚀 ~ file: note-upsert-modal.container.jsx ~ line 78 ~ handleFinish ~ AdditionalNoteInserts", - AdditionalNoteInserts - ); + const AdditionalNoteInserts = relatedros + ? Object.keys(relatedros).filter((key) => relatedros[key]) + : []; await insertNote({ variables: { diff --git a/client/src/components/notes-preset-button/notes-preset-button.component.jsx b/client/src/components/notes-preset-button/notes-preset-button.component.jsx index 97eaf36b6..6cf5de285 100644 --- a/client/src/components/notes-preset-button/notes-preset-button.component.jsx +++ b/client/src/components/notes-preset-button/notes-preset-button.component.jsx @@ -22,9 +22,17 @@ export function NotesPresetButton({ bodyshop, form }) { }; const menu = ( - + {bodyshop.md_notes_presets.map((i, idx) => ( - handleSelect(i)} key={idx}> + handleSelect(i)} + key={idx} + style={{ breakInside: "avoid" }} + > {i.label} ))} 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 8993a4654..4c1e01599 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 @@ -11,6 +11,7 @@ import { Select, Menu, Dropdown, + Checkbox, } from "antd"; import React from "react"; import { useTranslation } from "react-i18next"; @@ -114,6 +115,15 @@ export function PartsOrderModalComponent({ )} + {!isReturn && ( + + + + )} {t("parts_orders.labels.inthisorder")} @@ -280,6 +290,7 @@ export function PartsOrderModalComponent({ > + setSendType(e.target.value)} diff --git a/client/src/components/parts-order-modal/parts-order-modal.container.jsx b/client/src/components/parts-order-modal/parts-order-modal.container.jsx index b449b3881..18bd94986 100644 --- a/client/src/components/parts-order-modal/parts-order-modal.container.jsx +++ b/client/src/components/parts-order-modal/parts-order-modal.container.jsx @@ -32,6 +32,7 @@ import PartsOrderModalComponent from "./parts-order-modal.component"; import axios from "axios"; import { useTreatments } from "@splitsoftware/splitio-react"; import _ from "lodash"; +import { UPDATE_JOB } from "../../graphql/jobs.queries"; const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, @@ -90,8 +91,9 @@ export function PartsOrderModalContainer({ const [insertPartOrder] = useMutation(INSERT_NEW_PARTS_ORDERS); const [updateJobLines] = useMutation(UPDATE_JOB_LINE_STATUS); + const [updateJob] = useMutation(UPDATE_JOB); - const handleFinish = async (values) => { + const handleFinish = async ({ removefrompartsqueue, ...values }) => { logImEXEvent("parts_order_insert"); setSaving(true); const insertResult = await insertPartOrder({ @@ -128,6 +130,17 @@ export function PartsOrderModalContainer({ }, }); + if (!isReturn && removefrompartsqueue) { + await updateJob({ + variables: { + jobId: jobId, + job: { + queued_for_parts: false, + }, + }, + }); + } + insertAuditTrail({ jobid: jobId, operation: isReturn diff --git a/client/src/components/scoreboard-display/scoreboard-display.component.jsx b/client/src/components/scoreboard-display/scoreboard-display.component.jsx index e3f3244a4..a27b5c633 100644 --- a/client/src/components/scoreboard-display/scoreboard-display.component.jsx +++ b/client/src/components/scoreboard-display/scoreboard-display.component.jsx @@ -8,8 +8,11 @@ import { connect } from "react-redux"; import { createStructuredSelector } from "reselect"; import { selectBodyshop } from "../../redux/user/user.selectors"; import moment from "moment"; -import { useApolloClient } from "@apollo/client"; -import { GET_BLOCKED_DAYS } from "../../graphql/scoreboard.queries"; +import { useApolloClient, useQuery } from "@apollo/client"; +import { + GET_BLOCKED_DAYS, + QUERY_SCOREBOARD, +} from "../../graphql/scoreboard.queries"; const mapStateToProps = createStructuredSelector({ //currentUser: selectCurrentUser bodyshop: selectBodyshop, @@ -22,10 +25,15 @@ export default connect( mapDispatchToProps )(ScoreboardDisplayComponent); -export function ScoreboardDisplayComponent({ - bodyshop, - scoreboardSubscription, -}) { +export function ScoreboardDisplayComponent({ bodyshop }) { + const scoreboardSubscription = useQuery(QUERY_SCOREBOARD, { + variables: { + start: moment().startOf("month"), + end: moment().endOf("month"), + }, + pollInterval: 60000, + }); + const { data } = scoreboardSubscription; const client = useApolloClient(); const scoreBoardlist = (data && data.scoreboard) || []; diff --git a/client/src/components/vehicle-detail-form/vehicle-detail-form.component.jsx b/client/src/components/vehicle-detail-form/vehicle-detail-form.component.jsx index 86c587afe..6ec1c3853 100644 --- a/client/src/components/vehicle-detail-form/vehicle-detail-form.component.jsx +++ b/client/src/components/vehicle-detail-form/vehicle-detail-form.component.jsx @@ -139,6 +139,9 @@ export default function VehicleDetailFormComponent({ form, loading }) { + + + ); } diff --git a/client/src/graphql/jobs.queries.js b/client/src/graphql/jobs.queries.js index db2357a71..8603fcfe6 100644 --- a/client/src/graphql/jobs.queries.js +++ b/client/src/graphql/jobs.queries.js @@ -75,13 +75,9 @@ export const QUERY_PARTS_QUEUE = gql` v_make_desc v_color vehicleid - actual_completion - actual_delivery - actual_in + scheduled_in id clm_no - clm_total - owner_owing ro_number status updated_at @@ -534,6 +530,8 @@ export const GET_JOB_BY_PK = gql` v_model_desc v_make_desc v_color + notes + v_paint_codes jobs { id ro_number diff --git a/client/src/graphql/scoreboard.queries.js b/client/src/graphql/scoreboard.queries.js index 2b9a4195b..3ce8ed1bf 100644 --- a/client/src/graphql/scoreboard.queries.js +++ b/client/src/graphql/scoreboard.queries.js @@ -1,7 +1,7 @@ import { gql } from "@apollo/client"; -export const SUBSCRIPTION_SCOREBOARD = gql` - subscription SUBSCRIPTION_SCOREBOARD($start: date!, $end: date!) { +export const QUERY_SCOREBOARD = gql` + query QUERY_SCOREBOARD($start: date!, $end: date!) { scoreboard( where: { _and: { date: { _gte: $start, _lte: $end } } } order_by: { date: asc } diff --git a/client/src/graphql/vehicles.queries.js b/client/src/graphql/vehicles.queries.js index 507b22399..a2a31a57d 100644 --- a/client/src/graphql/vehicles.queries.js +++ b/client/src/graphql/vehicles.queries.js @@ -27,6 +27,7 @@ export const QUERY_VEHICLE_BY_ID = gql` v_bstyle updated_at trim_color + notes jobs { id ro_number diff --git a/client/src/pages/parts-queue/parts-queue.page.component.jsx b/client/src/pages/parts-queue/parts-queue.page.component.jsx index d5a11537a..651125800 100644 --- a/client/src/pages/parts-queue/parts-queue.page.component.jsx +++ b/client/src/pages/parts-queue/parts-queue.page.component.jsx @@ -15,7 +15,7 @@ import OwnerNameDisplay from "../../components/owner-name-display/owner-name-dis import { QUERY_PARTS_QUEUE } from "../../graphql/jobs.queries"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { onlyUnique } from "../../utils/arrayHelper"; -import { TimeAgoFormatter } from "../../utils/DateFormatter"; +import { DateTimeFormatter, TimeAgoFormatter } from "../../utils/DateFormatter"; import { alphaSort, dateSort } from "../../utils/sorters"; const mapStateToProps = createStructuredSelector({ @@ -158,6 +158,17 @@ export function PartsQueuePageComponent({ bodyshop }) { }, }, + { + title: t("jobs.fields.scheduled_in"), + dataIndex: "scheduled_in", + key: "scheduled_in", + ellipsis: true, + sorter: (a, b) => dateSort(a.scheduled_in, b.scheduled_in), + sortOrder: sortcolumn === "scheduled_in" && sortorder, + render: (text, record) => ( + {record.scheduled_in} + ), + }, { title: t("jobs.fields.vehicle"), dataIndex: "vehicle", diff --git a/client/src/pages/phonebook/phonebook.page.component.jsx b/client/src/pages/phonebook/phonebook.page.component.jsx index a8f5ee389..883cb5d81 100644 --- a/client/src/pages/phonebook/phonebook.page.component.jsx +++ b/client/src/pages/phonebook/phonebook.page.component.jsx @@ -160,6 +160,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {