UI fixes for manual job creation + owners pages + vehicles pages + all jobs BOD-155

This commit is contained in:
Patrick Fic
2020-06-12 17:54:20 -07:00
parent a88785fc43
commit 05bf94e808
37 changed files with 1339 additions and 972 deletions

View File

@@ -11077,27 +11077,6 @@
<folder_node>
<name>cards</name>
<children>
<concept_node>
<name>appraiser</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>customer</name>
<definition_loaded>false</definition_loaded>
@@ -13867,6 +13846,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>ownr_co_nm</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>ownr_ctry</name>
<definition_loaded>false</definition_loaded>
@@ -14058,6 +14058,74 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>forms</name>
<children>
<concept_node>
<name>address</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>contact</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>name</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>labels</name>
<children>
@@ -17514,6 +17582,74 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>forms</name>
<children>
<concept_node>
<name>detail</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>misc</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>registration</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
</children>
</folder_node>
<folder_node>
<name>labels</name>
<children>

View File

@@ -22,7 +22,12 @@
&__margin {
margin: 0.2rem 0.2rem;
}
&__margin-large {
margin: 0.5rem 0.5rem;
}
&__flex-space-around {
justify-content: space-around;
}
}

View File

@@ -1,10 +1,10 @@
import { Table, Button } from "antd";
import { Table, Button, Input } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import { alphaSort } from "../../utils/sorters";
export default function CourtesyCarsList({ loading, courtesycars }) {
import { SyncOutlined } from "@ant-design/icons";
export default function CourtesyCarsList({ loading, courtesycars, refetch }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" },
@@ -74,14 +74,28 @@ export default function CourtesyCarsList({ loading, courtesycars }) {
<Table
loading={loading}
title={() => (
<Link to={`/manage/courtesycars/new`}>
<Button>{t("courtesycars.actions.new")}</Button>
</Link>
<div className='imex-table-header'>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Link to={`/manage/courtesycars/new`}>
<Button>{t("courtesycars.actions.new")}</Button>
</Link>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onChange={(e) => {
//setSearchText(e.target.value);
}}
//value={searchText}
enterButton
/>
</div>
)}
size="small"
size='small'
pagination={{ position: "top" }}
columns={columns.map((item) => ({ ...item }))}
rowKey="id"
rowKey='id'
dataSource={courtesycars}
onChange={handleTableChange}
/>

View File

@@ -76,8 +76,7 @@ export function JobDetailCards({ setPrintCenterContext }) {
destroyOnClose
width={drawerPercentage}
placement='right'
onClose={handleDrawerClose}
footer={<div>The footer.</div>}>
onClose={handleDrawerClose}>
{loading ? <LoadingSpinner /> : null}
{error ? <AlertComponent message={error.message} type='error' /> : null}
{data ? (

View File

@@ -17,7 +17,7 @@ export default function JobDetailCardsTotalsComponent({ loading, data }) {
return (
<CardTemplate loading={loading} title={t("jobs.labels.cards.totals")}>
{totals ? (
<div className='imex-flex-row'>
<div className='imex-flex-row imex-flex-row__flex-space-around'>
<Statistic
className='imex-flex-row__margin-large'
title={t("jobs.labels.total_repairs")}

View File

@@ -3,127 +3,145 @@ 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 LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function JobsCreateJobsInfo({ form }) {
const { t } = useTranslation();
const { getFieldValue } = form;
return (
<div>
<Collapse defaultActiveKey="insurance">
<Collapse defaultActiveKey='insurance'>
<Collapse.Panel
key="insurance"
header={t("menus.jobsdetail.insurance")}
>
<Form.Item label={t("jobs.fields.ins_co_id")} name="ins_co_id">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.policy_no")} name="policy_no">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.clm_no")} name="clm_no">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.regie_number")} name="regie_number">
<Input />
</Form.Item>
TODO: missing KOL field???
<Form.Item label={t("jobs.fields.loss_date")} name="loss_date">
<DatePicker />
</Form.Item>
CAA # seems not correct based on field mapping Class seems not correct
based on field mapping
<Form.Item label={t("jobs.fields.ins_co_nm")} name="ins_co_nm">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_addr1")} name="ins_addr1">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_city")} name="ins_city">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_ln")} name="ins_ct_ln">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_fn")} name="ins_ct_fn">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ph1")} name="ins_ph1">
<FormItemPhone customInput={Input} />
</Form.Item>
<Form.Item
label={t("jobs.fields.ins_ea")}
name="ins_ea"
rules={[
{
type: "email",
message: "This is not a valid email address."
}
]}
>
<FormItemEmail email={getFieldValue("ins_ea")} />
</Form.Item>
Appraiser Info
<Form.Item label={t("jobs.fields.est_co_nm")} name="est_co_nm">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_fn")} name="est_ct_fn">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_ln")} name="est_ct_ln">
<Input />
</Form.Item>
TODO: Field is pay date but title is inspection date. Likely
incorrect?
<Form.Item label={t("jobs.fields.pay_date")} name="pay_date">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ph1")} name="est_ph1">
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.est_ea")}
name="est_ea"
rules={[
{
type: "email",
message: "This is not a valid email address."
}
]}
>
<FormItemEmail email={getFieldValue("est_ea")} />
</Form.Item>
<Form.Item
label={t("jobs.fields.selling_dealer")}
name="selling_dealer"
>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.servicing_dealer")}
name="servicing_dealer"
>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.selling_dealer_contact")}
name="selling_dealer_contact"
>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.servicing_dealer_contact")}
name="servicing_dealer_contact"
>
<Input />
</Form.Item>
key='insurance'
header={t("menus.jobsdetail.insurance")}>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.ins_co_id")} name='ins_co_id'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.policy_no")} name='policy_no'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.clm_no")} name='clm_no'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.regie_number")}
name='regie_number'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.loss_date")} name='loss_date'>
<DatePicker />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_co_nm")} name='ins_co_nm'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_addr1")} name='ins_addr1'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_city")} name='ins_city'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_ln")} name='ins_ct_ln'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ct_fn")} name='ins_ct_fn'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ins_ph1")} name='ins_ph1'>
<FormItemPhone customInput={Input} />
</Form.Item>
<Form.Item
label={t("jobs.fields.ins_ea")}
name='ins_ea'
rules={[
{
type: "email",
message: "This is not a valid email address.",
},
]}>
<FormItemEmail email={getFieldValue("ins_ea")} />
</Form.Item>
Appraiser Info
<Form.Item label={t("jobs.fields.est_co_nm")} name='est_co_nm'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_fn")} name='est_ct_fn'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ct_ln")} name='est_ct_ln'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.pay_date")} name='pay_date'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.est_ph1")} name='est_ph1'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.est_ea")}
name='est_ea'
rules={[
{
type: "email",
message: "This is not a valid email address.",
},
]}>
<FormItemEmail email={getFieldValue("est_ea")} />
</Form.Item>
<Form.Item
label={t("jobs.fields.selling_dealer")}
name='selling_dealer'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.servicing_dealer")}
name='servicing_dealer'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.selling_dealer_contact")}
name='selling_dealer_contact'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.servicing_dealer_contact")}
name='servicing_dealer_contact'>
<Input />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
<Collapse.Panel key="claim" header={t("menus.jobsdetail.claimdetail")}>
<Form.Item label={t("jobs.fields.csr")} name="csr">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.loss_desc")} name="loss_desc">
<Input />
</Form.Item>
<Collapse.Panel key='claim' header={t("menus.jobsdetail.claimdetail")}>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.csr")} name='csr'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.loss_desc")} name='loss_desc'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.ponumber")} name='po_number'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.unitnumber")} name='unit_number'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.specialcoveragepolicy")}
valuePropName='checked'
name='special_coverage_policy'>
<Switch />
</Form.Item>
<Form.Item label={t("jobs.fields.kmin")} name='kmin'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.kmout")} name='kmout'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.referralsource")}
name='referral_source'>
<Input />
</Form.Item>
</LayoutFormRow>
TODO How to handle different taxes and marking them as exempt?
{
// <Form.Item label={t("jobs.fields.exempt")}>
@@ -132,157 +150,125 @@ export default function JobsCreateJobsInfo({ form }) {
// })(<Input name='exempt' />)}
// </Form.Item>
}
<Form.Item label={t("jobs.fields.ponumber")} name="po_number">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.unitnumber")} name="unit_number">
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.specialcoveragepolicy")}
valuePropName="checked"
name="special_coverage_policy"
>
<Switch />
</Form.Item>
<Form.Item label={t("jobs.fields.kmin")} name="kmin">
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.kmout")} name="kmout">
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.referralsource")}
name="referral_source"
>
<Input />
</Form.Item>
</Collapse.Panel>
<Collapse.Panel
key="financial"
header={t("menus.jobsdetail.financials")}
>
<Form.Item label={t("jobs.fields.ded_amt")} name="ded_amt">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.ded_status")} name="ded_status">
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.depreciation_taxes")}
name="depreciation_taxes"
>
<InputNumber />
</Form.Item>
TODO This is equivalent of GST payable.
<Form.Item
label={t("jobs.fields.federal_tax_payable")}
name="federal_tax_payable"
>
<InputNumber />
</Form.Item>
TODO equivalent of other customer amount
<Form.Item
label={t("jobs.fields.other_amount_payable")}
name="other_amount_payable"
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.towing_payable")}
name="towing_payable"
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.storage_payable")}
name="storage_payable"
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.adjustment_bottom_line")}
name="adjustment_bottom_line"
>
<InputNumber />
</Form.Item>
Totals Table
<Form.Item
label={t("jobs.fields.labor_rate_desc")}
name="labor_rate_desc"
>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lab")} name="rate_lab">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lad")} name="rate_lad">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lae")} name="rate_lae">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lar")} name="rate_lar">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_las")} name="rate_las">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laf")} name="rate_laf">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lam")} name="rate_lam">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lag")} name="rate_lag">
<InputNumber />
</Form.Item>
Note //TODO Remove ATP rate?
<Form.Item label={t("jobs.fields.rate_atp")} name="rate_atp">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lau")} name="rate_lau">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la1")} name="rate_la1">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la2")} name="rate_la2">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la3")} name="rate_la3">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la4")} name="rate_la4">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mapa")} name="rate_mapa">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mash")} name="rate_mash">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mahw")} name="rate_mahw">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma2s")} name="rate_ma2s">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma3s")} name="rate_ma3s">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mabl")} name="rate_mabl">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_macs")} name="rate_macs">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_matd")} name="rate_matd">
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laa")} name="rate_laa">
<InputNumber />
</Form.Item>
key='financial'
header={t("menus.jobsdetail.financials")}>
<LayoutFormRow>
<Form.Item label={t("jobs.fields.ded_amt")} name='ded_amt'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.ded_status")} name='ded_status'>
<Input />
</Form.Item>
<Form.Item
label={t("jobs.fields.depreciation_taxes")}
name='depreciation_taxes'>
<InputNumber />
</Form.Item>
TODO This is equivalent of GST payable.
<Form.Item
label={t("jobs.fields.federal_tax_payable")}
name='federal_tax_payable'>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.other_amount_payable")}
name='other_amount_payable'>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.towing_payable")}
name='towing_payable'>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.storage_payable")}
name='storage_payable'>
<InputNumber />
</Form.Item>
<Form.Item
label={t("jobs.fields.adjustment_bottom_line")}
name='adjustment_bottom_line'>
<InputNumber />
</Form.Item>
Totals Table
<Form.Item
label={t("jobs.fields.labor_rate_desc")}
name='labor_rate_desc'>
<Input />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lab")} name='rate_lab'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lad")} name='rate_lad'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lae")} name='rate_lae'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lar")} name='rate_lar'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_las")} name='rate_las'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laf")} name='rate_laf'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lam")} name='rate_lam'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lag")} name='rate_lag'>
<InputNumber />
</Form.Item>
Note //TODO Remove ATP rate?
<Form.Item label={t("jobs.fields.rate_atp")} name='rate_atp'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_lau")} name='rate_lau'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la1")} name='rate_la1'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la2")} name='rate_la2'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la3")} name='rate_la3'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_la4")} name='rate_la4'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mapa")} name='rate_mapa'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mash")} name='rate_mash'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mahw")} name='rate_mahw'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma2s")} name='rate_ma2s'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_ma3s")} name='rate_ma3s'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_mabl")} name='rate_mabl'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_macs")} name='rate_macs'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_matd")} name='rate_matd'>
<InputNumber />
</Form.Item>
<Form.Item label={t("jobs.fields.rate_laa")} name='rate_laa'>
<InputNumber />
</Form.Item>
</LayoutFormRow>
</Collapse.Panel>
</Collapse>
</div>

View File

@@ -1,8 +1,13 @@
import { Col, Row, Typography } from "antd";
import React from "react";
import { Row, Col, Typography } from "antd";
import { useTranslation } from "react-i18next";
import JobsCreateOwnerInfoNewComponent from "./jobs-create-owner-info.new.component";
import JobsCreateOwnerInfoSearchComponent from "./jobs-create-owner-info.search.component";
import { useTranslation } from "react-i18next";
const colSpan = {
sm: { span: 24 },
lg: { span: 12 },
};
export default function JobsCreateOwnerInfoComponent({ loading, owners }) {
const { t } = useTranslation();
@@ -11,15 +16,15 @@ export default function JobsCreateOwnerInfoComponent({ loading, owners }) {
<Row>
<Typography.Title>{t("jobs.labels.create.ownerinfo")}</Typography.Title>
</Row>
<Row gutter={4}>
<Col span={16}>
<Row gutter={[32, 32]}>
<Col {...colSpan}>
<JobsCreateOwnerInfoSearchComponent
loading={loading}
owners={owners}
/>
</Col>
<Col span={8}>
<Col {...colSpan}>
<JobsCreateOwnerInfoNewComponent />
</Col>
</Row>

View File

@@ -1,18 +1,18 @@
import React, { useContext } from "react";
import JobsCreateOwnerInfoComponent from "./jobs-create-owner-info.component";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
import { useQuery } from "@apollo/react-hooks";
import React, { useContext } from "react";
import { QUERY_SEARCH_OWNER_BY_IDX } from "../../graphql/owners.queries";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import AlertComponent from "../alert/alert.component";
import JobsCreateOwnerInfoComponent from "./jobs-create-owner-info.component";
export default function JobsCreateOwnerContainer() {
const [state] = useContext(JobCreateContext);
const { loading, error, data } = useQuery(QUERY_SEARCH_OWNER_BY_IDX, {
variables: { search: `%${state.owner.search}%` },
skip: !state.owner.search
skip: !state.owner.search,
});
if (error) return <AlertComponent message={error.message} type="error" />;
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<JobsCreateOwnerInfoComponent
loading={loading}

View File

@@ -4,6 +4,7 @@ import { useTranslation } from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import FormItemPhone from "../form-items-formatted/phone-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function JobsCreateOwnerInfoNewComponent() {
const [state, setState] = useContext(JobCreateContext);
@@ -20,103 +21,111 @@ export default function JobsCreateOwnerInfoNewComponent() {
owner: {
...state.owner,
new: !state.owner.new,
selectedid: null
}
selectedid: null,
},
});
}}
>
}}>
{t("jobs.labels.create.newowner")}
</Checkbox>
<Form.Item
label={t("owners.fields.ownr_ln")}
name={["owner", "data", "ownr_ln"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_fn")}
name={["owner", "data", "ownr_fn"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.allow_text_message")}
valuePropName="checked"
name={["owner", "data", "allow_text_message"]}
>
<Switch disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_addr1")}
name={["owner", "data", "ownr_addr1"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_addr2")}
name={["owner", "data", "ownr_addr2"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_city")}
name={["owner", "data", "ownr_city"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ctry")}
name={["owner", "data", "ownr_ctry"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<LayoutFormRow header={t("owners.forms.name")} grow>
<Form.Item
label={t("owners.fields.ownr_ln")}
name={["owner", "data", "ownr_ln"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_fn")}
name={["owner", "data", "ownr_fn"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<Form.Item
label={t("owners.fields.ownr_ea")}
rules={[
{
type: "email",
message: "This is not a valid email address."
}
]}
name={["owner", "data", "ownr_ea"]}
>
<FormItemEmail
//TODO Fix this email={getFieldValue("ownr_ea")}
disabled={!state.owner.new}
/>
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ph1")}
name={["owner", "data", "ownr_ph1"]}
>
<FormItemPhone customInput={Input} disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_st")}
name={["owner", "data", "ownr_st"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_zip")}
name={["owner", "data", "ownr_zip"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.preferred_contact")}
name={["owner", "data", "preferred_contact"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_title")}
name={["owner", "data", "ownr_title"]}
>
<Input disabled={!state.owner.new} />
</Form.Item>
<LayoutFormRow grow>
<Form.Item
label={t("owners.fields.ownr_title")}
name={["owner", "data", "ownr_title"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_co_nm")}
name={["owner", "data", "ownr_co_nm"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("owners.forms.address")} grow>
<Form.Item
label={t("owners.fields.ownr_addr1")}
name={["owner", "data", "ownr_addr1"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_addr2")}
name={["owner", "data", "ownr_addr2"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("owners.fields.ownr_city")}
name={["owner", "data", "ownr_city"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_st")}
name={["owner", "data", "ownr_st"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("owners.fields.ownr_zip")}
name={["owner", "data", "ownr_zip"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ctry")}
name={["owner", "data", "ownr_ctry"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("owners.forms.contact")} grow>
<Form.Item
label={t("owners.fields.ownr_ea")}
rules={[
{
type: "email",
message: "This is not a valid email address.",
},
]}
name={["owner", "data", "ownr_ea"]}>
<FormItemEmail
//TODO Fix this email={getFieldValue("ownr_ea")}
disabled={!state.owner.new}
/>
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ph1")}
name={["owner", "data", "ownr_ph1"]}>
<FormItemPhone customInput={Input} disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("owners.fields.preferred_contact")}
name={["owner", "data", "preferred_contact"]}>
<Input disabled={!state.owner.new} />
</Form.Item>
<Form.Item
label={t("owners.fields.allow_text_message")}
valuePropName='checked'
name={["owner", "data", "allow_text_message"]}>
<Switch disabled={!state.owner.new} />
</Form.Item>
</LayoutFormRow>
</div>
);
}

View File

@@ -7,12 +7,12 @@ import { alphaSort } from "../../utils/sorters";
export default function JobsCreateOwnerInfoSearchComponent({
loading,
owners
owners,
}) {
const [state, setState] = useContext(JobCreateContext);
const [tableState, setTableState] = useState({
sortedInfo: {},
filteredInfo: { text: "" }
filteredInfo: { text: "" },
});
const { t } = useTranslation();
@@ -25,7 +25,7 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_ln" &&
tableState.sortedInfo.order
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_fn"),
@@ -34,7 +34,7 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_fn, b.ownr_fn),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_fn" &&
tableState.sortedInfo.order
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_addr1"),
@@ -43,7 +43,7 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_addr1, b.ownr_addr1),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_addr1" &&
tableState.sortedInfo.order
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_city"),
@@ -52,7 +52,7 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_city, b.ownr_city),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_city" &&
tableState.sortedInfo.order
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_ea"),
@@ -61,7 +61,7 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_ea, b.ownr_ea),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_ea" &&
tableState.sortedInfo.order
tableState.sortedInfo.order,
},
{
title: t("owners.fields.ownr_ph1"),
@@ -73,51 +73,54 @@ export default function JobsCreateOwnerInfoSearchComponent({
sorter: (a, b) => alphaSort(a.ownr_ph1, b.ownr_ph1),
sortOrder:
tableState.sortedInfo.columnKey === "ownr_ph1" &&
tableState.sortedInfo.order
}
tableState.sortedInfo.order,
},
];
const handleTableChange = (pagination, filters, sorter) => {
setTableState({ ...tableState, filteredInfo: filters, sortedInfo: sorter });
};
//TODO Implement searching & pagination
return (
<Table
loading={loading}
title={() => {
return (
<Input.Search
placeholder="Search..."
onSearch={value => {
setState({
...state,
owner: { ...state.owner, search: value }
});
}}
enterButton
/>
<div className='imex-table-header'>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onSearch={(value) => {
setState({
...state,
owner: { ...state.owner, search: value },
});
}}
enterButton
/>
</div>
);
}}
size="small"
size='small'
scroll={{ x: true }}
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
rowKey='id'
dataSource={owners}
onChange={handleTableChange}
rowSelection={{
onSelect: props => {
onSelect: (props) => {
setState({
...state,
owner: { ...state.owner, new: false, selectedid: props.id }
owner: { ...state.owner, new: false, selectedid: props.id },
});
},
type: "radio",
selectedRowKeys: [state.owner.selectedid]
selectedRowKeys: [state.owner.selectedid],
}}
onRow={(record, rowIndex) => {
return {
onClick: event => {
onClick: (event) => {
if (record) {
if (record.id) {
setState({
@@ -125,18 +128,18 @@ export default function JobsCreateOwnerInfoSearchComponent({
owner: {
...state.owner,
new: false,
selectedid: record.id
}
selectedid: record.id,
},
});
return;
}
}
setState({
...state,
owner: { ...state.owner, selectedid: null }
owner: { ...state.owner, selectedid: null },
});
}
},
};
}}
/>

View File

@@ -4,19 +4,24 @@ import { useTranslation } from "react-i18next";
import JobsCreateVehicleInfoNewComponent from "./jobs-create-vehicle-info.new.component";
import JobsCreateVehicleInfoSearchComponent from "./jobs-create-vehicle-info.search.component";
const colSpan = {
sm: { span: 24 },
lg: { span: 12 },
};
export default function JobsCreateVehicleInfoComponent({ loading, vehicles }) {
const { t } = useTranslation();
return (
<div>
<Typography.Title>{t("jobs.labels.create.vehicleinfo")}</Typography.Title>
<Row>
<Col span={16}>
<Row gutter={[32, 32]}>
<Col {...colSpan}>
<JobsCreateVehicleInfoSearchComponent
loading={loading}
vehicles={vehicles}
/>
</Col>
<Col span={8}>
<Col {...colSpan}>
<JobsCreateVehicleInfoNewComponent />
</Col>
</Row>

View File

@@ -9,9 +9,11 @@ export default function JobsCreateVehicleInfoContainer({ form }) {
const [state] = useContext(JobCreateContext);
const { loading, error, data } = useQuery(SEARCH_VEHICLE_BY_VIN, {
variables: { vin: `%${state.vehicle.search}%` },
skip: !state.vehicle.search
skip: !state.vehicle.search,
});
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<JobsCreateVehicleInfoComponent
loading={loading}

View File

@@ -2,6 +2,7 @@ import { DatePicker, Form, Input, Checkbox } from "antd";
import React, { useContext } from "react";
import { useTranslation } from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function JobsCreateVehicleInfoNewComponent() {
const [state, setState] = useContext(JobCreateContext);
@@ -18,178 +19,181 @@ export default function JobsCreateVehicleInfoNewComponent() {
vehicle: {
...state.vehicle,
new: !state.vehicle.new,
selectedid: null
}
selectedid: null,
},
});
}}
>
}}>
{t("jobs.labels.create.newvehicle")}
</Checkbox>
<Form.Item
label={t("vehicles.fields.v_vin")}
name={["vehicle", "data", "v_vin"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.plate_no")}
name={["vehicle", "data", "plate_no"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.plate_st")}
name={["vehicle", "data", "plate_st"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_type")}
name={["vehicle", "data", "v_type"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_trimcode")}
name={["vehicle", "data", "v_trimcode"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_tone")}
name={["vehicle", "data", "v_tone"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_bstyle")}
name={["vehicle", "data", "v_bstyle"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_stage")}
name={["vehicle", "data", "v_stage"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_prod_dt")}
name={["vehicle", "data", "v_prod_dt"]}
>
<DatePicker disabled={!state.vehicle.new} />
</Form.Item>
{
//TODO Add handling for paint code json
}
<Form.Item
label={t("vehicles.fields.v_paint_codes")}
name={["vehicle", "data", "v_paint_codes"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_options")}
name={["vehicle", "data", "v_options"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_yr")}
name={["vehicle", "data", "v_model_yr"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_desc")}
name={["vehicle", "data", "v_model_desc"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.trim_color")}
name={["vehicle", "data", "trim_color"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_mldgcode")}
name={["vehicle", "data", "v_mldgcode"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_makecode")}
name={["vehicle", "data", "v_makecode"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_make_desc")}
name={["vehicle", "data", "v_make_desc"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_engine")}
name={["vehicle", "data", "v_engine"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_cond")}
name={["vehicle", "data", "v_cond"]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_color")}
name={["vehicle", "data", "v_color"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required")
}
]}
>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<LayoutFormRow header={t("vehicles.forms.detail")} grow>
<Form.Item
label={t("vehicles.fields.v_vin")}
name={["vehicle", "data", "v_vin"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_color")}
name={["vehicle", "data", "v_color"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_yr")}
name={["vehicle", "data", "v_model_yr"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_make_desc")}
name={["vehicle", "data", "v_make_desc"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_desc")}
name={["vehicle", "data", "v_model_desc"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("vehicles.forms.registration")} grow>
<Form.Item
label={t("vehicles.fields.plate_st")}
name={["vehicle", "data", "plate_st"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.plate_no")}
name={["vehicle", "data", "plate_no"]}
rules={[
{
required: state.vehicle.new,
message: t("general.validation.required"),
},
]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("vehicles.forms.misc")} grow>
<Form.Item
label={t("vehicles.fields.v_type")}
name={["vehicle", "data", "v_type"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_trimcode")}
name={["vehicle", "data", "v_trimcode"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_tone")}
name={["vehicle", "data", "v_tone"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_bstyle")}
name={["vehicle", "data", "v_bstyle"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_stage")}
name={["vehicle", "data", "v_stage"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_prod_dt")}
name={["vehicle", "data", "v_prod_dt"]}>
<DatePicker disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_paint_codes")}
name={["vehicle", "data", "v_paint_codes"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_options")}
name={["vehicle", "data", "v_options"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.trim_color")}
name={["vehicle", "data", "trim_color"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_mldgcode")}
name={["vehicle", "data", "v_mldgcode"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_makecode")}
name={["vehicle", "data", "v_makecode"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_engine")}
name={["vehicle", "data", "v_engine"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow grow>
<Form.Item
label={t("vehicles.fields.v_cond")}
name={["vehicle", "data", "v_cond"]}>
<Input disabled={!state.vehicle.new} />
</Form.Item>
</LayoutFormRow>
</div>
);
}

View File

@@ -7,12 +7,12 @@ import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
export default function JobsCreateVehicleInfoSearchComponent({
loading,
vehicles
vehicles,
}) {
const [state, setState] = useContext(JobCreateContext);
const [tableState, setTableState] = useState({
sortedInfo: {},
filteredInfo: { text: "" }
filteredInfo: { text: "" },
});
const { t } = useTranslation();
@@ -28,7 +28,7 @@ export default function JobsCreateVehicleInfoSearchComponent({
tableState.sortedInfo.order,
render: (text, record) => (
<Link to={"/manage/vehicles/" + record.id}>{record.v_vin}</Link>
)
),
},
{
title: t("vehicles.fields.description"),
@@ -38,7 +38,7 @@ export default function JobsCreateVehicleInfoSearchComponent({
return (
<span>{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}</span>
);
}
},
},
{
title: t("vehicles.fields.plate_no"),
@@ -46,56 +46,59 @@ export default function JobsCreateVehicleInfoSearchComponent({
key: "plate",
render: (text, record) => {
return <span>{`${record.plate_st} | ${record.plate_no}`}</span>;
}
}
},
},
];
const handleTableChange = (pagination, filters, sorter) => {
setTableState({ ...tableState, filteredInfo: filters, sortedInfo: sorter });
};
//TODO Implement searching & pagination
return (
<Table
loading={loading}
title={() => {
return (
<Input.Search
placeholder="Search..."
onSearch={value => {
setState({
...state,
vehicle: { ...state.vehicle, search: value }
});
}}
enterButton
/>
<div className='imex-table-header'>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onSearch={(value) => {
setState({
...state,
vehicle: { ...state.vehicle, search: value },
});
}}
enterButton
/>
</div>
);
}}
size="small"
size='small'
scroll={{ x: true }}
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
rowKey='id'
dataSource={vehicles}
onChange={handleTableChange}
rowSelection={{
onSelect: props => {
onSelect: (props) => {
setState({
...state,
vehicle: {
...state.vehicle,
new: false,
selectedid: props.id,
vehicleObj: props
}
vehicleObj: props,
},
});
},
type: "radio",
selectedRowKeys: [state.vehicle.selectedid]
selectedRowKeys: [state.vehicle.selectedid],
}}
onRow={(record, rowIndex) => {
return {
onClick: event => {
onClick: (event) => {
if (record) {
if (record.id) {
setState({
@@ -104,8 +107,8 @@ export default function JobsCreateVehicleInfoSearchComponent({
...state.vehicle,
new: false,
selectedid: record.id,
vehicleObj: record
}
vehicleObj: record,
},
});
return;
@@ -113,9 +116,9 @@ export default function JobsCreateVehicleInfoSearchComponent({
}
setState({
...state,
vehicle: { ...state.vehicle, selectedid: null, vehicleObj: null }
vehicle: { ...state.vehicle, selectedid: null, vehicleObj: null },
});
}
},
};
}}
/>

View File

@@ -1,4 +1,4 @@
import { DatePicker, Form } from "antd";
import { Form } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import DateTimePicker from "../form-date-time-picker/form-date-time-picker.component";

View File

@@ -167,7 +167,6 @@ export default function JobsList({ refetch, loading, jobs, total }) {
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
console.log("handleTableChange -> sorter", sorter);
search.page = pagination.current;
search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order;
@@ -178,13 +177,26 @@ export default function JobsList({ refetch, loading, jobs, total }) {
<div>
<Table
loading={loading}
size='small'
scroll={{ x: true }}
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey='id'
dataSource={jobs}
onChange={handleTableChange}
title={() => {
return (
<div style={{ display: "flex" }}>
<div className='imex-table-header'>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onSearch={(value) => {
search.search = value;
@@ -195,17 +207,6 @@ export default function JobsList({ refetch, loading, jobs, total }) {
</div>
);
}}
size="small"
pagination={{
position: "top",
pageSize: 25,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
dataSource={jobs}
onChange={handleTableChange}
/>
</div>
);

View File

@@ -261,7 +261,7 @@ export function JobsList({ bodyshop }) {
onChange={(e) => {
setSearchText(e.target.value);
}}
vale={searchText}
value={searchText}
enterButton
/>
</div>

View File

@@ -2,10 +2,17 @@ import React from "react";
import { Row, Col, Typography } from "antd";
import "./layout-form-row.styles.scss";
export default function LayoutFormRow({ header, children }) {
export default function LayoutFormRow({ header, children, grow = false }) {
if (!!!children.length) {
//We have only one element. It's going to get the whole thing.
return children;
return (
<div className='imex-form-row'>
{header ? (
<Typography.Title level={4}>{header}</Typography.Title>
) : null}
{children}
</div>
);
}
const rowGutter = { gutter: [16, 16] };
@@ -15,16 +22,16 @@ export default function LayoutFormRow({ header, children }) {
span: 24,
},
sm: {
span: 12,
span: !grow ? 12 : Math.max(12, 24 / children.length),
},
md: {
span: 8,
span: !grow ? 8 : Math.max(8, 24 / children.length),
},
lg: {
span: 6,
span: !grow ? 6 : Math.max(6, 24 / children.length),
},
xl: {
span: 4,
span: !grow ? 4 : Math.max(4, 24 / children.length),
},
};
};

View File

@@ -1,75 +1,124 @@
import { Button, Col, Form, Input, Row, Switch } from "antd";
import { Button, Form, Input, Switch } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import FormItemEmail from "../form-items-formatted/email-form-item.component";
import FormItemPhone from "../form-items-formatted/phone-form-item.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function OwnerDetailFormComponent({ form }) {
const { t } = useTranslation();
const { getFieldValue } = form;
return (
<div>
<Button type='primary' key='submit' htmlType='submit'>
{t("general.actions.save")}
</Button>
<Row>
<Col span={8}>
<Form.Item label={t("owners.fields.ownr_ln")} name='ownr_ln'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_fn")} name='ownr_fn'>
<Input />
</Form.Item>
<Form.Item
label={t("owners.fields.allow_text_message")}
name='allow_text_message'
valuePropName='checked'>
<Switch />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_addr1")} name='ownr_addr1'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_addr2")} name='ownr_addr2'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_city")} name='ownr_city'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_ctry")} name='ownr_ctry'>
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
label={t("owners.fields.ownr_ea")}
name='ownr_ea'
rules={[
{
type: "email",
message: "This is not a valid email address."
}
]}>
<FormItemEmail email={getFieldValue("ownr_ea")} />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_ph1")} name='ownr_ph1'>
<FormItemPhone customInput={Input} />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_st")} name='ownr_st'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_zip")} name='ownr_zip'>
<Input />
</Form.Item>
<Form.Item
label={t("owners.fields.preferred_contact")}
name='preferred_contact'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_title")} name='ownr_title'>
<Input />
</Form.Item>
</Col>
</Row>
<div className='imex-flex-row imex-flex-row__flex-space-around'>
<Button
className='imex-flex-row__margin-large'
type='primary'
key='submit'
htmlType='submit'>
{t("general.actions.save")}
</Button>
<div className='imex-flex-row__grow imex-flex-row__margin-large'>
<FormFieldsChanged form={form} />
</div>
</div>
<LayoutFormRow header={t("owners.forms.name")}>
<Form.Item label={t("owners.fields.ownr_title")} name='ownr_title'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_ln")} name='ownr_ln'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_fn")} name='ownr_fn'>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_co_nm")} name='ownr_co_nm'>
<Input />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("owners.forms.address")}>
<Form.Item
label={t("owners.fields.ownr_addr1")}
name='ownr_addr1'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_addr2")} name='ownr_addr2'>
<Input />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_city")}
name='ownr_city'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_st")}
name='ownr_st'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_zip")}
name='ownr_zip'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_ctry")} name='ownr_ctry'>
<Input />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("owners.forms.contact")}>
<Form.Item
label={t("owners.fields.allow_text_message")}
name='allow_text_message'
valuePropName='checked'>
<Switch />
</Form.Item>
<Form.Item
label={t("owners.fields.ownr_ea")}
name='ownr_ea'
rules={[
{
type: "email",
message: "This is not a valid email address.",
},
]}>
<FormItemEmail email={getFieldValue("ownr_ea")} />
</Form.Item>
<Form.Item label={t("owners.fields.ownr_ph1")} name='ownr_ph1'>
<FormItemPhone customInput={Input} />
</Form.Item>
<Form.Item
label={t("owners.fields.preferred_contact")}
name='preferred_contact'>
<Input />
</Form.Item>
</LayoutFormRow>
</div>
);
}

View File

@@ -11,12 +11,12 @@ function OwnerDetailFormContainer({ owner, refetch }) {
const [updateOwner] = useMutation(UPDATE_OWNER);
const handleFinish = values => {
const handleFinish = (values) => {
updateOwner({
variables: { ownerId: owner.id, owner: values }
}).then(r => {
variables: { ownerId: owner.id, owner: values },
}).then((r) => {
notification["success"]({
message: t("owners.successes.save")
message: t("owners.successes.save"),
});
//TODO Better way to reset the field decorators?
if (refetch) refetch().then();
@@ -28,9 +28,9 @@ function OwnerDetailFormContainer({ owner, refetch }) {
<Form
form={form}
onFinish={handleFinish}
autoComplete="off"
initialValues={owner}
>
autoComplete='off'
layout='vertical'
initialValues={owner}>
<OwnerDetailFormComponent form={form} />
</Form>
);

View File

@@ -9,7 +9,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
import OwnerDetailUpdateJobsComponent from "../owner-detail-update-jobs/owner-detail-update-jobs.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
bodyshop: selectBodyshop,
});
function OwnerDetailJobsComponent({ bodyshop, owner }) {
@@ -25,7 +25,7 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
<Link to={`/manage/jobs/${record.id}`}>
{record.ro_number ? record.ro_number : `EST ${record.est_number}`}
</Link>
)
),
},
{
title: t("jobs.fields.vehicle"),
@@ -35,17 +35,17 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
<Link to={`/manage/vehicles/${record.vehicleid}`}>
{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc}`}
</Link>
)
),
},
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no"
key: "clm_no",
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status"
key: "status",
},
{
@@ -54,8 +54,8 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
key: "clm_total",
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
)
}
),
},
];
return (
@@ -70,20 +70,31 @@ function OwnerDetailJobsComponent({ bodyshop, owner }) {
</div>
)}
pagination={{ position: "bottom" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
scroll={{ x: true }}
rowKey='id'
dataSource={owner.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map(i => i.id) : []);
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.open_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: record => ({
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.open_statuses
? !bodyshop.md_ro_statuses.open_statuses.includes(record.status)
: true
})
: true,
}),
}}
/>
);

View File

@@ -1,4 +1,5 @@
import { Input, Table } from "antd";
import { SyncOutlined } from "@ant-design/icons";
import { Button, Input, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
@@ -8,7 +9,7 @@ import { alphaSort } from "../../utils/sorters";
export default function OwnersListComponent({ loading, owners, refetch }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" }
filteredInfo: { text: "" },
});
const { t } = useTranslation();
@@ -18,17 +19,14 @@ export default function OwnersListComponent({ loading, owners, refetch }) {
title: t("owners.fields.name"),
dataIndex: "name",
key: "name",
// onFilter: (value, record) => record.ro_number.includes(value),
// filteredValue: state.filteredInfo.text || null,
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
sortOrder:
state.sortedInfo.columnKey === "name" && state.sortedInfo.order,
render: (text, record) => (
<Link to={"/manage/owners/" + record.id}>
{`${record.ownr_fn} ${record.ownr_ln}`}
</Link>
)
),
},
{
title: t("owners.fields.ownr_ph1"),
@@ -39,12 +37,12 @@ export default function OwnersListComponent({ loading, owners, refetch }) {
state.sortedInfo.columnKey === "ownr_ph1" && state.sortedInfo.order,
render: (text, record) => {
return <PhoneFormatter>{record.ownr_ph1}</PhoneFormatter>;
}
},
},
{
title: t("owners.fields.ownr_ea"),
dataIndex: "ownr_ea",
key: "ownr_ea"
key: "ownr_ea",
},
{
title: t("owners.fields.address"),
@@ -52,36 +50,43 @@ export default function OwnersListComponent({ loading, owners, refetch }) {
key: "address",
render: (text, record) => {
return (
<div>{`${record.ownr_addr1 || ""} ${record.ownr_addr2 ||
""} ${record.ownr_city || ""} ${record.ownr_st ||
""} ${record.ownr_zip || ""}`}</div>
<div>{`${record.ownr_addr1 || ""} ${record.ownr_addr2 || ""} ${
record.ownr_city || ""
} ${record.ownr_st || ""} ${record.ownr_zip || ""}`}</div>
);
}
}
},
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
//TODO Implement searching & pagination
return (
<Table
loading={loading}
title={() => {
return (
<Input.Search
placeholder="Search..."
onSearch={value => {
console.log(value);
}}
enterButton
/>
<div className='imex-table-header'>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onChange={(e) => {
//setSearchText(e.target.value);
}}
//vale={searchText}
enterButton
/>
</div>
);
}}
size="small"
size='small'
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
rowKey='id'
scroll={{ x: true }}
dataSource={owners}
onChange={handleTableChange}
/>

View File

@@ -1,15 +1,15 @@
import React from "react";
import { useQuery } from "@apollo/react-hooks";
import React from "react";
import { QUERY_ALL_OWNERS } from "../../graphql/owners.queries";
import AlertComponent from "../alert/alert.component";
import OwnersListComponent from "./owners-list.component";
export default function OwnersListContainer() {
const { loading, error, data, refetch } = useQuery(QUERY_ALL_OWNERS, {
fetchPolicy: "network-only"
fetchPolicy: "network-only",
});
if (error) return <AlertComponent message={error.message} type="error" />;
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<OwnersListComponent
loading={loading}

View File

@@ -4,6 +4,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
import PhoneFormatter from "../../utils/PhoneFormatter";
import { Link } from "react-router-dom";
import { useTranslation } from "react-i18next";
import DataLabel from "../data-label/data-label.component";
export default function ScheduleEventComponent({ event, handleCancel }) {
const { t } = useTranslation();
@@ -23,59 +24,58 @@ export default function ScheduleEventComponent({ event, handleCancel }) {
</span>
</div>
)}
{event.job ? (
<div>
<div>{`${t("jobs.fields.ro_number")}: ${
(event.job && event.job.ro_number) || ""
}`}</div>
<div>
{t("jobs.fields.clm_total")}:
<DataLabel label={t("jobs.fields.ro_number")}>
{(event.job && event.job.ro_number) || ""}
</DataLabel>
<DataLabel label={t("jobs.fields.clm_total")}>
<CurrencyFormatter>
{(event.job && event.job.clm_total) || ""}
</CurrencyFormatter>
</div>
<div>{`${t("jobs.fields.clm_no")}: ${
(event.job && event.job.clm_no) || ""
}`}</div>
<div>
{t("jobs.fields.ownr_ea")}:{(event.job && event.job.ownr_ea) || ""}
</div>
<div>
{t("jobs.fields.ownr_ph1")}:
</DataLabel>
<DataLabel hideIfNull label={t("jobs.fields.ins_co_nm")}>
{(event.job && event.job.ins_co_nm) || ""}
</DataLabel>
<DataLabel hideIfNull label={t("jobs.fields.clm_no")}>
{(event.job && event.job.clm_no) || ""}
</DataLabel>
<DataLabel label={t("jobs.fields.ownr_ea")}>
{(event.job && event.job.ownr_ea) || ""}
</DataLabel>
<DataLabel label={t("jobs.fields.ownr_ph1")}>
<PhoneFormatter>
{(event.job && event.job.ownr_ph1) || ""}
</PhoneFormatter>
</div>
</DataLabel>
</div>
) : null}
{
//TODO Add phone 1 MessagingActionTypes.
}
{event.job ? (
<Link to={`/manage/jobs/${event.job && event.job.id}`}>
<Button>{t("appointments.actions.viewjob")}</Button>
</Link>
) : null}
<Button onClick={() => handleCancel(event.id)} disabled={event.arrived}>
{t("appointments.actions.cancel")}
</Button>
<Button disabled={event.arrived}>
{
//TODO Add reschedule Func.
}
{t("appointments.actions.reschedule")}
</Button>
{event.isintake ? (
<Link
to={{
pathname: `/manage/jobs/${event.job && event.job.id}/intake`,
search: `?appointmentId=${event.id}`,
}}>
<Button disabled={event.arrived}>
{t("appointments.actions.intake")}
</Button>
</Link>
) : null}
<div className='imex-flex-row'>
{event.job ? (
<Link to={`/manage/jobs/${event.job && event.job.id}`}>
<Button>{t("appointments.actions.viewjob")}</Button>
</Link>
) : null}
<Button onClick={() => handleCancel(event.id)} disabled={event.arrived}>
{t("appointments.actions.cancel")}
</Button>
<Button disabled={event.arrived}>
{t("appointments.actions.reschedule")}
</Button>
{event.isintake ? (
<Link
to={{
pathname: `/manage/jobs/${event.job && event.job.id}/intake`,
search: `?appointmentId=${event.id}`,
}}>
<Button disabled={event.arrived}>
{t("appointments.actions.intake")}
</Button>
</Link>
) : null}
</div>
</div>
);
@@ -96,14 +96,9 @@ export default function ScheduleEventComponent({ event, handleCancel }) {
</div>
);
const Load = (
<div className='load'>
<Progress percent={77} showInfo={false} />
</div>
);
return (
<Popover content={popoverContent}>
<div>{event.allDay ? Load : RegularEvent}</div>
<Popover trigger='click' content={popoverContent}>
{RegularEvent}
</Popover>
);
}

View File

@@ -1,94 +1,160 @@
import { Button, Col, DatePicker, Form, Input, Row } from "antd";
import { Button, DatePicker, Form, Input, InputNumber } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
export default function VehicleDetailFormComponent() {
import FormFieldsChanged from "../form-fields-changed-alert/form-fields-changed-alert.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component";
export default function VehicleDetailFormComponent({ form }) {
const { t } = useTranslation();
return (
<div>
<Button type="primary" key="submit" htmlType="submit">
{t("general.actions.save")}
</Button>
<Row>
<Col span={8}>
<Form.Item label={t("vehicles.fields.v_vin")} name="v_vin">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.plate_no")} name="plate_no">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.plate_st")} name="plate_st">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_type")} name="v_type">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_trimcode")} name="v_trimcode">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_tone")} name="v_tone">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_bstyle")} name="v_bstyle">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("vehicles.fields.v_stage")} name="v_stage">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_prod_dt")} name="v_prod_dt">
<DatePicker />
</Form.Item>
{
//TODO Add handling for paint code json
}
<Form.Item
label={t("vehicles.fields.v_paint_codes")}
name="v_paint_codes"
>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_options")} name="v_options">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_model_yr")} name="v_model_yr">
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_desc")}
name="v_model_desc"
>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.trim_color")} name="trim_color">
<Input />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item label={t("vehicles.fields.v_mldgcode")} name="v_mldgcode">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_makecode")} name="v_makecode">
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_make_desc")}
name="v_make_desc"
>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_engine")} name="v_engine">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_cond")} name="v_cond">
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_color")} name="v_color">
<Input />
</Form.Item>
</Col>
</Row>
<div className='imex-flex-row imex-flex-row__flex-space-around'>
<Button
className='imex-flex-row__margin-large'
type='primary'
key='submit'
htmlType='submit'>
{t("general.actions.save")}
</Button>
<div className='imex-flex-row__grow imex-flex-row__margin-large'>
<FormFieldsChanged form={form} />
</div>
</div>
<LayoutFormRow header={t("vehicles.forms.detail")}>
<Form.Item
label={t("vehicles.fields.v_model_yr")}
name='v_model_yr'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<InputNumber precision={0} />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_make_desc")}
name='v_make_desc'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_model_desc")}
name='v_model_desc'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_color")}
name='v_color'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.v_vin")}
name='v_vin'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("vehicles.forms.registration")}>
<Form.Item
label={t("vehicles.fields.plate_st")}
name='plate_st'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
<Form.Item
label={t("vehicles.fields.plate_no")}
name='plate_no'
rules={[
{
required: true,
message: t("general.validation.required"),
},
]}>
<Input />
</Form.Item>
</LayoutFormRow>
<LayoutFormRow header={t("vehicles.forms.misc")}>
<Form.Item label={t("vehicles.fields.v_type")} name='v_type'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_trimcode")} name='v_trimcode'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_tone")} name='v_tone'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_bstyle")} name='v_bstyle'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_stage")} name='v_stage'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_prod_dt")} name='v_prod_dt'>
<DatePicker />
</Form.Item>
{
//TODO Add handling for paint code json
}
<Form.Item
label={t("vehicles.fields.v_paint_codes")}
name='v_paint_codes'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_options")} name='v_options'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.trim_color")} name='trim_color'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_mldgcode")} name='v_mldgcode'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_makecode")} name='v_makecode'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_engine")} name='v_engine'>
<Input />
</Form.Item>
<Form.Item label={t("vehicles.fields.v_cond")} name='v_cond'>
<Input />
</Form.Item>
</LayoutFormRow>
</div>
);
}

View File

@@ -11,12 +11,12 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
const [updateVehicle] = useMutation(UPDATE_VEHICLE);
const [form] = Form.useForm();
const handleFinish = values => {
const handleFinish = (values) => {
updateVehicle({
variables: { vehId: vehicle.id, vehicle: values }
}).then(r => {
variables: { vehId: vehicle.id, vehicle: values },
}).then((r) => {
notification["success"]({
message: t("vehicles.successes.save")
message: t("vehicles.successes.save"),
});
//TODO Better way to reset the field decorators?
if (refetch) refetch();
@@ -27,13 +27,13 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
<Form
onFinish={handleFinish}
form={form}
autoComplete="off"
autoComplete='off'
layout='vertical'
initialValues={{
...vehicle,
v_prod_dt: vehicle.v_prod_dt ? moment(vehicle.v_prod_dt) : null
}}
>
<VehicleDetailFormComponent />
v_prod_dt: vehicle.v_prod_dt ? moment(vehicle.v_prod_dt) : null,
}}>
<VehicleDetailFormComponent form={form} />
</Form>
);
}

View File

@@ -1,15 +1,15 @@
import React, { useState } from "react";
import { Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import { connect } from "react-redux";
import { Link } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter";
import VehicleDetailUpdateJobsComponent from "../vehicle-detail-update-jobs/vehicle-detail-update-jobs.component";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop
bodyshop: selectBodyshop,
});
export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
@@ -26,7 +26,7 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
<Link to={`/manage/jobs/${record.id}`}>
{record.ro_number ? record.ro_number : `EST ${record.est_number}`}
</Link>
)
),
},
{
title: t("jobs.fields.owner"),
@@ -36,17 +36,17 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
<Link to={`/manage/owners/${record.owner.id}`}>
{`${record.ownr_fn} ${record.ownr_ln}`}
</Link>
)
),
},
{
title: t("jobs.fields.clm_no"),
dataIndex: "clm_no",
key: "clm_no"
key: "clm_no",
},
{
title: t("jobs.fields.status"),
dataIndex: "status",
key: "status"
key: "status",
},
{
@@ -55,8 +55,8 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
key: "clm_total",
render: (text, record) => (
<CurrencyFormatter>{record.clm_total}</CurrencyFormatter>
)
}
),
},
];
return (
@@ -71,20 +71,31 @@ export function VehicleDetailJobsComponent({ vehicle, bodyshop }) {
</div>
)}
pagination={{ position: "bottom" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
rowKey='id'
scroll={{ x: true }}
dataSource={vehicle.jobs}
rowSelection={{
onSelect: (record, selected, selectedRows) => {
setSelectedJobs(selectedRows ? selectedRows.map(i => i.id) : []);
setSelectedJobs(selectedRows ? selectedRows.map((i) => i.id) : []);
},
onSelectAll: (selected, selectedRows, changeRows) => {
setSelectedJobs(
selectedRows
? selectedRows
.filter((i) =>
bodyshop.md_ro_statuses.open_statuses.includes(i.status)
)
.map((i) => i.id)
: []
);
},
selectedRowKeys: selectedJobs,
getCheckboxProps: record => ({
getCheckboxProps: (record) => ({
disabled: bodyshop.md_ro_statuses.open_statuses
? !bodyshop.md_ro_statuses.open_statuses.includes(record.status)
: true
})
: true,
}),
}}
/>
);

View File

@@ -1,4 +1,5 @@
import { Input, Table } from "antd";
import { SyncOutlined } from "@ant-design/icons";
import { Button, Input, Table } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
@@ -7,7 +8,7 @@ import { alphaSort } from "../../utils/sorters";
export default function VehiclesListComponent({ loading, vehicles, refetch }) {
const [state, setState] = useState({
sortedInfo: {},
filteredInfo: { text: "" }
filteredInfo: { text: "" },
});
const { t } = useTranslation();
@@ -17,15 +18,13 @@ export default function VehiclesListComponent({ loading, vehicles, refetch }) {
title: t("vehicles.fields.v_vin"),
dataIndex: "v_vin",
key: "v_vin",
// onFilter: (value, record) => record.ro_number.includes(value),
// filteredValue: state.filteredInfo.text || null,
sorter: (a, b) => alphaSort(a.v_vin, b.v_vin),
sortOrder:
state.sortedInfo.columnKey === "v_vin" && state.sortedInfo.order,
render: (text, record) => (
<Link to={"/manage/vehicles/" + record.id}>{record.v_vin}</Link>
)
),
},
{
title: t("vehicles.fields.description"),
@@ -35,7 +34,7 @@ export default function VehiclesListComponent({ loading, vehicles, refetch }) {
return (
<span>{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}</span>
);
}
},
},
{
title: t("vehicles.fields.plate_no"),
@@ -43,32 +42,40 @@ export default function VehiclesListComponent({ loading, vehicles, refetch }) {
key: "plate",
render: (text, record) => {
return <span>{`${record.plate_st} | ${record.plate_no}`}</span>;
}
}
},
},
];
const handleTableChange = (pagination, filters, sorter) => {
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
};
//TODO Implement searching & pagination
return (
<Table
loading={loading}
title={() => {
return (
<Input.Search
placeholder="Search..."
onSearch={value => {
console.log(value);
}}
enterButton
/>
<div className='imex-table-header'>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
className='imex-table-header__search'
placeholder={t("general.labels.search")}
onChange={(e) => {
//setSearchText(e.target.value);
}}
//vale={searchText}
enterButton
/>
</div>
);
}}
size="small"
size='small'
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
columns={columns}
rowKey='id'
scroll={{ x: true }}
dataSource={vehicles}
onChange={handleTableChange}
/>

View File

@@ -28,6 +28,7 @@ export const QUERY_ALL_ACTIVE_APPOINTMENTS = gql`
clm_total
id
clm_no
ins_co_nm
v_model_yr
v_make_desc
v_model_desc

View File

@@ -1,6 +1,12 @@
import React from "react";
import CourtesyCarsListComponent from "../../components/courtesy-cars-list/courtesy-cars-list.component";
export default function CourtesyCarsPageComponent({ loading, data }) {
return <CourtesyCarsListComponent loading={loading} courtesycars={data} />;
export default function CourtesyCarsPageComponent({ loading, data, refetch }) {
return (
<CourtesyCarsListComponent
loading={loading}
courtesycars={data}
refetch={refetch}
/>
);
}

View File

@@ -12,7 +12,7 @@ const mapDispatchToProps = (dispatch) => ({
});
export function CourtesyCarsPageContainer({ setBreadcrumbs }) {
const { loading, error, data } = useQuery(QUERY_ALL_CC);
const { loading, error, data, refetch } = useQuery(QUERY_ALL_CC);
const { t } = useTranslation();
useEffect(() => {
document.title = t("titles.courtesycars");
@@ -21,11 +21,12 @@ export function CourtesyCarsPageContainer({ setBreadcrumbs }) {
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
]);
}, [setBreadcrumbs, t]);
if (error) return <AlertComponent message={error.message} type="error" />;
if (error) return <AlertComponent message={error.message} type='error' />;
return (
<CourtesyCarsPageComponent
loading={loading}
data={(data && data.courtesycars) || []}
refetch={refetch}
/>
);
}

View File

@@ -19,18 +19,18 @@ export default function JobsCreateComponent({ form }) {
title: t("jobs.labels.create.vehicleinfo"),
content: <JobsCreateVehicleInfoContainer />,
validation: !!state.vehicle.new || !!state.vehicle.selectedid,
error: t("vehicles.errors.selectexistingornew")
error: t("vehicles.errors.selectexistingornew"),
},
{
title: t("jobs.labels.create.ownerinfo"),
content: <JobsCreateOwnerInfoContainer />,
validation: !!state.owner.new || !!state.owner.selectedid,
error: t("owners.errors.selectexistingornew")
error: t("owners.errors.selectexistingornew"),
},
{
title: t("jobs.labels.create.jobinfo"),
content: <JobsCreateJobsInfo form={form} />
}
content: <JobsCreateJobsInfo form={form} />,
},
];
const next = () => {
@@ -43,19 +43,15 @@ export default function JobsCreateComponent({ form }) {
const ProgressButtons = () => {
return (
<div>
{pageIndex > 0 && (
<Button style={{ margin: 8 }} onClick={() => prev()}>
Previous
</Button>
)}
<div style={{ margin: "1rem" }}>
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
{pageIndex < steps.length - 1 && (
<Button
type='primary'
onClick={() => {
form
.validateFields()
.then(r => {
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
next();
@@ -63,7 +59,7 @@ export default function JobsCreateComponent({ form }) {
setErrorMessage(steps[pageIndex].error);
}
})
.catch(error => console.log("error", error));
.catch((error) => console.log("error", error));
}}>
Next
</Button>
@@ -85,7 +81,7 @@ export default function JobsCreateComponent({ form }) {
status='success'
title={t("jobs.successes.creatednoclick")}
subTitle={t("jobs.successes.created_subtitle", {
est_number: state.newJobEstNum
est_number: state.newJobEstNum,
})}
extra={[
<Link to={`/manage/jobs/${state.newJobId}`} key='gotojob'>
@@ -93,7 +89,7 @@ export default function JobsCreateComponent({ form }) {
</Link>,
<Link to={`/manage/jobs/`} key='gotojoblist'>
<Button>{t("menus.header.activejobs")}</Button>
</Link>
</Link>,
]}
/>
</div>
@@ -108,7 +104,7 @@ export default function JobsCreateComponent({ form }) {
onClick={() => {
form
.validateFields()
.then(r => {
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
setPageIndex(idx);
@@ -116,7 +112,7 @@ export default function JobsCreateComponent({ form }) {
setErrorMessage(steps[pageIndex].error);
}
})
.catch(error => console.log("error", error));
.catch((error) => console.log("error", error));
}}
/>
))}
@@ -130,7 +126,12 @@ export default function JobsCreateComponent({ form }) {
) : null}
{steps.map((item, idx) => (
<div key={idx} style={{ display: idx === pageIndex ? "" : "none" }}>
<div
key={idx}
style={{
display: idx === pageIndex ? "" : "none",
margin: "1rem",
}}>
{item.content}
</div>
))}

View File

@@ -74,6 +74,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs }) {
};
const handleFinish = (values) => {
console.log("handleFinish -> values", values);
let job = Object.assign(
{},
values,
@@ -86,13 +87,14 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs }) {
ownerid: state.owner.selectedid || null,
},
{
status: bodyshop.md_ro_statuses.default_imported || "Open*", //Pull from redux store.
status: bodyshop.md_ro_statuses.default_imported || "Open*",
shopid: bodyshop.id,
}
);
//TODO Logic to ensure the owner is actually fetched.
console.log("job", job);
let ownerData;
if (!!job.owner) {
if (!!!job.ownerid) {
ownerData = job.owner.data;
ownerData.shopid = bodyshop.id;
delete ownerData.allow_text_message;
@@ -103,7 +105,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs }) {
delete ownerData.id;
delete ownerData.__typename;
}
if (!!job.vehicle) {
if (!!!job.vehicleid) {
delete job.vehicleid;
job.vehicle.data.shopid = bodyshop.id;
job.plate_no = job.vehicle.data.plate_no;
@@ -114,8 +116,6 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs }) {
job.v_make_desc = job.vehicle.data.v_make_desc;
job.v_color = job.vehicle.data.v_color;
} else {
//Vehicle selected.
job.vehicle.data.shopid = bodyshop.id;
job.plate_no = state.vehicle.vehicleObj.plate_no;
job.plate_st = state.vehicle.vehicleObj.plate_st;
job.v_vin = state.vehicle.vehicleObj.v_vin;
@@ -131,7 +131,11 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs }) {
return (
<JobCreateContext.Provider value={contextState}>
<Form form={form} onFinish={handleFinish} autoComplete={"off"}>
<Form
form={form}
onFinish={handleFinish}
layout='vertical'
autoComplete={"off"}>
<JobsCreateComponent form={form} />
</Form>
</JobCreateContext.Provider>

View File

@@ -15,6 +15,7 @@ const mapDispatchToProps = (dispatch) => ({
export function VehicleDetailContainer({ match, setBreadcrumbs }) {
const { vehId } = match.params;
const { t } = useTranslation();
const { loading, data, error, refetch } = useQuery(QUERY_VEHICLE_BY_ID, {
variables: { id: vehId },
fetchPolicy: "network-only",

View File

@@ -686,7 +686,6 @@
"availablenew": "Available New Jobs",
"availablesupplements": "Available Supplements",
"cards": {
"appraiser": "Appraiser",
"customer": "Customer Information",
"damage": "Area of Damage",
"dates": "Dates",
@@ -855,6 +854,7 @@
"ownr_addr1": "Address",
"ownr_addr2": "Address 2",
"ownr_city": "City",
"ownr_co_nm": "Owner Co. Name",
"ownr_ctry": "Country",
"ownr_ea": "Email",
"ownr_fn": "First Name",
@@ -865,6 +865,11 @@
"ownr_zip": "Zip/Postal Code",
"preferred_contact": "Preferred Contact Method"
},
"forms": {
"address": "Address",
"contact": "Contact Information",
"name": "Owner Details"
},
"labels": {
"create_new": "Create a new owner record.",
"existing_owners": "Existing Owners",
@@ -1093,6 +1098,11 @@
"v_type": "Type",
"v_vin": "Vehicle Identification Number"
},
"forms": {
"detail": "Vehicle Details",
"misc": "Miscellaneous",
"registration": "Registration"
},
"labels": {
"updatevehicle": "Update Vehicle Information"
},

View File

@@ -686,7 +686,6 @@
"availablenew": "",
"availablesupplements": "",
"cards": {
"appraiser": "Tasador",
"customer": "Información al cliente",
"damage": "Área de Daño",
"dates": "fechas",
@@ -855,6 +854,7 @@
"ownr_addr1": "Dirección",
"ownr_addr2": "Dirección 2",
"ownr_city": "ciudad",
"ownr_co_nm": "",
"ownr_ctry": "País",
"ownr_ea": "Email",
"ownr_fn": "Nombre de pila",
@@ -865,6 +865,11 @@
"ownr_zip": "código postal",
"preferred_contact": "Método de Contacto Preferido"
},
"forms": {
"address": "",
"contact": "",
"name": ""
},
"labels": {
"create_new": "Crea un nuevo registro de propietario.",
"existing_owners": "Propietarios existentes",
@@ -1093,6 +1098,11 @@
"v_type": "Tipo",
"v_vin": "Número de identificación del vehículo"
},
"forms": {
"detail": "",
"misc": "",
"registration": ""
},
"labels": {
"updatevehicle": ""
},

View File

@@ -686,7 +686,6 @@
"availablenew": "",
"availablesupplements": "",
"cards": {
"appraiser": "Expert",
"customer": "Informations client",
"damage": "Zone de dommages",
"dates": "Rendez-vous",
@@ -855,6 +854,7 @@
"ownr_addr1": "Adresse",
"ownr_addr2": "Adresse 2 ",
"ownr_city": "Ville",
"ownr_co_nm": "",
"ownr_ctry": "Pays",
"ownr_ea": "Email",
"ownr_fn": "Prénom",
@@ -865,6 +865,11 @@
"ownr_zip": "Zip / code postal",
"preferred_contact": "Méthode de contact préférée"
},
"forms": {
"address": "",
"contact": "",
"name": ""
},
"labels": {
"create_new": "Créez un nouvel enregistrement de propriétaire.",
"existing_owners": "Propriétaires existants",
@@ -1093,6 +1098,11 @@
"v_type": "Type",
"v_vin": "Plaque d'immatriculation"
},
"forms": {
"detail": "",
"misc": "",
"registration": ""
},
"labels": {
"updatevehicle": ""
},