BOD-17 Added return car modal.

This commit is contained in:
Patrick Fic
2020-04-01 17:47:27 -07:00
parent 2a1cb3fb9f
commit ecec2c0368
25 changed files with 672 additions and 48 deletions

View File

View File

@@ -1981,6 +1981,27 @@
<folder_node>
<name>errors</name>
<children>
<concept_node>
<name>returning</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>saving</name>
<definition_loaded>false</definition_loaded>
@@ -2133,6 +2154,27 @@
</translation>
</translations>
</concept_node>
<concept_node>
<name>driver</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>driver_addr1</name>
<definition_loaded>false</definition_loaded>
@@ -2591,6 +2633,32 @@
<folder_node>
<name>courtesycars</name>
<children>
<folder_node>
<name>actions</name>
<children>
<concept_node>
<name>return</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>errors</name>
<children>
@@ -3260,6 +3328,27 @@
</concept_node>
</children>
</folder_node>
<concept_node>
<name>return</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>vehicle</name>
<definition_loaded>false</definition_loaded>

View File

@@ -16,13 +16,15 @@ export default function CourtesyCarContractListComponent({ contracts }) {
const columns = [
{
title: t("contracts.fields.agreementnumber"),
dataIndex: "id",
key: "id",
sorter: (a, b) => alphaSort(a.id, b.id),
sortOrder: state.sortedInfo.columnKey === "id" && state.sortedInfo.order,
dataIndex: "agreementnumber",
key: "agreementnumber",
sorter: (a, b) => a.agreementnumber - b.agreementnumber,
sortOrder:
state.sortedInfo.columnKey === "agreementnumber" &&
state.sortedInfo.order,
render: (text, record) => (
<Link to={`/manage/courtesycars/contracts/${record.id}`}>
{record.id || ""}
{record.agreementnumber || ""}
</Link>
)
},

View File

@@ -0,0 +1,49 @@
import { Form, DatePicker, InputNumber } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import CourtesyCarFuelSlider from "../courtesy-car-fuel-select/courtesy-car-fuel-select.component";
export default function CourtesyCarReturnModalComponent() {
const { t } = useTranslation();
return (
<div>
<Form.Item
label={t("contracts.fields.actualreturn")}
name="actualreturn"
rules={[
{
required: true,
message: t("general.validation.required")
}
]}
>
<DatePicker />
</Form.Item>
<Form.Item
label={t("contracts.fields.kmend")}
name="kmend"
rules={[
{
required: true,
message: t("general.validation.required")
}
]}
>
<InputNumber />
</Form.Item>
<Form.Item
label={t("courtesycars.fields.fuel")}
name={["courtesycar", "data", "fuel"]}
rules={[
{
required: true,
message: t("general.validation.required")
}
]}
>
<CourtesyCarFuelSlider />
</Form.Item>
</div>
);
}

View File

@@ -0,0 +1,86 @@
import { Form, Modal, notification } from "antd";
import React from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { toggleModalVisible } from "../../redux/modals/modals.actions";
import { selectCourtesyCarReturn } from "../../redux/modals/modals.selectors";
import { selectBodyshop } from "../../redux/user/user.selectors";
import CourtesyCarReturnModalComponent from "./courtesy-car-return-modal.component";
import moment from "moment";
import { RETURN_CONTRACT } from "../../graphql/cccontracts.queries";
import { useMutation } from "@apollo/react-hooks";
const mapStateToProps = createStructuredSelector({
courtesyCarReturnModal: selectCourtesyCarReturn,
bodyshop: selectBodyshop
});
const mapDispatchToProps = dispatch => ({
toggleModalVisible: () => dispatch(toggleModalVisible("courtesyCarReturn"))
});
export function InvoiceEnterModalContainer({
courtesyCarReturnModal,
toggleModalVisible,
bodyshop
}) {
const { visible, context, actions } = courtesyCarReturnModal;
const { t } = useTranslation();
const [form] = Form.useForm();
const [updateContract] = useMutation(RETURN_CONTRACT);
const handleFinish = values => {
console.log("Finish", values);
updateContract({
variables: {
contractId: context.contractId,
cccontract: {
kmend: values.kmend,
actualreturn: values.actualreturn,
status: "contracts.status.returned"
},
courtesycarid: context.courtesyCarId,
courtesycar: {
status: "courtesycars.status.in",
fuel: values.fuel,
mileage: values.kmend
}
}
})
.then(r => {
if (actions.refetch) actions.refetch();
toggleModalVisible();
})
.catch(error => {
notification["error"]({
message: t("contracts.errors.returning", { error: error })
});
});
};
return (
<Modal
title={t("courtesycars.labels.return")}
visible={visible}
onCancel={() => toggleModalVisible()}
width={"90%"}
okText={t("general.actions.save")}
onOk={() => form.submit()}
okButtonProps={{ htmlType: "submit" }}
>
<Form
form={form}
onFinish={handleFinish}
initialValues={{ fuel: 100, actualreturn: moment(new Date()) }}
>
<CourtesyCarReturnModalComponent />
</Form>
</Modal>
);
}
export default connect(
mapStateToProps,
mapDispatchToProps
)(InvoiceEnterModalContainer);

View File

@@ -25,7 +25,7 @@ export default ({
<img alt="Shop Logo" src={logo} style={{ height: "40px" }} />
</Col>
) : null}
<Col span={14}>
<Col span={21}>
{landingHeader ? (
<Menu
theme="dark"

View File

@@ -56,7 +56,7 @@ export default function VehicleTagPopoverComponent({ job }) {
</Col>
</Row>
<Link to={`/manage/vehicles/${job.vehicle.id}`}>
<Button>{t("vehicle.labels.updatevehicle")}</Button>
<Button>{t("vehicles.labels.updatevehicle")}</Button>
</Link>
</div>
);

View File

@@ -22,6 +22,28 @@ export const UPDATE_CONTRACT = gql`
}
}
`;
export const RETURN_CONTRACT = gql`
mutation RETURN_CONTRACT(
$contractId: uuid!
$cccontract: cccontracts_set_input!
$courtesycarid: uuid!
$courtesycar: courtesycars_set_input!
) {
update_cccontracts(where: { id: { _eq: $contractId } }, _set: $cccontract) {
returning {
id
}
}
update_courtesycars(
where: { id: { _eq: $courtesycarid } }
_set: $courtesycar
) {
returning {
id
}
}
}
`;
export const QUERY_CONTRACT_BY_PK = gql`
query QUERY_CONTRACT_BY_PK($id: uuid!) {

View File

@@ -231,6 +231,7 @@ export const GET_JOB_BY_PK = gql`
status
start
scheduledreturn
agreementnumber
}
appointments_aggregate {
aggregate {

View File

@@ -1,20 +1,50 @@
import { Button, Typography } from "antd";
import React from "react";
import ContractFormComponent from "../../components/contract-form/contract-form.component";
import { useTranslation } from "react-i18next";
import { Button } from "antd";
import ContractJobBlock from "../../components/contract-job-block/contract-job-block.component";
import { connect } from "react-redux";
import ContractCourtesyCarBlock from "../../components/contract-courtesy-car-block/contract-courtesy-car-block.component";
import ContractFormComponent from "../../components/contract-form/contract-form.component";
import ContractJobBlock from "../../components/contract-job-block/contract-job-block.component";
import { setModalContext } from "../../redux/modals/modals.actions";
export default function ContractDetailPage({ job, courtesyCar }) {
const mapDispatchToProps = dispatch => ({
setCourtesyCarReturnModalContext: context =>
dispatch(setModalContext({ context: context, modal: "courtesyCarReturn" }))
});
export function ContractDetailPage({
contract,
job,
courtesyCar,
setCourtesyCarReturnModalContext,
refetch
}) {
const { t } = useTranslation();
return (
<div>
<Typography.Title>{`Agreement ${(contract && contract.agreementnumber) ||
""}`}</Typography.Title>
<Button type="primary" htmlType="submit">
{t("general.actions.save")}
</Button>
<Button
disabled={contract && contract.status !== "contracts.status.out"}
onClick={() => {
setCourtesyCarReturnModalContext({
actions: { refetch },
context: {
contractId: contract.id,
courtesyCarId: courtesyCar.id
}
});
}}
>
{t("courtesycars.actions.return")}
</Button>
<ContractJobBlock job={job} />
<ContractCourtesyCarBlock courtesyCar={courtesyCar} />
<ContractFormComponent />
</div>
);
}
export default connect(null, mapDispatchToProps)(ContractDetailPage);

View File

@@ -10,6 +10,7 @@ import {
UPDATE_CONTRACT
} from "../../graphql/cccontracts.queries";
import ContractDetailPageComponent from "./contract-detail.page.component";
import CourtesyCarReturnModalContainer from "../../components/courtesy-car-return-modal/courtesy-car-return-modal.container";
export default function ContractDetailPageContainer() {
const { t } = useTranslation();
@@ -17,7 +18,7 @@ export default function ContractDetailPageContainer() {
const [form] = Form.useForm();
const { contractId } = useParams();
const { loading, error, data } = useQuery(QUERY_CONTRACT_BY_PK, {
const { loading, error, data, refetch } = useQuery(QUERY_CONTRACT_BY_PK, {
variables: { id: contractId }
});
@@ -27,7 +28,7 @@ export default function ContractDetailPageContainer() {
: error
? t("titles.app")
: t("titles.contracts-detail", {
id: (data && data.cccontracts_by_pk.id) || ""
id: (data && data.cccontracts_by_pk.agreementnumber) || ""
});
}, [t, data, error, loading]);
@@ -51,37 +52,42 @@ export default function ContractDetailPageContainer() {
if (error) return <AlertComponent message={error.message} type="error" />;
return (
<Form
form={form}
autoComplete="no"
onFinish={handleFinish}
initialValues={
data
? {
...data.cccontracts_by_pk,
start: data.cccontracts_by_pk.start
? moment(data.cccontracts_by_pk.start)
: null,
scheduledreturn: data.cccontracts_by_pk.scheduledreturn
? moment(data.cccontracts_by_pk.scheduledreturn)
: null,
actualreturn: data.cccontracts_by_pk.actualreturn
? moment(data.cccontracts_by_pk.actualreturn)
: null,
driver_dlexpiry: data.cccontracts_by_pk.driver_dlexpiry
? moment(data.cccontracts_by_pk.driver_dlexpiry)
: null,
driver_dob: data.cccontracts_by_pk.driver_dob
? moment(data.cccontracts_by_pk.driver_dob)
: null
}
: {}
}
>
<ContractDetailPageComponent
job={data ? data.cccontracts_by_pk.job : null}
courtesyCar={data ? data.cccontracts_by_pk.courtesycar : null}
/>
</Form>
<div>
<CourtesyCarReturnModalContainer />
<Form
form={form}
autoComplete="no"
onFinish={handleFinish}
initialValues={
data
? {
...data.cccontracts_by_pk,
start: data.cccontracts_by_pk.start
? moment(data.cccontracts_by_pk.start)
: null,
scheduledreturn: data.cccontracts_by_pk.scheduledreturn
? moment(data.cccontracts_by_pk.scheduledreturn)
: null,
actualreturn: data.cccontracts_by_pk.actualreturn
? moment(data.cccontracts_by_pk.actualreturn)
: null,
driver_dlexpiry: data.cccontracts_by_pk.driver_dlexpiry
? moment(data.cccontracts_by_pk.driver_dlexpiry)
: null,
driver_dob: data.cccontracts_by_pk.driver_dob
? moment(data.cccontracts_by_pk.driver_dob)
: null
}
: {}
}
>
<ContractDetailPageComponent
contract={data ? data.cccontracts_by_pk : null}
job={data ? data.cccontracts_by_pk.job : null}
courtesyCar={data ? data.cccontracts_by_pk.courtesycar : null}
refetch={refetch}
/>
</Form>
</div>
);
}

View File

@@ -10,7 +10,8 @@ const baseModal = {
const INITIAL_STATE = {
jobLineEdit: { ...baseModal },
invoiceEnter: { ...baseModal }
invoiceEnter: { ...baseModal },
courtesyCarReturn: { ...baseModal }
};
const modalsReducer = (state = INITIAL_STATE, action) => {

View File

@@ -12,3 +12,8 @@ export const selectInvoiceEnterModal = createSelector(
modals => modals.invoiceEnter
);
export const selectCourtesyCarReturn = createSelector(
[selectModals],
modals => modals.courtesyCarReturn
);

View File

@@ -141,6 +141,7 @@
},
"contracts": {
"errors": {
"returning": "Error returning courtesy car. {{error}}",
"saving": "Error saving contract. {{error}}",
"selectjobandcar": "Please ensure both a car and job are selected."
},
@@ -150,6 +151,7 @@
"cc_cardholder": "Cardholder Name",
"cc_expiry": "Credit Card Expiry Date",
"cc_num": "Credit Card Number",
"driver": "Driver",
"driver_addr1": "Driver Address 1",
"driver_addr2": "Driver Address 2",
"driver_city": "Driver City",
@@ -178,6 +180,9 @@
}
},
"courtesycars": {
"actions": {
"return": "Return Car"
},
"errors": {
"saving": "Error saving courtesy card. {{error}}"
},
@@ -216,6 +221,7 @@
"empty": "Empty",
"full": "Full"
},
"return": "Return Courtesy Car",
"vehicle": "Vehicle Description"
},
"status": {

View File

@@ -141,6 +141,7 @@
},
"contracts": {
"errors": {
"returning": "",
"saving": "",
"selectjobandcar": ""
},
@@ -150,6 +151,7 @@
"cc_cardholder": "",
"cc_expiry": "",
"cc_num": "",
"driver": "",
"driver_addr1": "",
"driver_addr2": "",
"driver_city": "",
@@ -178,6 +180,9 @@
}
},
"courtesycars": {
"actions": {
"return": ""
},
"errors": {
"saving": ""
},
@@ -216,6 +221,7 @@
"empty": "",
"full": ""
},
"return": "",
"vehicle": ""
},
"status": {

View File

@@ -141,6 +141,7 @@
},
"contracts": {
"errors": {
"returning": "",
"saving": "",
"selectjobandcar": ""
},
@@ -150,6 +151,7 @@
"cc_cardholder": "",
"cc_expiry": "",
"cc_num": "",
"driver": "",
"driver_addr1": "",
"driver_addr2": "",
"driver_city": "",
@@ -178,6 +180,9 @@
}
},
"courtesycars": {
"actions": {
"return": ""
},
"errors": {
"saving": ""
},
@@ -216,6 +221,7 @@
"empty": "",
"full": ""
},
"return": "",
"vehicle": ""
},
"status": {

View File

@@ -0,0 +1,5 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."courtesycars" DROP COLUMN "mileage";
type: run_sql

View File

@@ -0,0 +1,6 @@
- args:
cascade: false
read_only: false
sql: ALTER TABLE "public"."courtesycars" ADD COLUMN "mileage" numeric NOT NULL
DEFAULT 0;
type: run_sql

View File

@@ -0,0 +1,51 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_insert_permission
- args:
permission:
check:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- bodyshopid
- make
- model
- year
- plate
- color
- vin
- fleetnumber
- purchasedate
- servicestartdate
- serviceenddate
- leaseenddate
- status
- nextservicekm
- nextservicedate
- damage
- notes
- fuel
- registrationexpires
- insuranceexpires
- dailycost
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: courtesycars
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,52 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_insert_permission
- args:
permission:
check:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
columns:
- id
- created_at
- updated_at
- bodyshopid
- make
- model
- year
- plate
- color
- vin
- fleetnumber
- purchasedate
- servicestartdate
- serviceenddate
- leaseenddate
- status
- nextservicekm
- nextservicedate
- damage
- notes
- fuel
- registrationexpires
- insuranceexpires
- dailycost
- mileage
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: courtesycars
schema: public
type: create_insert_permission

View File

@@ -0,0 +1,49 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- insuranceexpires
- leaseenddate
- nextservicedate
- purchasedate
- registrationexpires
- serviceenddate
- servicestartdate
- dailycost
- fuel
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status
- vin
- year
- created_at
- updated_at
- bodyshopid
- id
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: courtesycars
schema: public
type: create_select_permission

View File

@@ -0,0 +1,50 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_select_permission
- args:
permission:
allow_aggregations: false
columns:
- insuranceexpires
- leaseenddate
- nextservicedate
- purchasedate
- registrationexpires
- serviceenddate
- servicestartdate
- dailycost
- fuel
- mileage
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status
- vin
- year
- created_at
- updated_at
- bodyshopid
- id
computed_fields: []
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
role: user
table:
name: courtesycars
schema: public
type: create_select_permission

View File

@@ -0,0 +1,51 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_update_permission
- args:
permission:
columns:
- insuranceexpires
- leaseenddate
- nextservicedate
- purchasedate
- registrationexpires
- serviceenddate
- servicestartdate
- dailycost
- fuel
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status
- vin
- year
- created_at
- updated_at
- bodyshopid
- id
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: courtesycars
schema: public
type: create_update_permission

View File

@@ -0,0 +1,52 @@
- args:
role: user
table:
name: courtesycars
schema: public
type: drop_update_permission
- args:
permission:
columns:
- insuranceexpires
- leaseenddate
- nextservicedate
- purchasedate
- registrationexpires
- serviceenddate
- servicestartdate
- dailycost
- fuel
- mileage
- nextservicekm
- color
- damage
- fleetnumber
- make
- model
- notes
- plate
- status
- vin
- year
- created_at
- updated_at
- bodyshopid
- id
filter:
bodyshop:
associations:
_and:
- user:
authid:
_eq: X-Hasura-User-Id
- active:
_eq: true
localPresets:
- key: ""
value: ""
set: {}
role: user
table:
name: courtesycars
schema: public
type: create_update_permission

View File

@@ -34,7 +34,6 @@
"devDependencies": {
"concurrently": "^5.1.0",
"eslint": "^6.8.0",
"eslint-plugin-promise": "^4.2.1",
"hasura-cli": "^1.1.0"
"eslint-plugin-promise": "^4.2.1"
}
}