From d3bd68d40ab2948f67d1a4f6c580dd45df0409c3 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Fri, 7 Feb 2020 15:27:53 -0800 Subject: [PATCH] Added owners detail fields and owner jobs list. --- bodyshop_translations.babel | 199 ++++++++++++++++++ .../email-form-item.component.jsx | 8 +- .../owner-detail-form.component.jsx | 106 ++++++++++ .../owner-detail-form.container.jsx | 46 ++++ .../owner-detail-jobs.component.jsx | 59 ++++++ client/src/graphql/owners.queries.js | 47 +++++ client/src/graphql/vehicles.queries.js | 2 +- .../owners-detail.page.component.jsx | 12 +- .../owners-detail.page.container.jsx | 26 ++- .../vehicles-detail.page.component.jsx | 2 - .../vehicles-detail.page.container.jsx | 8 +- client/src/translations/en_us/common.json | 15 +- client/src/translations/es/common.json | 15 +- client/src/translations/fr/common.json | 15 +- 14 files changed, 542 insertions(+), 18 deletions(-) create mode 100644 client/src/components/owner-detail-form/owner-detail-form.component.jsx create mode 100644 client/src/components/owner-detail-form/owner-detail-form.container.jsx create mode 100644 client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index e1f0bcff6..7dbc275db 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -4668,9 +4668,56 @@ owners + + errors + + + noaccess + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + fields + + allow_text_message + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + ownr_addr1 false @@ -4692,6 +4739,27 @@ + + ownr_addr2 + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + ownr_city false @@ -4713,6 +4781,27 @@ + + ownr_ctry + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + ownr_ea false @@ -4797,6 +4886,90 @@ + + ownr_st + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + ownr_title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + ownr_zip + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + preferred_contact + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + @@ -4825,6 +4998,32 @@ + + successes + + + save + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + diff --git a/client/src/components/form-items-formatted/email-form-item.component.jsx b/client/src/components/form-items-formatted/email-form-item.component.jsx index bb51094ca..c007b6bb3 100644 --- a/client/src/components/form-items-formatted/email-form-item.component.jsx +++ b/client/src/components/form-items-formatted/email-form-item.component.jsx @@ -5,9 +5,13 @@ function FormItemEmail(props, ref) { + props.email ? ( + + + + ) : ( - + ) } /> ); diff --git a/client/src/components/owner-detail-form/owner-detail-form.component.jsx b/client/src/components/owner-detail-form/owner-detail-form.component.jsx new file mode 100644 index 000000000..37eb40385 --- /dev/null +++ b/client/src/components/owner-detail-form/owner-detail-form.component.jsx @@ -0,0 +1,106 @@ +import { Button, Col, Form, Input, Row, Switch } from "antd"; +import React from "react"; +import { useTranslation } from "react-i18next"; +import FormItemEmail from "../form-items-formatted/email-form-item.component"; +import FormItemPhone from "../form-items-formatted/phone-form-item.component"; +import ResetForm from "../form-items-formatted/reset-form-item.component"; + +export default function OwnerDetailFormComponent({ form, owner }) { + const { t } = useTranslation(); + const { + isFieldsTouched, + resetFields, + getFieldDecorator, + getFieldValue + } = form; + + return ( +
+ {isFieldsTouched() ? : null} + + + + + {getFieldDecorator("ownr_ln", { + initialValue: owner.ownr_ln + })()} + + + {getFieldDecorator("ownr_fn", { + initialValue: owner.ownr_fn + })()} + + + {getFieldDecorator("allow_text_message", { + initialValue: owner.allow_text_message, + valuePropName: "checked" + })()} + + + {getFieldDecorator("ownr_addr1", { + initialValue: owner.ownr_addr1 + })()} + + + {getFieldDecorator("ownr_addr2", { + initialValue: owner.ownr_addr2 + })()} + + + {getFieldDecorator("ownr_city", { + initialValue: owner.ownr_city + })()} + + + {getFieldDecorator("ownr_ctry", { + initialValue: owner.ownr_ctry + })()} + + + + {" "} + + {getFieldDecorator("ownr_ea", { + initialValue: owner.ownr_ea, + rules: [ + { + type: "email", + message: "This is not a valid email address." + } + ] + })( + + )} + + + {getFieldDecorator("ownr_ph1", { + initialValue: owner.ownr_ph1 + })()} + + + {getFieldDecorator("ownr_st", { + initialValue: owner.ownr_st + })()} + + + {getFieldDecorator("ownr_zip", { + initialValue: owner.ownr_zip + })()} + + + {getFieldDecorator("preferred_contact", { + initialValue: owner.preferred_contact + })()} + + + {getFieldDecorator("ownr_title", { + initialValue: owner.ownr_title + })()} + + + +
+ ); +} diff --git a/client/src/components/owner-detail-form/owner-detail-form.container.jsx b/client/src/components/owner-detail-form/owner-detail-form.container.jsx new file mode 100644 index 000000000..a58168463 --- /dev/null +++ b/client/src/components/owner-detail-form/owner-detail-form.container.jsx @@ -0,0 +1,46 @@ +import { Form, notification } from "antd"; +import React from "react"; +import { useMutation } from "react-apollo"; +import { useTranslation } from "react-i18next"; +import { UPDATE_OWNER } from "../../graphql/owners.queries"; +import OwnerDetailFormComponent from "./owner-detail-form.component"; + +function OwnerDetailFormContainer({ form, owner, refetch }) { + const { t } = useTranslation(); + + const [updateOwner] = useMutation(UPDATE_OWNER); + + const handleSubmit = e => { + e.preventDefault(); + + form.validateFieldsAndScroll((err, values) => { + if (err) { + notification["error"]({ + message: t("owners.errors.validationtitle"), + description: t("owners.errors.validation") + }); + } + if (!err) { + updateOwner({ + variables: { ownerId: owner.id, owner: values } + }).then(r => { + notification["success"]({ + message: t("owners.successes.save") + }); + //TODO: Better way to reset the field decorators? + if (refetch) refetch().then(); + form.resetFields(); + }); + } + }); + }; + + return ( +
+ + + ); +} +export default Form.create({ name: "OwnerDetailFormContainer" })( + OwnerDetailFormContainer +); diff --git a/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx b/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx new file mode 100644 index 000000000..2f26506dd --- /dev/null +++ b/client/src/components/owner-detail-jobs/owner-detail-jobs.component.jsx @@ -0,0 +1,59 @@ +import React from "react"; +import { Table } from "antd"; +import { useTranslation } from "react-i18next"; +import { Link } from "react-router-dom"; +import CurrencyFormatter from "../../utils/CurrencyFormatter"; +export default function OwnerDetailJobsComponent({ owner }) { + const { t } = useTranslation(); + const columns = [ + { + title: t("jobs.fields.ro_number"), + dataIndex: "ro_number", + key: "ro_number", + ellipsis: true, + render: (text, record) => ( + + {record.ro_number ? record.ro_number : `EST ${record.est_number}`} + + ) + }, + { + title: t("jobs.fields.vehicle"), + dataIndex: "owner", + key: "owner", + render: (text, record) => ( + + {`${record.vehicle.v_model_yr} ${record.vehicle.v_make_desc} ${record.vehicle.v_model_desc}`} + + ) + }, + { + title: t("jobs.fields.clm_no"), + dataIndex: "clm_no", + key: "clm_no" + }, + { + title: t("jobs.fields.status"), + dataIndex: "status", + key: "status" + }, + + { + title: t("jobs.fields.clm_total"), + dataIndex: "clm_total", + key: "clm_total", + render: (text, record) => ( + {record.clm_total} + ) + } + ]; + + return ( + ({ ...item }))} + rowKey="id" + dataSource={owner.jobs} + /> + ); +} diff --git a/client/src/graphql/owners.queries.js b/client/src/graphql/owners.queries.js index 0945e48b0..0a86d4f90 100644 --- a/client/src/graphql/owners.queries.js +++ b/client/src/graphql/owners.queries.js @@ -18,3 +18,50 @@ export const QUERY_SEARCH_OWNER_BY_IDX = gql` } } `; + +export const QUERY_OWNER_BY_ID = gql` + query QUERY_OWNER_BY_ID($id: uuid!) { + owners_by_pk(id: $id) { + id + allow_text_message + ownr_addr1 + ownr_addr2 + ownr_co_nm + ownr_city + ownr_ctry + ownr_ea + ownr_fn + ownr_ph1 + ownr_ln + ownr_ph2 + ownr_st + ownr_title + ownr_zip + preferred_contact + jobs { + id + ro_number + est_number + clm_no + status + clm_total + vehicle { + id + v_model_yr + v_model_desc + v_make_desc + } + } + } + } +`; + +export const UPDATE_OWNER = gql` + mutation UPDATE_OWNER($ownerId: uuid!, $owner: owners_set_input!) { + update_owners(where: { id: { _eq: $ownerId } }, _set: $owner) { + returning { + id + } + } + } +`; diff --git a/client/src/graphql/vehicles.queries.js b/client/src/graphql/vehicles.queries.js index 2dcc10303..0ca51d30a 100644 --- a/client/src/graphql/vehicles.queries.js +++ b/client/src/graphql/vehicles.queries.js @@ -2,7 +2,7 @@ import { gql } from "apollo-boost"; export const QUERY_VEHICLE_BY_ID = gql` query QUERY_VEHICLE_BY_ID($id: uuid!) { - vehicles(where: { id: { _eq: $id } }) { + vehicles_by_pk(id: $id) { created_at db_v_code id diff --git a/client/src/pages/owners-detail/owners-detail.page.component.jsx b/client/src/pages/owners-detail/owners-detail.page.component.jsx index 122d88f1a..89c274134 100644 --- a/client/src/pages/owners-detail/owners-detail.page.component.jsx +++ b/client/src/pages/owners-detail/owners-detail.page.component.jsx @@ -1,5 +1,11 @@ import React from "react"; - -export default function OwnersDetailComponent() { - return
Owner Detail
; +import OwnerDetailForm from "../../components/owner-detail-form/owner-detail-form.container"; +import OwnerDetailJobsComponent from "../../components/owner-detail-jobs/owner-detail-jobs.component"; +export default function OwnersDetailComponent({ owner, refetch }) { + return ( +
+ + +
+ ); } diff --git a/client/src/pages/owners-detail/owners-detail.page.container.jsx b/client/src/pages/owners-detail/owners-detail.page.container.jsx index bc7b94f4b..f2adcb24a 100644 --- a/client/src/pages/owners-detail/owners-detail.page.container.jsx +++ b/client/src/pages/owners-detail/owners-detail.page.container.jsx @@ -1,8 +1,28 @@ import React from "react"; import OwnersDetailComponent from "./owners-detail.page.component"; - +import { useTranslation } from "react-i18next"; +import { useQuery } from "react-apollo"; +import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; +import AlertComponent from "../../components/alert/alert.component"; +import { QUERY_OWNER_BY_ID } from "../../graphql/owners.queries"; export default function OwnersDetailContainer({ match }) { const { ownerId } = match.params; - console.log("ownerId", ownerId); - return ; + const { t } = useTranslation(); + + const { loading, data, error, refetch } = useQuery(QUERY_OWNER_BY_ID, { + variables: { id: ownerId }, + fetchPolicy: "network-only" + }); + + if (loading) return ; + if (error) return ; + + if (data.owners_by_pk) + return ( + + ); + else + return ( + + ); } diff --git a/client/src/pages/vehicles-detail/vehicles-detail.page.component.jsx b/client/src/pages/vehicles-detail/vehicles-detail.page.component.jsx index 8af261cf5..3cc260675 100644 --- a/client/src/pages/vehicles-detail/vehicles-detail.page.component.jsx +++ b/client/src/pages/vehicles-detail/vehicles-detail.page.component.jsx @@ -5,8 +5,6 @@ import VehicleDetailJobsComponent from "../../components/vehicle-detail-jobs/veh export default function VehicleDetailComponent({ vehicle, refetch }) { return (
- Veh detail {vehicle.v_vin} -
Vehicle Fields
diff --git a/client/src/pages/vehicles-detail/vehicles-detail.page.container.jsx b/client/src/pages/vehicles-detail/vehicles-detail.page.container.jsx index 5df581377..a2a7b2ca3 100644 --- a/client/src/pages/vehicles-detail/vehicles-detail.page.container.jsx +++ b/client/src/pages/vehicles-detail/vehicles-detail.page.container.jsx @@ -17,8 +17,8 @@ export default function VehicleDetailContainer({ match }) { useEffect(() => { document.title = t("titles.vehicledetail", { vehicle: - data && data.vehicles[0] - ? `${data.vehicles[0].v_model_yr} ${data.vehicles[0].v_make_desc} ${data.vehicles[0].v_model_desc}` + data && data.vehicles_by_pk + ? `${data.vehicles_by_pk.v_model_yr} ${data.vehicles_by_pk.v_make_desc} ${data.vehicles_by_pk.v_model_desc}` : "" }); }, [t, data]); @@ -26,9 +26,9 @@ export default function VehicleDetailContainer({ match }) { if (loading) return ; if (error) return ; - if (data.vehicles[0]) + if (data.vehicles_by_pk) return ( - + ); else return ( diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 0dc6852df..1e32c1895 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -291,16 +291,29 @@ } }, "owners": { + "errors": { + "noaccess": "The record does not exist or you do not have access to it. " + }, "fields": { + "allow_text_message": "Permission to Text?", "ownr_addr1": "Address", + "ownr_addr2": "Address 2", "ownr_city": "City", + "ownr_ctry": "Country", "ownr_ea": "Email", "ownr_fn": "First Name", "ownr_ln": "Last Name", - "ownr_ph1": "Phone 1" + "ownr_ph1": "Phone 1", + "ownr_st": "State/Province", + "ownr_title": "Title", + "ownr_zip": "Zip/Postal Code", + "preferred_contact": "Preferred Contact Method" }, "labels": { "existing_owners": "Existing Owners" + }, + "successes": { + "save": "Owner saved successfully." } }, "profile": { diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 3db448c3a..3b3bbe1d5 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -291,16 +291,29 @@ } }, "owners": { + "errors": { + "noaccess": "El registro no existe o no tiene acceso a él." + }, "fields": { + "allow_text_message": "Permiso de texto?", "ownr_addr1": "Dirección", + "ownr_addr2": "Dirección 2", "ownr_city": "ciudad", + "ownr_ctry": "País", "ownr_ea": "Email", "ownr_fn": "Nombre de pila", "ownr_ln": "Apellido", - "ownr_ph1": "" + "ownr_ph1": "Teléfono 1", + "ownr_st": "Provincia del estado", + "ownr_title": "Título", + "ownr_zip": "código postal", + "preferred_contact": "Método de Contacto Preferido" }, "labels": { "existing_owners": "Propietarios existentes" + }, + "successes": { + "save": "Propietario guardado con éxito." } }, "profile": { diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index 1feadd201..ae349c18b 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -291,16 +291,29 @@ } }, "owners": { + "errors": { + "noaccess": "L'enregistrement n'existe pas ou vous n'y avez pas accès." + }, "fields": { + "allow_text_message": "Autorisation de texte?", "ownr_addr1": "Adresse", + "ownr_addr2": "Adresse 2 ", "ownr_city": "Ville", + "ownr_ctry": "Pays", "ownr_ea": "Email", "ownr_fn": "Prénom", "ownr_ln": "Nom de famille", - "ownr_ph1": "" + "ownr_ph1": "Téléphone 1", + "ownr_st": "Etat / Province", + "ownr_title": "Titre", + "ownr_zip": "Zip / code postal", + "preferred_contact": "Méthode de contact préférée" }, "labels": { "existing_owners": "Propriétaires existants" + }, + "successes": { + "save": "Le propriétaire a bien enregistré." } }, "profile": {