BOD-10 BOD-12 BOD-11 WIP for Manual Job Creation.

This commit is contained in:
Patrick Fic
2020-03-18 14:31:33 -07:00
parent ec53663a1d
commit d7afe7e43f
15 changed files with 643 additions and 37 deletions

View File

@@ -6670,6 +6670,95 @@
</concept_node>
</children>
</folder_node>
<folder_node>
<name>create</name>
<children>
<concept_node>
<name>jobinfo</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>newvehicle</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>ownerinfo</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>vehicleinfo</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>
<concept_node>
<name>creating_new_job</name>
<definition_loaded>false</definition_loaded>

View File

@@ -72,22 +72,6 @@ function InvoiceEnterModalContainer({
};
const handleFinish = values => {
console.log("values", values);
console.log(
"Assigned",
Object.assign(
{},
values,
{ jobid: roSearch.selectedId },
{ vendorid: vendorSearch.selectedId },
{
invoicelines: {
data: values.invoicelines.map(item => delete item.joblinename)
}
}
)
);
insertInvoice({
variables: {
invoice: [

View File

@@ -0,0 +1,43 @@
import { Checkbox, Col, Row, Typography } from "antd";
import React, { useContext } from "react";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import { useTranslation } from "react-i18next";
import JobsCreateVehicleInfoNewComponent from "./jobs-create-vehicle-info.new.component";
import JobsCreateVehicleInfoSearchComponent from "./jobs-create-vehicle-info.search.component";
export default function JobsCreateVehicleInfoComponent({ loading, vehicles }) {
const [state, setState] = useContext(JobCreateContext);
const { t } = useTranslation();
return (
<div>
<Typography.Title>{t("jobs.labels.create.vehicleinfo")}</Typography.Title>
<Row>
<Col span={16}>
<JobsCreateVehicleInfoSearchComponent
loading={loading}
vehicles={vehicles}
/>
</Col>
<Col span={8}>
<Checkbox
defaultChecked={state.vehicle.new}
checked={state.vehicle.new}
onChange={() => {
setState({
...state,
vehicle: {
...state.vehicle,
new: !state.vehicle.new,
selectedid: null
}
});
}}
>
{t("jobs.labels.create.newvehicle")}
</Checkbox>
<JobsCreateVehicleInfoNewComponent />
</Col>
</Row>
</div>
);
}

View File

@@ -0,0 +1,19 @@
import React, { useContext } from "react";
import JobsCreateVehicleInfoComponent from "./jobs-create-vehicle-info.component";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
import { SEARCH_VEHICLE_BY_VIN } from "../../graphql/vehicles.queries";
import { useQuery } from "react-apollo";
export default function JobsCreateVehicleInfoContainer({ form }) {
const [state, setState] = useContext(JobCreateContext);
const { loading, error, data } = useQuery(SEARCH_VEHICLE_BY_VIN, {
variables: { vin: `%${state.vehicle.search}%` },
skip: !state.vehicle.search
});
return (
<JobsCreateVehicleInfoComponent
loading={loading}
vehicles={data ? data.vehicles : null}
/>
);
}

View File

@@ -0,0 +1,179 @@
import { DatePicker, Form, Input } from "antd";
import React, { useContext } from "react";
import { useTranslation } from "react-i18next";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
export default function JobsCreateVehicleInfoNewComponent() {
const [state] = useContext(JobCreateContext);
const { t } = useTranslation();
return (
<div>
<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>
</div>
);
}

View File

@@ -0,0 +1,118 @@
import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import { Table, Input } from "antd";
import { Link } from "react-router-dom";
import { alphaSort } from "../../utils/sorters";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
export default function JobsCreateVehicleInfoSearchComponent({
loading,
vehicles
}) {
const [state, setState] = useContext(JobCreateContext);
const [tableState, setTableState] = useState({
sortedInfo: {},
filteredInfo: { text: "" }
});
const { t } = useTranslation();
const columns = [
{
title: t("vehicles.fields.v_vin"),
dataIndex: "v_vin",
key: "v_vin",
sorter: (a, b) => alphaSort(a.v_vin, b.v_vin),
sortOrder:
tableState.sortedInfo.columnKey === "v_vin" &&
tableState.sortedInfo.order,
render: (text, record) => (
<Link to={"/manage/vehicles/" + record.id}>{record.v_vin}</Link>
)
},
{
title: t("vehicles.fields.description"),
dataIndex: "description",
key: "description",
render: (text, record) => {
return (
<span>{`${record.v_model_yr} ${record.v_make_desc} ${record.v_model_desc} ${record.v_color}`}</span>
);
}
},
{
title: t("vehicles.fields.plate_no"),
dataIndex: "plate",
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
console.log("vehicles", vehicles);
return (
<Table
loading={loading}
title={() => {
return (
<Input.Search
placeholder="Search..."
onSearch={value => {
setState({
...state,
vehicle: { ...state.vehicle, search: value }
});
}}
enterButton
/>
);
}}
size="small"
pagination={{ position: "top" }}
columns={columns.map(item => ({ ...item }))}
rowKey="id"
dataSource={vehicles}
onChange={handleTableChange}
rowSelection={{
onSelect: props => {
setState({
...state,
vehicle: { ...state.vehicle, new: false, selectedid: props.id }
});
},
type: "radio",
selectedRowKeys: [state.vehicle.selectedid]
}}
onRow={(record, rowIndex) => {
return {
onClick: event => {
if (record) {
if (record.id) {
setState({
...state,
vehicle: {
...state.vehicle,
new: false,
selectedid: record.id
}
});
console.log("Should be clearing fields.");
return;
}
}
setState({
...state,
vehicle: { ...state.vehicle, selectedid: null }
});
}
};
}}
/>
);
}

View File

@@ -1,13 +1,13 @@
import axios from "axios";
import React, { useEffect, useState } from "react";
import Gallery from "react-grid-gallery";
import { Document, Page, pdfjs } from "react-pdf";
//import { Document, Page, pdfjs } from "react-pdf";
import DocumentsUploadContainer from "../documents-upload/documents-upload.container";
import LoadingSpinner from "../loading-spinner/loading-spinner.component";
//import LoadingSpinner from "../loading-spinner/loading-spinner.component";
import { Collapse } from "antd";
import { useTranslation } from "react-i18next";
pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf.worker.min.js`;
//pdfjs.GlobalWorkerOptions.workerSrc = `https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.1.266/pdf.worker.min.js`;
function JobsDocumentsComponent({ data, jobId, refetch }) {
const [galleryImages, setgalleryImages] = useState([]);
@@ -87,16 +87,18 @@ function JobsDocumentsComponent({ data, jobId, refetch }) {
}}
></Gallery>
</Collapse.Panel>
<Collapse.Panel
key="documents"
header={t("documents.labels.documents")}
>
{pdfDocuments.map((doc, idx) => (
<Document key={idx} loading={<LoadingSpinner />} file={doc.src}>
<Page pageIndex={0} />
</Document>
))}
</Collapse.Panel>
{
// <Collapse.Panel
// key="documents"
// header={t("documents.labels.documents")}
// >
// {pdfDocuments.map((doc, idx) => (
// <Document key={idx} loading={<LoadingSpinner />} file={doc.src}>
// <Page pageIndex={0} />
// </Document>
// ))}
// </Collapse.Panel>
}
</Collapse>
</div>
);

View File

@@ -70,3 +70,33 @@ export const QUERY_ALL_VEHICLES = gql`
}
}
`;
export const SEARCH_VEHICLE_BY_VIN = gql`
query SEARCH_VEHICLE_BY_VIN($vin: String!) {
vehicles(where: { v_vin: { _ilike: $vin } }) {
id
plate_no
plate_st
v_vin
v_model_yr
v_model_desc
v_make_desc
v_color
v_bstyle
updated_at
v_type
v_trimcode
v_tone
v_stage
v_prod_dt
v_paint_codes
v_options
v_mldgcode
v_makecode
v_engine
v_cond
trim_color
db_v_code
}
}
`;

View File

@@ -0,0 +1,76 @@
import { Button, message, Steps } from "antd";
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
export default function JobsCreateComponent({ form }) {
const [pageIndex, setPageIndex] = useState(0);
const { t } = useTranslation();
const steps = [
{
title: t("jobs.labels.create.vehicleinfo"),
content: <JobsCreateVehicleInfoContainer form={form} />
},
{
title: t("jobs.labels.create.ownerinfo"),
content: "Second-content"
},
{
title: t("jobs.labels.create.jobinfo"),
content: "Last-content"
}
];
const next = () => {
setPageIndex(pageIndex + 1);
};
const prev = () => {
setPageIndex(pageIndex - 1);
};
const { Step } = Steps;
return (
<div>
<Steps current={pageIndex}>
{steps.map((item, idx) => (
<Step
key={item.title}
title={item.title}
style={{ cursor: "pointer" }}
onClick={() => {
setPageIndex(idx);
}}
/>
))}
</Steps>
{steps.map((item, idx) => (
<div key={idx} style={{ display: idx === pageIndex ? "" : "none" }}>
{item.content}
</div>
))}
<div className="steps-action">
{pageIndex > 0 && (
<Button style={{ margin: 8 }} onClick={() => prev()}>
Previous
</Button>
)}
{pageIndex < steps.length - 1 && (
<Button type="primary" onClick={() => next()}>
Next
</Button>
)}
{pageIndex === steps.length - 1 && (
<Button
type="primary"
htmlType="submit"
onClick={() => message.success("Processing complete!")}
>
Done
</Button>
)}
</div>
</div>
);
}

View File

@@ -0,0 +1,36 @@
import React, { useState } from "react";
import JobsCreateComponent from "./jobs-create.component";
import { Form } from "antd";
import JobCreateContext from "./jobs-create.context";
export default function JobsCreateContainer() {
const [form] = Form.useForm();
const contextState = useState({
vehicle: { new: false, search: "", selectedid: null },
owner: { new: false },
job: null
});
const [state, setState] = contextState;
const handleFinish = values => {
console.log("Form Values", values);
//const vehicleSpread = state.vehicle.selectedid ? {vehicleid: state.vehicle.selectedid} : {vehicle: {data: { ...values.vehicle} }
const job = Object.assign(
{},
{
vehicle: state.vehicle.selectedid ? null : values.vehicle,
vehicleid: state.vehicle.selectedid || null
}
);
console.log("Job To Save", job);
};
return (
<JobCreateContext.Provider value={contextState}>
<Form form={form} onFinish={handleFinish} autoComplete={"off"}>
<JobsCreateComponent form={form} />
</Form>
</JobCreateContext.Provider>
);
}

View File

@@ -0,0 +1,3 @@
import React from "react";
const JobCreateContext = React.createContext(null);
export default JobCreateContext;

View File

@@ -1,7 +1,7 @@
import { BackTop, Layout } from "antd";
import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next";
import { Route } from "react-router";
import { Route, Switch } from "react-router-dom";
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
import FooterComponent from "../../components/footer/footer.component";
//Component Imports
@@ -40,14 +40,15 @@ const ShopPage = lazy(() => import("../shop/shop.page.component"));
const ShopVendorPageContainer = lazy(() =>
import("../shop-vendor/shop-vendor.page.container")
);
const EmailOverlayContainer = lazy(() =>
import("../../components/email-overlay/email-overlay.container.jsx")
);
const GlobalLoadingBar = lazy(() =>
import("../../components/global-loading-bar/global-loading-bar.component")
);
const JobsCreateContainerPage = lazy(() =>
import("../jobs-create/jobs-create.container")
);
const { Header, Content, Footer } = Layout;
@@ -78,11 +79,19 @@ export default function Manage({ match }) {
<EmailOverlayContainer />
<Route exact path={`${match.path}`} component={ManageRootPage} />
<Route exact path={`${match.path}/jobs`} component={JobsPage} />
<Route
exact
path={`${match.path}/jobs/:jobId`}
component={JobsDetailPage}
/>
<Switch>
<Route
exact
path={`${match.path}/jobs/create`}
component={JobsCreateContainerPage}
/>
<Route
exact
path={`${match.path}/jobs/:jobId`}
component={JobsDetailPage}
/>
</Switch>
<Route
exact
path={`${match.path}/profile`}

View File

@@ -433,6 +433,12 @@
"totals": "Totals",
"vehicle": "Vehicle"
},
"create": {
"jobinfo": "Job Info",
"newvehicle": "Create a new Vehicle Instead",
"ownerinfo": "Owner Info",
"vehicleinfo": "Vehicle Info"
},
"creating_new_job": "Creating new job...",
"documents": "Documents",
"existing_jobs": "Existing Jobs",

View File

@@ -433,6 +433,12 @@
"totals": "Totales",
"vehicle": "Vehículo"
},
"create": {
"jobinfo": "",
"newvehicle": "",
"ownerinfo": "",
"vehicleinfo": ""
},
"creating_new_job": "Creando nuevo trabajo ...",
"documents": "documentos",
"existing_jobs": "Empleos existentes",

View File

@@ -433,6 +433,12 @@
"totals": "Totaux",
"vehicle": "Véhicule"
},
"create": {
"jobinfo": "",
"newvehicle": "",
"ownerinfo": "",
"vehicleinfo": ""
},
"creating_new_job": "Création d'un nouvel emploi ...",
"documents": "Les documents",
"existing_jobs": "Emplois existants",