- Merge client update into test-beta

Signed-off-by: Dave Richer <dave@imexsystems.ca>
This commit is contained in:
Dave Richer
2024-01-18 19:20:08 -05:00
696 changed files with 92291 additions and 107075 deletions

View File

@@ -1,155 +1,158 @@
import { Button, PageHeader, Result, Space, Steps } from "antd";
import React, { useContext, useState } from "react";
import { useTranslation } from "react-i18next";
import { Link } from "react-router-dom";
import {Button, Result, Space, Steps} from "antd";
import {PageHeader} from "@ant-design/pro-layout";
import React, {useContext, useState} from "react";
import {useTranslation} from "react-i18next";
import {Link} from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component";
import JobsCreateJobsInfo from "../../components/jobs-create-jobs-info/jobs-create-jobs-info.component";
import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container";
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
import JobsCreateVehicleInfoContainer
from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
export default function JobsCreateComponent({ form }) {
const [pageIndex, setPageIndex] = useState(0);
const [errorMessage, setErrorMessage] = useState(null);
const [state] = useContext(JobCreateContext);
export default function JobsCreateComponent({form}) {
const [pageIndex, setPageIndex] = useState(0);
const [errorMessage, setErrorMessage] = useState(null);
const [state] = useContext(JobCreateContext);
const { t } = useTranslation();
const steps = [
{
title: t("jobs.labels.create.vehicleinfo"),
content: <JobsCreateVehicleInfoContainer form={form} />,
validation:
!!state.vehicle.new ||
!!state.vehicle.selectedid ||
!!state.vehicle.none,
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"),
},
{
title: t("jobs.labels.create.jobinfo"),
content: <JobsCreateJobsInfo form={form} selected={pageIndex === 2} />,
},
];
const {t} = useTranslation();
const steps = [
{
title: t("jobs.labels.create.vehicleinfo"),
content: <JobsCreateVehicleInfoContainer form={form}/>,
validation:
!!state.vehicle.new ||
!!state.vehicle.selectedid ||
!!state.vehicle.none,
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"),
},
{
title: t("jobs.labels.create.jobinfo"),
content: <JobsCreateJobsInfo form={form} selected={pageIndex === 2}/>,
},
];
const next = () => {
setPageIndex(pageIndex + 1);
};
const prev = () => {
setPageIndex(pageIndex - 1);
};
const { Step } = Steps;
const next = () => {
setPageIndex(pageIndex + 1);
};
const prev = () => {
setPageIndex(pageIndex - 1);
};
const {Step} = Steps;
const ProgressButtons = ({ top }) => {
return (
<PageHeader
extra={
<Space wrap>
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
{pageIndex < steps.length - 1 && (
<Button
type="primary"
onClick={() => {
form
.validateFields()
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
next();
} else {
setErrorMessage(steps[pageIndex].error);
}
})
.catch((error) => console.log("error", error));
}}
>
Next
</Button>
)}
{pageIndex === steps.length - 1 && (
<Button type="primary" htmlType="submit">
Done
</Button>
)}
</Space>
}
>
{top && (
<Steps current={pageIndex}>
{steps.map((item, idx) => (
<Step
key={item.title}
title={item.title}
style={{
cursor: "pointer",
fontWeight: idx === pageIndex && "bolder",
}}
onClick={() => {
form
.validateFields()
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
setPageIndex(idx);
} else {
setErrorMessage(steps[pageIndex].error);
}
})
.catch((error) => console.log("error", error));
}}
/>
))}
</Steps>
)}
</PageHeader>
);
};
return (
<div>
{state.created ? (
<div>
<Result
status="success"
title={t("jobs.successes.creatednoclick")}
extra={[
<Link to={`/manage/jobs/${state.newJobId}`} key="gotojob">
<Button type="primary">{t("jobs.actions.gotojob")}</Button>
</Link>,
<Link to={`/manage/jobs/`} key="gotojoblist">
<Button>{t("menus.header.activejobs")}</Button>
</Link>,
]}
/>
</div>
) : (
<div>
<ProgressButtons top />
{errorMessage ? (
<div>
<AlertComponent message={errorMessage} type="error" />
</div>
) : null}
{steps.map((item, idx) => (
<div
key={idx}
style={{
display: idx === pageIndex ? "" : "none",
margin: "1rem",
}}
const ProgressButtons = ({top}) => {
return (
<PageHeader
extra={
<Space wrap>
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
{pageIndex < steps.length - 1 && (
<Button
type="primary"
onClick={() => {
form
.validateFields()
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
next();
} else {
setErrorMessage(steps[pageIndex].error);
}
})
.catch((error) => console.log("error", error));
}}
>
Next
</Button>
)}
{pageIndex === steps.length - 1 && (
<Button type="primary" htmlType="submit">
Done
</Button>
)}
</Space>
}
>
{item.content}
</div>
))}
<ProgressButtons />
{top && (
<Steps current={pageIndex}>
{steps.map((item, idx) => (
<Step
key={item.title}
title={item.title}
style={{
cursor: "pointer",
fontWeight: idx === pageIndex && "bolder",
}}
onClick={() => {
form
.validateFields()
.then((r) => {
if (steps[pageIndex].validation) {
setErrorMessage(null);
setPageIndex(idx);
} else {
setErrorMessage(steps[pageIndex].error);
}
})
.catch((error) => console.log("error", error));
}}
/>
))}
</Steps>
)}
</PageHeader>
);
};
return (
<div>
{state.created ? (
<div>
<Result
status="success"
title={t("jobs.successes.creatednoclick")}
extra={[
<Link to={`/manage/jobs/${state.newJobId}`} key="gotojob">
<Button type="primary">{t("jobs.actions.gotojob")}</Button>
</Link>,
<Link to={`/manage/jobs/`} key="gotojoblist">
<Button>{t("menus.header.activejobs")}</Button>
</Link>,
]}
/>
</div>
) : (
<div>
<ProgressButtons top/>
{errorMessage ? (
<div>
<AlertComponent message={errorMessage} type="error"/>
</div>
) : null}
{steps.map((item, idx) => (
<div
key={idx}
style={{
display: idx === pageIndex ? "" : "none",
margin: "1rem",
}}
>
{item.content}
</div>
))}
<ProgressButtons/>
</div>
)}
</div>
)}
</div>
);
);
}

View File

@@ -1,194 +1,193 @@
import { useLazyQuery, useMutation } from "@apollo/client";
import { Form, notification } from "antd";
import {useLazyQuery, useMutation} from "@apollo/client";
import {Form, notification} from "antd";
import _ from "lodash";
import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import React, {useEffect, useState} from "react";
import {useTranslation} from "react-i18next";
import {connect} from "react-redux";
import {createStructuredSelector} from "reselect";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { INSERT_NEW_JOB } from "../../graphql/jobs.queries";
import { QUERY_OWNER_FOR_JOB_CREATION } from "../../graphql/owners.queries";
import {
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import {INSERT_NEW_JOB} from "../../graphql/jobs.queries";
import {QUERY_OWNER_FOR_JOB_CREATION} from "../../graphql/owners.queries";
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
import {selectBodyshop} from "../../redux/user/user.selectors";
import JobsCreateComponent from "./jobs-create.component";
import JobCreateContext from "./jobs-create.context";
const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop,
bodyshop: selectBodyshop,
});
const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
});
function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation();
const contextState = useState({
vehicle: {
new: false,
search: "",
selectedid: null,
vehicleObj: null,
none: false,
},
owner: { new: false, search: "", selectedid: null },
job: null,
created: false,
error: null,
newJobId: null,
newJobEstNum: null,
});
const [form] = Form.useForm();
const [state, setState] = contextState;
const [insertJob] = useMutation(INSERT_NEW_JOB);
const [loadOwner, RemoteOwnerData] = useLazyQuery(
QUERY_OWNER_FOR_JOB_CREATION
);
useEffect(() => {
if (!!state.owner.selectedid) {
loadOwner({
variables: { id: state.owner.selectedid },
});
}
}, [state.owner.selectedid, loadOwner]);
useEffect(() => {
document.title = t("titles.jobs-create");
setSelectedHeader("newjob");
setBreadcrumbs([
{ link: "/manage/available", label: t("titles.bc.availablejobs") },
{
link: "/manage/jobs/new",
label: t("titles.bc.jobs-new"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
const runInsertJob = (job) => {
insertJob({ variables: { job: job } })
.then((resp) => {
setState({
...state,
created: true,
error: null,
newJobId: resp.data.insert_jobs.returning[0].id,
});
})
.catch((error) => {
notification["error"]({
message: t("jobs.errors.creating", { error: error }),
});
setState({ ...state, error: error });
});
};
const handleFinish = (values) => {
let job = Object.assign(
{},
values,
{ date_open: new Date() },
{ date_estimated: new Date() },
{
vehicle:
state.vehicle.selectedid || state.vehicle.none
? null
: values.vehicle,
vehicleid: state.vehicle.selectedid || null,
},
{
owner: state.owner.selectedid ? null : values.owner,
ownerid: state.owner.selectedid || null,
},
{
status: bodyshop.md_ro_statuses.default_imported || "Open*",
shopid: bodyshop.id,
}
function JobsCreateContainer({bodyshop, setBreadcrumbs, setSelectedHeader}) {
const {t} = useTranslation();
const contextState = useState({
vehicle: {
new: false,
search: "",
selectedid: null,
vehicleObj: null,
none: false,
},
owner: {new: false, search: "", selectedid: null},
job: null,
created: false,
error: null,
newJobId: null,
newJobEstNum: null,
});
const [form] = Form.useForm();
const [state, setState] = contextState;
const [insertJob] = useMutation(INSERT_NEW_JOB);
const [loadOwner, RemoteOwnerData] = useLazyQuery(
QUERY_OWNER_FOR_JOB_CREATION
);
let ownerData;
if (!!!job.ownerid) {
ownerData = job.owner.data;
ownerData.shopid = bodyshop.id;
delete ownerData.allow_text_message;
delete ownerData.preferred_contact;
delete job.ownerid;
} else {
ownerData = _.cloneDeep(RemoteOwnerData.data.owners_by_pk);
delete ownerData.id;
delete ownerData.__typename;
}
if (!state.vehicle.none) {
if (!!!job.vehicleid) {
delete job.vehicleid;
job.vehicle.data.shopid = bodyshop.id;
job.plate_no = job.vehicle.data.plate_no;
job.plate_st = job.vehicle.data.plate_st;
job.v_vin = job.vehicle.data.v_vin;
job.v_model_yr = job.vehicle.data.v_model_yr;
job.v_model_desc = job.vehicle.data.v_model_desc;
job.v_make_desc = job.vehicle.data.v_make_desc;
job.v_color = job.vehicle.data.v_color;
} else {
job.plate_no = state.vehicle.vehicleObj.plate_no;
job.plate_st = state.vehicle.vehicleObj.plate_st;
job.v_vin = state.vehicle.vehicleObj.v_vin;
job.v_model_yr = state.vehicle.vehicleObj.v_model_yr;
job.v_model_desc = state.vehicle.vehicleObj.v_model_desc;
job.v_make_desc = state.vehicle.vehicleObj.v_make_desc;
job.v_color = state.vehicle.vehicleObj.v_color;
}
}
useEffect(() => {
if (!!state.owner.selectedid) {
loadOwner({
variables: {id: state.owner.selectedid},
});
}
}, [state.owner.selectedid, loadOwner]);
job = { ...job, ...ownerData };
if (job.owner === null) delete job.owner;
if (job.vehicle === null) delete job.vehicle;
runInsertJob(job);
};
return (
<JobCreateContext.Provider value={contextState}>
<RbacWrapper action="jobs:create">
<Form
scrollToFirstError
form={form}
onFinish={handleFinish}
layout="vertical"
autoComplete={"off"}
initialValues={{
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
cieca_pft: {
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
...bodyshop.md_responsibility_centers.taxes.tax_ty5,
useEffect(() => {
document.title = t("titles.jobs-create");
setSelectedHeader("newjob");
setBreadcrumbs([
{link: "/manage/available", label: t("titles.bc.availablejobs")},
{
link: "/manage/jobs/new",
label: t("titles.bc.jobs-new"),
},
materials: bodyshop.md_responsibility_centers.cieca_pfm,
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates,
}}
>
<JobsCreateComponent form={form} />
</Form>
</RbacWrapper>
</JobCreateContext.Provider>
);
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
const runInsertJob = (job) => {
insertJob({variables: {job: job}})
.then((resp) => {
setState({
...state,
created: true,
error: null,
newJobId: resp.data.insert_jobs.returning[0].id,
});
})
.catch((error) => {
notification["error"]({
message: t("jobs.errors.creating", {error: error}),
});
setState({...state, error: error});
});
};
const handleFinish = (values) => {
let job = Object.assign(
{},
values,
{date_open: new Date()},
{date_estimated: new Date()},
{
vehicle:
state.vehicle.selectedid || state.vehicle.none
? null
: values.vehicle,
vehicleid: state.vehicle.selectedid || null,
},
{
owner: state.owner.selectedid ? null : values.owner,
ownerid: state.owner.selectedid || null,
},
{
status: bodyshop.md_ro_statuses.default_imported || "Open*",
shopid: bodyshop.id,
}
);
let ownerData;
if (!!!job.ownerid) {
ownerData = job.owner.data;
ownerData.shopid = bodyshop.id;
delete ownerData.allow_text_message;
delete ownerData.preferred_contact;
delete job.ownerid;
} else {
ownerData = _.cloneDeep(RemoteOwnerData.data.owners_by_pk);
delete ownerData.id;
delete ownerData.__typename;
}
if (!state.vehicle.none) {
if (!!!job.vehicleid) {
delete job.vehicleid;
job.vehicle.data.shopid = bodyshop.id;
job.plate_no = job.vehicle.data.plate_no;
job.plate_st = job.vehicle.data.plate_st;
job.v_vin = job.vehicle.data.v_vin;
job.v_model_yr = job.vehicle.data.v_model_yr;
job.v_model_desc = job.vehicle.data.v_model_desc;
job.v_make_desc = job.vehicle.data.v_make_desc;
job.v_color = job.vehicle.data.v_color;
} else {
job.plate_no = state.vehicle.vehicleObj.plate_no;
job.plate_st = state.vehicle.vehicleObj.plate_st;
job.v_vin = state.vehicle.vehicleObj.v_vin;
job.v_model_yr = state.vehicle.vehicleObj.v_model_yr;
job.v_model_desc = state.vehicle.vehicleObj.v_model_desc;
job.v_make_desc = state.vehicle.vehicleObj.v_make_desc;
job.v_color = state.vehicle.vehicleObj.v_color;
}
}
job = {...job, ...ownerData};
if (job.owner === null) delete job.owner;
if (job.vehicle === null) delete job.vehicle;
runInsertJob(job);
};
return (
<JobCreateContext.Provider value={contextState}>
<RbacWrapper action="jobs:create">
<Form
scrollToFirstError
form={form}
onFinish={handleFinish}
layout="vertical"
autoComplete={"off"}
initialValues={{
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
cieca_pft: {
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
...bodyshop.md_responsibility_centers.taxes.tax_ty5,
},
materials: bodyshop.md_responsibility_centers.cieca_pfm,
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates,
}}
>
<JobsCreateComponent form={form}/>
</Form>
</RbacWrapper>
</JobCreateContext.Provider>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
mapStateToProps,
mapDispatchToProps
)(JobsCreateContainer);

View File

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