diff --git a/_business_logic/documents.md b/_business_logic/documents.md index 7291c0a58..9641363eb 100644 --- a/_business_logic/documents.md +++ b/_business_logic/documents.md @@ -5,4 +5,4 @@ 1. Get a presigned URL by hitting our own express server with a unique key. 2. Use this presigned URL to upload an individual file. 3. Store the key + the bucket name to the documents record. -4. ???Figure out how to add thumbnails. \ No newline at end of file +4. \ No newline at end of file diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index bde400703..8c606e919 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -484,6 +484,27 @@ + + nodates + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + nojobselected false @@ -615,6 +636,69 @@ fields + + actual_completion + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + actual_delivery + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + actual_in + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + claim_total false @@ -678,6 +762,132 @@ + + date_closed + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + date_estimated + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + date_exported + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + date_invoiced + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + date_open + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + date_scheduled + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + deductible false @@ -846,6 +1056,69 @@ + + scheduled_completion + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + scheduled_delivery + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + scheduled_in + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + status false @@ -1886,6 +2159,37 @@ + + user + + + actions + + + signout + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + vehicles diff --git a/client/src/App/App.js b/client/src/App/App.js index b9eeb58cc..3fa93e5d1 100644 --- a/client/src/App/App.js +++ b/client/src/App/App.js @@ -30,6 +30,7 @@ export default () => { useEffect(() => { //Run the auth code only on the first render. const unsubscribeFromAuth = auth.onAuthStateChanged(async user => { + console.log("Auth State Changed.") if (user) { let token; token = await user.getIdToken(); diff --git a/client/src/components/current-user-dropdown/current-user-dropdown.component.jsx b/client/src/components/current-user-dropdown/current-user-dropdown.component.jsx index 10ce89da3..177a1cb97 100644 --- a/client/src/components/current-user-dropdown/current-user-dropdown.component.jsx +++ b/client/src/components/current-user-dropdown/current-user-dropdown.component.jsx @@ -63,7 +63,7 @@ export default function CurrentUserDropdown() { - {currentUser?.displayName ?? t("general.labels.unknown")} + {currentUser?.displayName || t("general.labels.unknown")} diff --git a/client/src/components/job-detail-cards/job-detail-cards.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.component.jsx index 2b868a860..5c900483d 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.component.jsx @@ -1,26 +1,24 @@ -import React, { useState } from "react"; -import { Link } from "react-router-dom"; -import { useTranslation } from "react-i18next"; import { useQuery } from "@apollo/react-hooks"; -import AlertComponent from "../alert/alert.component"; +import { Button, Icon, PageHeader, Tag } from "antd"; +import React, { useState } from "react"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries"; -import { PageHeader, Button, Descriptions, Tag, Icon } from "antd"; - +import AlertComponent from "../alert/alert.component"; +import LoadingSpinner from "../loading-spinner/loading-spinner.component"; +import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; //import JobDetailCardsHeaderComponent from "./job-detail-cards.header.component"; import JobDetailCardsCustomerComponent from "./job-detail-cards.customer.component"; -import JobDetailCardsVehicleComponent from "./job-detail-cards.vehicle.component"; -import JobDetailCardsInsuranceComponent from "./job-detail-cards.insurance.component"; -import JobDetailCardsDatesComponent from "./job-detail-cards.dates.component"; -import JobDetailCardsPartsComponent from "./job-detail-cards.parts.component"; -import JobDetailCardsNotesComponent from "./job-detail-cards.notes.component"; import JobDetailCardsDamageComponent from "./job-detail-cards.damage.component"; -import JobDetailCardsTotalsComponent from "./job-detail-cards.totals.component"; +import JobDetailCardsDatesComponent from "./job-detail-cards.dates.component"; import JobDetailCardsDocumentsComponent from "./job-detail-cards.documents.component"; -import LoadingSpinner from "../loading-spinner/loading-spinner.component"; - +import JobDetailCardsInsuranceComponent from "./job-detail-cards.insurance.component"; +import JobDetailCardsNotesComponent from "./job-detail-cards.notes.component"; +import JobDetailCardsPartsComponent from "./job-detail-cards.parts.component"; import "./job-detail-cards.styles.scss"; -import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component"; -import NoteUpsertModal from "../note-upsert-modal/note-upsert-modal.container"; +import JobDetailCardsTotalsComponent from "./job-detail-cards.totals.component"; + + export default function JobDetailCards({ selectedJob }) { const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, { @@ -95,33 +93,38 @@ export default function JobDetailCards({ selectedJob }) { {t("jobs.actions.postInvoices")} ]}> - {loading ? ( - - ) : ( - - Lili Qu - 421421 - - 2017-01-10 - - - 2017-10-10 - - - Gonghu Road, Xihu District, Hangzhou, Zhejiang, China - - - )} + { + // loading ? ( + // + // ) : ( + // + // Lili Qu + // 421421 + // + // 2017-01-10 + // + // + // 2017-10-10 + // + // + // Gonghu Road, Xihu District, Hangzhou, Zhejiang, China + // + // + // ) + }
- + { + // + } + + extraLink={data && data.owner ? `/manage/owners/${data.owner.id}` : null}> {data ? ( -
{`${data?.ownr_fn ?? ""} ${data.ownr_ln ?? ""}`}
+
{`${data.ownr_fn || ""} ${data.ownr_ln || ""}`}
{t("jobs.fields.phoneshort")}: - {`${data?.ownr_ph1 ?? + {`${data.ownr_ph1 || t("general.labels.na")}`}
-
{t("jobs.fields.ownr_ea")}: - {data?.ownr_ea ? ( + {data.ownr_ea ? ( - {`${data?.ownr_ea ?? ""}`} + {`${data.ownr_ea || ""}`} ) : ( t("general.labels.na") )}
- -
{`${data?.owner?.preferred_contact ?? ""}`}
+
{`${(data.owner && data.owner.preferred_contact) || ""}`}
+ {data.vehicle ? ( + + {`${data.vehicle.v_model_yr || ""} ${data.vehicle.v_make_desc || + ""} ${data.vehicle.v_model_desc || ""}`} + + ) : ( + {t("jobs.errors.novehicle")} + )}
) : null} diff --git a/client/src/components/job-detail-cards/job-detail-cards.dates.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.dates.component.jsx index d329d1f58..a6c17e793 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.dates.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.dates.component.jsx @@ -11,13 +11,112 @@ export default function JobDetailCardsDatesComponent({ loading, data }) { {data ? ( - - Actual In {data?.actual_in} - - - Scheduled Completion - {data?.scheduled_completion} - + {!( + data.actual_in || + data.scheduled_completion || + data.scheduled_in || + data.actual_completion || + data.scheduled_delivery || + data.actual_delivery || + data.date_estimated || + data.date_open || + data.date_scheduled || + data.date_invoiced || + data.date_closed || + data.date_exported + ) ? ( +
{t("jobs.errors.nodates")}
+ ) : null} + + {data.actual_in ? ( + + {t("jobs.fields.actual_in")} + {data.actual_in || ""} + + ) : null} + + {data.scheduled_completion ? ( + + {t("jobs.fields.scheduled_completion")} + + {data.scheduled_completion || ""} + + + ) : null} + + {data.scheduled_in ? ( + + {t("jobs.fields.scheduled_in")} + {data.scheduled_in || ""} + + ) : null} + + {data.actual_completion ? ( + + {t("jobs.fields.actual_completion")} + + {data.actual_completion || ""} + + + ) : null} + + {data.scheduled_delivery ? ( + + {t("jobs.fields.scheduled_delivery")} + + {data.scheduled_delivery || ""} + + + ) : null} + + {data.actual_delivery ? ( + + {t("jobs.fields.actual_delivery")} + {data.actual_delivery || ""} + + ) : null} + + {data.date_estimated ? ( + + {t("jobs.fields.date_estimated")} + {data.date_estimated || ""} + + ) : null} + + {data.date_open ? ( + + {t("jobs.fields.date_open")} + {data.date_open || ""} + + ) : null} + + {data.date_scheduled ? ( + + {t("jobs.fields.date_scheduled")} + {data.date_scheduled || ""} + + ) : null} + + {data.date_invoiced ? ( + + {t("jobs.fields.date_invoiced")} + {data.date_invoiced || ""} + + ) : null} + + {data.date_closed ? ( + + {t("jobs.fields.date_closed")} + {data.date_closed || ""} + + ) : null} + + {data.date_exported ? ( + + {t("jobs.fields.date_exported")} + {data.date_exported || ""} + + ) : null}
) : null}
diff --git a/client/src/components/job-detail-cards/job-detail-cards.insurance.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.insurance.component.jsx index 5dd73988c..54602f2d8 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.insurance.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.insurance.component.jsx @@ -10,16 +10,16 @@ export default function JobDetailCardsInsuranceComponent({ loading, data }) { {data ? ( -
{data?.ins_co_nm ?? t("general.labels.unknown")}
-
{data?.clm_no ?? t("general.labels.unknown")}
+
{data?.ins_co_nm || t("general.labels.unknown")}
+
{data?.clm_no || t("general.labels.unknown")}
{t("jobs.labels.cards.filehandler")} {data?.ins_ea ? ( -
{`${data?.ins_ct_fn ?? ""} ${data?.ins_ct_ln ?? ""}`}
+
{`${data?.ins_ct_fn || ""} ${data?.ins_ct_ln || ""}`}
) : ( -
{`${data?.ins_ct_fn ?? ""} ${data?.ins_ct_ln ?? ""}`}
+
{`${data?.ins_ct_fn || ""} ${data?.ins_ct_ln || ""}`}
)} {data?.ins_ph1 ? ( {data?.ins_ph1} @@ -31,10 +31,10 @@ export default function JobDetailCardsInsuranceComponent({ loading, data }) { {t("jobs.labels.cards.appraiser")} {data?.est_ea ? ( -
{`${data?.ins_ct_fn ?? ""} ${data?.ins_ct_ln ?? ""}`}
+
{`${data?.ins_ct_fn || ""} ${data?.ins_ct_ln || ""}`}
) : ( -
{`${data?.ins_ct_fn ?? ""} ${data?.ins_ct_ln ?? ""}`}
+
{`${data?.ins_ct_fn || ""} ${data?.ins_ct_ln || ""}`}
)}
@@ -42,10 +42,10 @@ export default function JobDetailCardsInsuranceComponent({ loading, data }) { {t("jobs.labels.cards.estimator")} {data?.est_ea ? ( -
{`${data?.est_ct_fn ?? ""} ${data?.est_ct_ln ?? ""}`}
+
{`${data?.est_ct_fn || ""} ${data?.est_ct_ln || ""}`}
) : ( -
{`${data?.est_ct_fn ?? ""} ${data?.est_ct_ln ?? ""}`}
+
{`${data?.est_ct_fn || ""} ${data?.est_ct_ln || ""}`}
)} {data?.est_ph1 ? ( {data?.est_ph1} diff --git a/client/src/components/job-detail-cards/job-detail-cards.vehicle.component.jsx b/client/src/components/job-detail-cards/job-detail-cards.vehicle.component.jsx index ed58b3f81..3cf89b0ed 100644 --- a/client/src/components/job-detail-cards/job-detail-cards.vehicle.component.jsx +++ b/client/src/components/job-detail-cards/job-detail-cards.vehicle.component.jsx @@ -13,9 +13,9 @@ export default function JobDetailCardsVehicleComponent({ loading, data }) { > {data ? ( - {data.vehicle?.v_model_yr ?? t("general.labels.na")}{" "} - {data.vehicle?.v_make_desc ?? t("general.labels.na")}{" "} - {data.vehicle?.v_model_desc ?? t("general.labels.na")} + {data.vehicle?.v_model_yr || t("general.labels.na")}{" "} + {data.vehicle?.v_make_desc || t("general.labels.na")}{" "} + {data.vehicle?.v_model_desc || t("general.labels.na")} ) : null}
diff --git a/client/src/components/job-tombstone/job-tombstone.component.jsx b/client/src/components/job-tombstone/job-tombstone.component.jsx index 3d6d2ba75..0bb478743 100644 --- a/client/src/components/job-tombstone/job-tombstone.component.jsx +++ b/client/src/components/job-tombstone/job-tombstone.component.jsx @@ -91,9 +91,9 @@ function JobTombstone({ job, ...otherProps }) { title={tombstoneTitle} subTitle={ jobContext.owner - ? (jobContext.owner?.first_name ?? "") + + ? (jobContext.owner?.first_name || "") + " " + - (jobContext.owner?.last_name ?? "") + (jobContext.owner?.last_name || "") : t("jobs.errors.noowner") } tags={ @@ -133,10 +133,10 @@ function JobTombstone({ job, ...otherProps }) { - {jobContext.vehicle?.v_model_yr ?? t("general.labels.na")}{" "} - {jobContext.vehicle?.v_make_desc ?? t("general.labels.na")}{" "} - {jobContext.vehicle?.v_model_desc ?? t("general.labels.na")} |{" "} - {jobContext.vehicle?.plate_no ?? t("general.labels.na")} + {jobContext.vehicle?.v_model_yr || t("general.labels.na")}{" "} + {jobContext.vehicle?.v_make_desc || t("general.labels.na")}{" "} + {jobContext.vehicle?.v_model_desc || t("general.labels.na")} |{" "} + {jobContext.vehicle?.plate_no || t("general.labels.na")} diff --git a/client/src/components/jobs-list/jobs-list.component.jsx b/client/src/components/jobs-list/jobs-list.component.jsx index 5cf9bec8b..f92279eee 100644 --- a/client/src/components/jobs-list/jobs-list.component.jsx +++ b/client/src/components/jobs-list/jobs-list.component.jsx @@ -91,7 +91,7 @@ export default withRouter(function JobsList({ sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order, render: (text, record) => { - return record.job_status?.name ?? t("general.labels.na"); + return record.job_status?.name || t("general.labels.na"); } }, diff --git a/client/src/components/sign-out/sign-out.component.jsx b/client/src/components/sign-out/sign-out.component.jsx index 2ed476ef7..9e995d819 100644 --- a/client/src/components/sign-out/sign-out.component.jsx +++ b/client/src/components/sign-out/sign-out.component.jsx @@ -16,10 +16,5 @@ export default function SignoutComponent() { const { t } = useTranslation(); - return ( -
- {this.renderRedirect()} -
{t("user.actions.signout")}
-
- ); + return
{t("user.actions.signout")}
; } diff --git a/client/src/components/white-board-card/white-board-card.component.jsx b/client/src/components/white-board-card/white-board-card.component.jsx index e5367c085..393878f8f 100644 --- a/client/src/components/white-board-card/white-board-card.component.jsx +++ b/client/src/components/white-board-card/white-board-card.component.jsx @@ -63,11 +63,11 @@ export default function WhiteBoardCard({ metadata }) {
- {metadata.vehicle?.v_model_yr ?? t("general.labels.na")}{" "} - {metadata.vehicle?.v_make_desc ?? t("general.labels.na")}{" "} - {metadata.vehicle?.v_model_desc ?? t("general.labels.na")} + {metadata.vehicle?.v_model_yr || t("general.labels.na")}{" "} + {metadata.vehicle?.v_make_desc || t("general.labels.na")}{" "} + {metadata.vehicle?.v_model_desc || t("general.labels.na")} {metadata.vehicle?.v_vin ? ( - VIN: {metadata.vehicle?.v_vin ?? t("general.labels.na")} + VIN: {metadata.vehicle?.v_vin || t("general.labels.na")} ) : null} diff --git a/client/src/graphql/apollo-error-handling.js b/client/src/graphql/apollo-error-handling.js index 271052f78..6b5b74677 100644 --- a/client/src/graphql/apollo-error-handling.js +++ b/client/src/graphql/apollo-error-handling.js @@ -1,5 +1,5 @@ import { onError } from "apollo-link-error"; -import { Observable } from "apollo-link"; +//import { Observable } from "apollo-link"; import { auth } from "../firebase/firebase.utils"; //https://stackoverflow.com/questions/57163454/refreshing-a-token-with-apollo-client-firebase-auth const errorLink = onError( diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index bff05c3e1..7a6db6841 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -38,6 +38,7 @@ }, "errors": { "noaccess": "This job does not exist or you do not have access to it.", + "nodates": "No dates specified for this job.", "nojobselected": "No job is selected.", "noowner": "No owner associated.", "novehicle": "No vehicle associated.", @@ -46,9 +47,18 @@ "validationtitle": "Validation Error" }, "fields": { + "actual_completion": "Actual Completion", + "actual_delivery": "Actual Delivery", + "actual_in": "Actual In", "claim_total": "Claim Total", "clm_no": "Claim #", "clm_total": "Claim Total", + "date_closed": "Closed", + "date_estimated": "Date Estimated", + "date_exported": "Exported", + "date_invoiced": "Invoiced", + "date_open": "Open", + "date_scheduled": "Scheduled", "deductible": "Deductible", "est_number": "Estimate Number", "owner": "Owner", @@ -57,6 +67,9 @@ "phone1": "Phone 1", "phoneshort": "PH", "ro_number": "RO #", + "scheduled_completion": "Scheduled Completion", + "scheduled_delivery": "Scheduled Delivery", + "scheduled_in": "Scheduled In", "status": "Job Status", "vehicle": "Vehicle" }, @@ -133,6 +146,11 @@ "jobsdocuments": "Job Documents {{ro_number}} | $t(titles.app)", "profile": "My Profile | $t(titles.app)" }, + "user": { + "actions": { + "signout": "Sign Out" + } + }, "vehicles": { "fields": { "plate_no": "License Plate" diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index ff81af7c1..fda17bd90 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -38,6 +38,7 @@ }, "errors": { "noaccess": "Este trabajo no existe o no tiene acceso a él.", + "nodates": "No hay fechas especificadas para este trabajo.", "nojobselected": "No hay trabajo seleccionado.", "noowner": "Ningún propietario asociado.", "novehicle": "No hay vehículo asociado.", @@ -46,9 +47,18 @@ "validationtitle": "Error de validacion" }, "fields": { + "actual_completion": "Realización real", + "actual_delivery": "Entrega real", + "actual_in": "Real en", "claim_total": "Reclamar total", "clm_no": "Reclamación #", "clm_total": "Reclamar total", + "date_closed": "Cerrado", + "date_estimated": "Fecha estimada", + "date_exported": "Exportado", + "date_invoiced": "Facturado", + "date_open": "Abierto", + "date_scheduled": "Programado", "deductible": "Deducible", "est_number": "Numero Estimado", "owner": "Propietario", @@ -57,6 +67,9 @@ "phone1": "Teléfono 1", "phoneshort": "PH", "ro_number": "RO #", + "scheduled_completion": "Finalización programada", + "scheduled_delivery": "Entrega programada", + "scheduled_in": "Programado en", "status": "Estado del trabajo", "vehicle": "Vehículo" }, @@ -133,6 +146,11 @@ "jobsdocuments": "Documentos de trabajo {{ro_number}} | $ t (títulos.app)", "profile": "Mi perfil | $t(titles.app)" }, + "user": { + "actions": { + "signout": "desconectar" + } + }, "vehicles": { "fields": { "plate_no": "Placa" diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index dad791091..53926ea54 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -38,6 +38,7 @@ }, "errors": { "noaccess": "Ce travail n'existe pas ou vous n'y avez pas accès.", + "nodates": "Aucune date spécifiée pour ce travail.", "nojobselected": "Aucun travail n'est sélectionné.", "noowner": "Aucun propriétaire associé.", "novehicle": "Aucun véhicule associé.", @@ -46,9 +47,18 @@ "validationtitle": "Erreur de validation" }, "fields": { + "actual_completion": "Achèvement réel", + "actual_delivery": "Livraison réelle", + "actual_in": "En réel", "claim_total": "Total réclamation", "clm_no": "Prétendre #", "clm_total": "Total réclamation", + "date_closed": "Fermé", + "date_estimated": "Date estimée", + "date_exported": "Exportés", + "date_invoiced": "Facturé", + "date_open": "Ouvrir", + "date_scheduled": "Prévu", "deductible": "Déductible", "est_number": "Numéro d'estimation", "owner": "Propriétaire", @@ -57,6 +67,9 @@ "phone1": "Téléphone 1", "phoneshort": "PH", "ro_number": "RO #", + "scheduled_completion": "Achèvement planifié", + "scheduled_delivery": "Livraison programmée", + "scheduled_in": "Planifié dans", "status": "Statut de l'emploi", "vehicle": "Véhicule" }, @@ -133,6 +146,11 @@ "jobsdocuments": "Documents de travail {{ro_number}} | $ t (titres.app)", "profile": "Mon profil | $t(titles.app)" }, + "user": { + "actions": { + "signout": "Déconnexion" + } + }, "vehicles": { "fields": { "plate_no": "Plaque d'immatriculation"