BOD-17 Added Contracts list page + updates and bugfixes on other pages.
This commit is contained in:
@@ -2561,7 +2561,7 @@
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>successess</name>
|
||||
<name>successes</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>saved</name>
|
||||
@@ -9130,6 +9130,32 @@
|
||||
</concept_node>
|
||||
</children>
|
||||
</folder_node>
|
||||
<folder_node>
|
||||
<name>jobsactions</name>
|
||||
<children>
|
||||
<concept_node>
|
||||
<name>newcccontract</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>jobsdetail</name>
|
||||
<children>
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
import { Table } from "antd";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
|
||||
export default function ContractsList({ loading, contracts }) {
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: { text: "" }
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("contracts.fields.agreementnumber"),
|
||||
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.agreementnumber || ""}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "job.ro_number",
|
||||
key: "job.ro_number",
|
||||
sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "job.ro_number" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
{record.job.ro_number || ""}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("contracts.fields.driver"),
|
||||
dataIndex: "driver_ln",
|
||||
key: "driver_ln",
|
||||
sorter: (a, b) => alphaSort(a.driver_ln, b.driver_ln),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "driver_ln" && state.sortedInfo.order,
|
||||
render: (text, record) =>
|
||||
`${record.driver_fn || ""} ${record.driver_ln || ""}`
|
||||
},
|
||||
{
|
||||
title: t("contracts.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
render: (text, record) => t(record.status)
|
||||
},
|
||||
{
|
||||
title: t("contracts.fields.start"),
|
||||
dataIndex: "start",
|
||||
key: "start",
|
||||
sorter: (a, b) => alphaSort(a.start, b.start),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "start" && state.sortedInfo.order,
|
||||
render: (text, record) => <DateFormatter>{record.start}</DateFormatter>
|
||||
},
|
||||
{
|
||||
title: t("contracts.fields.scheduledreturn"),
|
||||
dataIndex: "scheduledreturn",
|
||||
key: "scheduledreturn",
|
||||
sorter: (a, b) => alphaSort(a.scheduledreturn, b.scheduledreturn),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "scheduledreturn" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<DateFormatter>{record.scheduledreturn}</DateFormatter>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
return (
|
||||
<Table
|
||||
loading={loading}
|
||||
size="small"
|
||||
pagination={{ position: "top" }}
|
||||
columns={columns.map(item => ({ ...item }))}
|
||||
rowKey="id"
|
||||
dataSource={contracts}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
|
||||
export default function JobsList({ loading, courtesycars }) {
|
||||
export default function CourtesyCarsList({ loading, courtesycars }) {
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: { text: "" }
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import React from "react";
|
||||
import { Menu, Dropdown, Button } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { DownCircleFilled } from "@ant-design/icons";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
export default function JobsDetailHeaderActions({ job }) {
|
||||
const { t } = useTranslation();
|
||||
const statusmenu = (
|
||||
<Menu key="popovermenu">
|
||||
<Menu.Item key="cccontract">
|
||||
<Link
|
||||
to={{
|
||||
pathname: "/manage/courtesycars/contracts/new",
|
||||
state: { jobId: job.id }
|
||||
}}
|
||||
>
|
||||
{t("menus.jobsactions.newcccontract")}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
</Menu>
|
||||
);
|
||||
return (
|
||||
<Dropdown overlay={statusmenu} key="changestatus">
|
||||
<Button>
|
||||
{t("general.labels.actions")} <DownCircleFilled />
|
||||
</Button>
|
||||
</Dropdown>
|
||||
);
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
Checkbox,
|
||||
Descriptions,
|
||||
Dropdown,
|
||||
List,
|
||||
Menu,
|
||||
notification,
|
||||
PageHeader,
|
||||
@@ -16,6 +15,7 @@ import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import Moment from "react-moment";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import CarImage from "../../assets/car.svg";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
@@ -23,7 +23,7 @@ import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import BarcodePopup from "../barcode-popup/barcode-popup.component";
|
||||
import OwnerTagPopoverComponent from "../owner-tag-popover/owner-tag-popover.component";
|
||||
import VehicleTagPopoverComponent from "../vehicle-tag-popover/vehicle-tag-popover.component";
|
||||
import { Link } from "react-router-dom";
|
||||
import JobsDetailHeaderActions from "../jobs-detail-header-actions/jobs-detail-header-actions.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
@@ -36,7 +36,6 @@ export default connect(
|
||||
job,
|
||||
mutationConvertJob,
|
||||
refetch,
|
||||
handleFinish,
|
||||
scheduleModalState,
|
||||
bodyshop,
|
||||
updateJobStatus
|
||||
@@ -99,6 +98,7 @@ export default connect(
|
||||
>
|
||||
{t("jobs.actions.convert")}
|
||||
</Button>,
|
||||
<JobsDetailHeaderActions key="actions" job={job} />,
|
||||
<Button type="primary" key="submit" htmlType="submit">
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
@@ -156,7 +156,7 @@ export default connect(
|
||||
key={item.id}
|
||||
to={`/manage/courtesycars/contracts/${item.id}`}
|
||||
>
|
||||
<div>{`${item.start} - ${item.scheduledreturn}`}</div>
|
||||
<div>{`${item.agreementnumber} - ${item.start} - ${item.scheduledreturn}`}</div>
|
||||
</Link>
|
||||
))}
|
||||
</Descriptions.Item>
|
||||
|
||||
@@ -74,3 +74,36 @@ export const QUERY_CONTRACT_BY_PK = gql`
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export const QUERY_ACTIVE_CONTRACTS = gql`
|
||||
query QUERY_ACTIVE_CONTRACTS {
|
||||
cccontracts(where: { status: { _neq: "contracts.status.returned" } }) {
|
||||
agreementnumber
|
||||
courtesycarid
|
||||
driver_fn
|
||||
driver_ln
|
||||
driver_ph1
|
||||
id
|
||||
jobid
|
||||
job {
|
||||
id
|
||||
est_number
|
||||
ro_number
|
||||
ownr_fn
|
||||
ownr_ln
|
||||
ownr_co_nm
|
||||
}
|
||||
scheduledreturn
|
||||
start
|
||||
status
|
||||
courtesycar {
|
||||
id
|
||||
fleetnumber
|
||||
make
|
||||
model
|
||||
year
|
||||
plate
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -301,6 +301,7 @@ export const QUERY_JOB_CARD_DETAILS = gql`
|
||||
ded_amt
|
||||
cccontracts {
|
||||
id
|
||||
agreementnumber
|
||||
status
|
||||
start
|
||||
scheduledreturn
|
||||
|
||||
@@ -8,7 +8,7 @@ import { Form, notification } from "antd";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries";
|
||||
import { useMutation } from "@apollo/react-hooks";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { useHistory, useLocation } from "react-router-dom";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
@@ -16,10 +16,15 @@ const mapStateToProps = createStructuredSelector({
|
||||
export function ContractCreatePageContainer({ bodyshop }) {
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslation();
|
||||
const selectedCarState = useState(null);
|
||||
const selectedJobState = useState(null);
|
||||
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
|
||||
const history = useHistory();
|
||||
const location = useLocation();
|
||||
const selectedCarState = useState(null);
|
||||
const selectedJobState = useState(
|
||||
(location.state && location.state.jobId) || null
|
||||
);
|
||||
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
|
||||
|
||||
console.log("location", location);
|
||||
|
||||
const handleFinish = values => {
|
||||
if (!!selectedCarState[0] && !!selectedJobState[0]) {
|
||||
|
||||
@@ -36,7 +36,7 @@ export default function ContractDetailPageContainer() {
|
||||
variables: { cccontract: { ...values }, contractId: contractId }
|
||||
})
|
||||
.then(response => {
|
||||
notification["success"]({ message: t("contracts.successess.saved") });
|
||||
notification["success"]({ message: t("contracts.successes.saved") });
|
||||
})
|
||||
.catch(error =>
|
||||
notification["error"]({
|
||||
|
||||
10
client/src/pages/contracts/contracts.page.component.jsx
Normal file
10
client/src/pages/contracts/contracts.page.component.jsx
Normal file
@@ -0,0 +1,10 @@
|
||||
import React from "react";
|
||||
import ContractsList from "../../components/contracts-list/contracts-list.component";
|
||||
|
||||
export default function ContractsPageComponent({ loading, data }) {
|
||||
return (
|
||||
<div>
|
||||
<ContractsList loading={loading} contracts={data} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
19
client/src/pages/contracts/contracts.page.container.jsx
Normal file
19
client/src/pages/contracts/contracts.page.container.jsx
Normal file
@@ -0,0 +1,19 @@
|
||||
import React from "react";
|
||||
import ContractsPageComponent from "./contracts.page.component";
|
||||
import { useQuery } from "@apollo/react-hooks";
|
||||
import { QUERY_ACTIVE_CONTRACTS } from "../../graphql/cccontracts.queries";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
|
||||
export default function ContractsPageContainer() {
|
||||
const { loading, error, data } = useQuery(QUERY_ACTIVE_CONTRACTS);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<div>
|
||||
<ContractsPageComponent
|
||||
loading={loading}
|
||||
data={data ? data.cccontracts : []}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -61,7 +61,9 @@ const ContractCreatePage = lazy(() =>
|
||||
const ContractDetailPage = lazy(() =>
|
||||
import("../contract-detail/contract-detail.page.container")
|
||||
);
|
||||
|
||||
const ContractsList = lazy(() =>
|
||||
import("../contracts/contracts.page.container")
|
||||
);
|
||||
const { Header, Content, Footer } = Layout;
|
||||
|
||||
export default function Manage({ match }) {
|
||||
@@ -117,7 +119,7 @@ export default function Manage({ match }) {
|
||||
<Route
|
||||
exact
|
||||
path={`${match.path}/courtesycars/contracts`}
|
||||
component={() => <div>HOLD</div>}
|
||||
component={ContractsList}
|
||||
/>
|
||||
|
||||
<Route
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
"out": "Out",
|
||||
"returned": "Returned"
|
||||
},
|
||||
"successess": {
|
||||
"successes": {
|
||||
"saved": "Contract saved successfully. "
|
||||
}
|
||||
},
|
||||
@@ -581,6 +581,9 @@
|
||||
"shop_vendors": "Vendors",
|
||||
"vehicles": "Vehicles"
|
||||
},
|
||||
"jobsactions": {
|
||||
"newcccontract": "Create Courtesy Car Contract"
|
||||
},
|
||||
"jobsdetail": {
|
||||
"claimdetail": "Claim Details",
|
||||
"dates": "Dates",
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
"out": "",
|
||||
"returned": ""
|
||||
},
|
||||
"successess": {
|
||||
"successes": {
|
||||
"saved": ""
|
||||
}
|
||||
},
|
||||
@@ -581,6 +581,9 @@
|
||||
"shop_vendors": "Vendedores",
|
||||
"vehicles": "Vehículos"
|
||||
},
|
||||
"jobsactions": {
|
||||
"newcccontract": ""
|
||||
},
|
||||
"jobsdetail": {
|
||||
"claimdetail": "Detalles de la reclamación",
|
||||
"dates": "fechas",
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
"out": "",
|
||||
"returned": ""
|
||||
},
|
||||
"successess": {
|
||||
"successes": {
|
||||
"saved": ""
|
||||
}
|
||||
},
|
||||
@@ -581,6 +581,9 @@
|
||||
"shop_vendors": "Vendeurs",
|
||||
"vehicles": "Véhicules"
|
||||
},
|
||||
"jobsactions": {
|
||||
"newcccontract": ""
|
||||
},
|
||||
"jobsdetail": {
|
||||
"claimdetail": "Détails de la réclamation",
|
||||
"dates": "Rendez-vous",
|
||||
|
||||
Reference in New Issue
Block a user