Merge branch 'feature/IO-3255-simplified-part-management' into feature/IO-2776-cdk-fortellis
# Conflicts: # client/package-lock.json # client/src/components/dms-cdk-makes/dms-cdk-makes.component.jsx # client/src/components/dms-customer-selector/dms-customer-selector.component.jsx # client/src/pages/dms/dms.container.jsx # package-lock.json # package.json
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import QboAuthorizeComponent from "../../components/qbo-authorize/qbo-authorize.component";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AccountingReceivablesContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
export function AccountingReceivablesContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -18,11 +18,10 @@ import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import useLocalStorage from "../../utils/useLocalStorage";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPartsOrderContext: (context) => dispatch(setModalContext({ context: context, modal: "partsOrder" })),
|
||||
setBillEnterContext: (context) => dispatch(setModalContext({ context: context, modal: "billEnter" }))
|
||||
});
|
||||
|
||||
export function BillsListPage({ loading, data, refetch, total, setPartsOrderContext, setBillEnterContext }) {
|
||||
export function BillsListPage({ loading, data, refetch, total, setBillEnterContext }) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
@@ -193,7 +192,6 @@ export function BillsListPage({ loading, data, refetch, total, setPartsOrderCont
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchBills();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchBills(value) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Button, Col, Form, Row, Space, Switch } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ContractCarsContainer from "../../components/contract-cars/contract-cars.container";
|
||||
import ContractFormComponent from "../../components/contract-form/contract-form.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Card, Form } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { Button, Col, Dropdown, Form, Row, Space, Typography } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import ContractConvertToRo from "../../components/contract-convert-to-ro/contract-convert-to-ro.component";
|
||||
@@ -37,8 +35,8 @@ export function ContractDetailPage({
|
||||
</Row>
|
||||
<PageHeader
|
||||
title={t("contracts.labels.agreement", {
|
||||
agreement_num: contract && contract.agreementnumber,
|
||||
status: t(contract && contract.status)
|
||||
agreement_num: contract?.agreementnumber,
|
||||
status: t(contract?.status)
|
||||
})}
|
||||
extra={
|
||||
<Form.Item shouldUpdate>
|
||||
@@ -78,7 +76,7 @@ export function ContractDetailPage({
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!!!contract || (contract && contract.status !== "contracts.status.out")}
|
||||
disabled={!contract || (contract && contract.status !== "contracts.status.out")}
|
||||
onClick={() => {
|
||||
setCourtesyCarReturnModalContext({
|
||||
actions: { refetch },
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { Card, Form } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -52,7 +52,7 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
|
||||
rome: t("titles.romeonline")
|
||||
})
|
||||
: t("titles.contracts-detail", {
|
||||
id: (data && data.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
id: (data?.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
});
|
||||
|
||||
setBreadcrumbs([
|
||||
@@ -64,12 +64,12 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
|
||||
{
|
||||
link: "/manage/courtesycars/contracts/new",
|
||||
label: t("titles.bc.contracts-detail", {
|
||||
number: (data && data.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
number: (data?.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
if (data && data.cccontracts_by_pk)
|
||||
if (data?.cccontracts_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
contractId,
|
||||
@@ -85,7 +85,7 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
|
||||
const result = await updateContract({
|
||||
variables: { cccontract: { ...values }, contractId: contractId }
|
||||
});
|
||||
if (!!result.errors) {
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
@@ -102,7 +102,7 @@ export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, set
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.cccontracts_by_pk) form.resetFields();
|
||||
if (data?.cccontracts_by_pk) form.resetFields();
|
||||
}, [data, form]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import ContractsList from "../../components/contracts-list/contracts-list.component";
|
||||
|
||||
export default function ContractsPageComponent({ loading, data, refetch, total }) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Card, Form } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
@@ -37,7 +37,7 @@ export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
variables: { courtesycar: { ...values, bodyshopid: bodyshop.id } }
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import CourtesyCarCreateFormComponent from "../../components/courtesy-car-form/courtesy-car-form.component";
|
||||
import CourtesyCarContractListComponent from "../../components/courtesy-car-contract-list/courtesy-car-contract-list.component";
|
||||
import { Col, Divider, Row } from "antd";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { Form } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
@@ -68,19 +68,19 @@ export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem,
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
}),
|
||||
id: (data && data.courtesycars_by_pk && data.courtesycars_by_pk.fleet_number) || ""
|
||||
id: (data?.courtesycars_by_pk && data.courtesycars_by_pk.fleet_number) || ""
|
||||
});
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
|
||||
{
|
||||
link: `/manage/courtesycars/${(data && data.courtesycars_by_pk && data.courtesycars_by_pk.id) || ""}`,
|
||||
link: `/manage/courtesycars/${(data?.courtesycars_by_pk && data.courtesycars_by_pk.id) || ""}`,
|
||||
label: t("titles.bc.courtesycars-detail", {
|
||||
number: (data && data.courtesycars_by_pk && data.courtesycars_by_pk.fleetnumber) || ""
|
||||
number: (data?.courtesycars_by_pk && data.courtesycars_by_pk.fleetnumber) || ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
if (data && data.courtesycars_by_pk)
|
||||
if (data?.courtesycars_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
ccId,
|
||||
@@ -103,7 +103,7 @@ export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem,
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
if (result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", { error: error })
|
||||
});
|
||||
@@ -117,7 +117,7 @@ export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem,
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.courtesycars_by_pk) {
|
||||
if (data?.courtesycars_by_pk) {
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
}
|
||||
@@ -126,7 +126,7 @@ export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem,
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (!!!data.courtesycars_by_pk) return <NotFound />;
|
||||
if (!data.courtesycars_by_pk) return <NotFound />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:detail">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import CourtesyCarsListComponent from "../../components/courtesy-cars-list/courtesy-cars-list.component";
|
||||
|
||||
export default function CourtesyCarsPageComponent({ loading, data, refetch }) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
@@ -45,7 +45,7 @@ export function CourtesyCarsPageContainer({ setBreadcrumbs, setSelectedHeader })
|
||||
}
|
||||
>
|
||||
<RbacWrapper action="courtesycar:list">
|
||||
<CourtesyCarsPageComponent loading={loading} data={(data && data.courtesycars) || []} refetch={refetch} />
|
||||
<CourtesyCarsPageComponent loading={loading} data={data?.courtesycars || []} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import { Typography } from "antd";
|
||||
import InstanceRenderMgr from "../../utils/instanceRenderMgr";
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Button, Card, Col, Row, Select, Space } from "antd";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
@@ -9,13 +9,10 @@ import DmsAllocationsSummaryApComponent from "../../components/dms-allocations-s
|
||||
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
@@ -33,7 +30,7 @@ export const socket = SocketIO(import.meta.env.PROD ? import.meta.env.VITE_APP_A
|
||||
}
|
||||
});
|
||||
|
||||
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
export function DmsContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useNavigate();
|
||||
@@ -85,7 +82,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("ap-export-complete", (payload) => {
|
||||
socket.on("ap-export-complete", () => {
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: t("jobs.labels.dms.apexported")
|
||||
@@ -97,7 +94,6 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (!state?.billids) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Col, Result, Row, Select, Space } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
@@ -157,13 +157,12 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, inse
|
||||
history("/manage/accounting/receivables");
|
||||
});
|
||||
|
||||
if (socket.disconnected) socket.connect();
|
||||
if (socket.disconnected) socket.connect();
|
||||
return () => {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
|
||||
@@ -3,23 +3,19 @@ import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
|
||||
import _ from "lodash";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormatter } from "../../utils/DateFormatter";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import { alphaSort, dateSort } from "./../../utils/sorters";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
export function ExportLogsPageComponent({ bodyshop }) {
|
||||
export function ExportLogsPageComponent() {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search } = searchParams;
|
||||
const history = useNavigate();
|
||||
@@ -97,9 +93,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
|
||||
sortOrder: sortcolumn === "ro_number" && sortorder,
|
||||
render: (text, record) =>
|
||||
record.job && (
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
{(record.job && record.job.ro_number) || t("general.labels.na")}
|
||||
</Link>
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>{record.job?.ro_number || t("general.labels.na")}</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -109,11 +103,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
|
||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||
sortOrder: sortcolumn === "invoice_number" && sortorder,
|
||||
render: (text, record) =>
|
||||
record.bill && (
|
||||
<Link to={"/manage/bills?billid=" + (record.bill && record.bill.id)}>
|
||||
{record.bill && record.bill.invoice_number}
|
||||
</Link>
|
||||
)
|
||||
record.bill && <Link to={"/manage/bills?billid=" + record.bill?.id}>{record.bill?.invoice_number}</Link>
|
||||
},
|
||||
{
|
||||
title: t("payments.fields.paymentnum"),
|
||||
@@ -123,9 +113,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
|
||||
sortOrder: sortcolumn === "paymentnum" && sortorder,
|
||||
render: (text, record) =>
|
||||
record.payment && (
|
||||
<Link to={"/manage/payments?search=" + (record.payment && record.payment.paymentnum)}>
|
||||
{record.payment && record.payment.paymentnum}
|
||||
</Link>
|
||||
<Link to={"/manage/payments?search=" + record.payment?.paymentnum}>{record.payment?.paymentnum}</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
@@ -197,12 +185,12 @@ export function ExportLogsPageComponent({ bodyshop }) {
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
current: parseInt(page || 1, 10),
|
||||
total: data && data.search_exportlog_aggregate.aggregate.count
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_exportlog}
|
||||
dataSource={data?.search_exportlog}
|
||||
style={{ height: "100%" }}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import axios from "axios";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
@@ -33,6 +33,7 @@ export function FeedbackPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
theme: "light" // options: light [default], dark, auto
|
||||
});
|
||||
}
|
||||
|
||||
RenderCanny();
|
||||
}, []);
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import HelpRescue from "../../components/help-rescue/help-rescue.component";
|
||||
|
||||
export default function HelpPage() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Result, Row, Space, Typography } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -77,7 +77,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.jobs_by_pk) return <NotFound />;
|
||||
if (!data.jobs_by_pk) return <NotFound />;
|
||||
if (!data.jobs_by_pk.job_totals)
|
||||
return <Result title={t("jobs.errors.nofinancial")} extra={<JobCalculateTotals job={data.jobs_by_pk} />} />;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Button } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
@@ -63,7 +63,7 @@ export function JobsAvailablePageContainer({ partnerVersion, setBreadcrumbs, set
|
||||
message={t("general.messages.partnernotrunning", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
})
|
||||
})}
|
||||
/>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Row, Typography } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -12,21 +12,17 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { QUERY_JOB_CHECKLISTS } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
export function JobsChecklistViewContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_CHECKLISTS, {
|
||||
@@ -48,7 +44,7 @@ export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
{
|
||||
link: `/manage/jobs/${jobId}`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: (data && data.jobs_by_pk && data.jobs_by_pk.ro_number) || ""
|
||||
number: (data?.jobs_by_pk && data.jobs_by_pk.ro_number) || ""
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -87,10 +83,10 @@ export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.intakechecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form && (
|
||||
{data.jobs_by_pk.intakechecklist?.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
||||
formItems={data.jobs_by_pk.intakechecklist?.form}
|
||||
type="intake"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
@@ -101,10 +97,10 @@ export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelect
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Typography.Title level={4}>{t("jobs.labels.deliverchecklist")}</Typography.Title>
|
||||
{data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form && (
|
||||
{data.jobs_by_pk.deliverchecklist?.form && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
||||
formItems={data.jobs_by_pk.deliverchecklist?.form}
|
||||
type="deliver"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Result } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -30,7 +30,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobRe
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data && data.jobs_by_pk) {
|
||||
if (data?.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
}
|
||||
}, [data, setJobReadOnly]);
|
||||
@@ -41,7 +41,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobRe
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
}),
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
number: data ? data.jobs_by_pk?.ro_number : null
|
||||
});
|
||||
|
||||
setBreadcrumbs([
|
||||
@@ -52,7 +52,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobRe
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
number: data ? data.jobs_by_pk?.ro_number : null
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -64,7 +64,7 @@ export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobRe
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.jobs_by_pk) return <NotFound />;
|
||||
if (!data.jobs_by_pk) return <NotFound />;
|
||||
|
||||
if (!data.jobs_by_pk.job_totals)
|
||||
return <Result title={t("jobs.errors.nofinancial")} extra={<JobCalculateTotals job={data.jobs_by_pk} />} />;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import { Button, Result, Space, Steps } from "antd";
|
||||
|
||||
import React, { useContext, useState } from "react";
|
||||
import { useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
@@ -63,7 +63,7 @@ export default function JobsCreateComponent({ form }) {
|
||||
next();
|
||||
form
|
||||
.validateFields()
|
||||
.then((r) => {
|
||||
.then(() => {
|
||||
if (steps[pageIndex].validation) {
|
||||
setErrorMessage(null);
|
||||
next();
|
||||
@@ -83,7 +83,9 @@ export default function JobsCreateComponent({ form }) {
|
||||
onClick={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((r) => {})
|
||||
.then(() => {
|
||||
// NO OP
|
||||
})
|
||||
.catch((error) => console.log("error", error));
|
||||
form.submit();
|
||||
}}
|
||||
@@ -108,7 +110,7 @@ export default function JobsCreateComponent({ form }) {
|
||||
setPageIndex(idx);
|
||||
form
|
||||
.validateFields()
|
||||
.then((r) => {
|
||||
.then(() => {
|
||||
if (steps[pageIndex].validation) {
|
||||
setErrorMessage(null);
|
||||
setPageIndex(idx);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useLazyQuery, useMutation } from "@apollo/client";
|
||||
import { Form } from "antd";
|
||||
import _ from "lodash";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -48,7 +48,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const [loadOwner, RemoteOwnerData] = useLazyQuery(QUERY_OWNER_FOR_JOB_CREATION);
|
||||
|
||||
useEffect(() => {
|
||||
if (!!state.owner.selectedid) {
|
||||
if (state.owner.selectedid) {
|
||||
loadOwner({
|
||||
variables: { id: state.owner.selectedid }
|
||||
});
|
||||
@@ -111,7 +111,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
);
|
||||
|
||||
let ownerData;
|
||||
if (!!!job.ownerid) {
|
||||
if (!job.ownerid) {
|
||||
ownerData = job.owner.data;
|
||||
ownerData.shopid = bodyshop.id;
|
||||
delete ownerData.preferred_contact;
|
||||
@@ -122,7 +122,7 @@ function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
delete ownerData.__typename;
|
||||
}
|
||||
if (!state.vehicle.none) {
|
||||
if (!!!job.vehicleid) {
|
||||
if (!job.vehicleid) {
|
||||
delete job.vehicleid;
|
||||
job.vehicle.data.shopid = bodyshop.id;
|
||||
job.plate_no = job.vehicle.data.plate_no;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -59,7 +59,7 @@ export function JobsDeliverContainer({ bodyshop, setBreadcrumbs, setSelectedHead
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (data && !!!data.bodyshops_by_pk.deliverchecklist)
|
||||
if (data && !data.bodyshops_by_pk.deliverchecklist)
|
||||
return <AlertComponent message={t("deliver.errors.nochecklist")} type="error" />;
|
||||
return (
|
||||
<FeatureWrapperComponent
|
||||
|
||||
@@ -260,7 +260,7 @@ export function JobsDetailPage({
|
||||
form.setFieldsValue(transformJobToForm(job));
|
||||
form.resetFields();
|
||||
}
|
||||
} catch (error) {
|
||||
} catch {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc")
|
||||
});
|
||||
@@ -487,7 +487,7 @@ export function JobsDetailPage({
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailPage);
|
||||
|
||||
const transformJobToForm = (job) => {
|
||||
export const transformJobToForm = (job) => {
|
||||
const transformedJob = { ...job };
|
||||
|
||||
transformedJob.parts_tax_rates = Object.keys(transformedJob.parts_tax_rates).reduce((acc, parttype) => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -61,19 +61,19 @@ function JobsDetailPageContainer({ setBreadcrumbs, addRecentItem, setSelectedHea
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
}),
|
||||
ro_number: (data.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na")
|
||||
ro_number: data.jobs_by_pk?.ro_number || t("general.labels.na")
|
||||
});
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/jobs", label: t("titles.bc.jobs") },
|
||||
{
|
||||
link: `/manage/jobs/${jobId}`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: (data && data.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na")
|
||||
number: (data?.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na")
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
if (data && data.jobs_by_pk) {
|
||||
if (data?.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
|
||||
addRecentItem(
|
||||
@@ -90,7 +90,7 @@ function JobsDetailPageContainer({ setBreadcrumbs, addRecentItem, setSelectedHea
|
||||
|
||||
if (loading) return <SpinComponent />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.jobs_by_pk) return <NotFound />;
|
||||
if (!data.jobs_by_pk) return <NotFound />;
|
||||
|
||||
return data.jobs_by_pk ? (
|
||||
<RbacWrapper action="jobs:detail">
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -48,7 +48,7 @@ export function JobsIntakeContainer({ bodyshop, setBreadcrumbs, setSelectedHeade
|
||||
{
|
||||
link: `/manage/jobs/${jobId}`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: data && ((data.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na"))
|
||||
number: data && (data.jobs_by_pk?.ro_number || t("general.labels.na"))
|
||||
})
|
||||
},
|
||||
{
|
||||
@@ -61,7 +61,7 @@ export function JobsIntakeContainer({ bodyshop, setBreadcrumbs, setSelectedHeade
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (data && !!!data.bodyshops_by_pk.intakechecklist)
|
||||
if (data && !data.bodyshops_by_pk.intakechecklist)
|
||||
return <AlertComponent message={t("intake.errors.nochecklist")} type="error" />;
|
||||
|
||||
return (
|
||||
@@ -82,7 +82,7 @@ export function JobsIntakeContainer({ bodyshop, setBreadcrumbs, setSelectedHeade
|
||||
<JobChecklist
|
||||
type="intake"
|
||||
checklistConfig={(data && data.bodyshops_by_pk.intakechecklist) || {}}
|
||||
job={data && data.jobs_by_pk}
|
||||
job={data?.jobs_by_pk}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
//import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { setBreadcrumbs } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ManageRootPageComponent from "./manage-root.page.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs))
|
||||
});
|
||||
|
||||
export function ManageRootPageContainer({ setBreadcrumbs, bodyshop }) {
|
||||
export function ManageRootPageContainer({ setBreadcrumbs }) {
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.manageroot", {
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import { Button, FloatButton, Layout, Space, Spin } from "antd";
|
||||
import { AlertOutlined, BulbOutlined } from "@ant-design/icons";
|
||||
import { FloatButton, Layout, Spin } from "antd";
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
|
||||
// import preval from "preval.macro";
|
||||
import React, { lazy, Suspense, useEffect, useState } from "react";
|
||||
import { lazy, Suspense, useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, Route, Routes } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
|
||||
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
|
||||
@@ -15,20 +14,19 @@ import ErrorBoundary from "../../components/error-boundary/error-boundary.compon
|
||||
//Component Imports
|
||||
import * as Sentry from "@sentry/react";
|
||||
import TestComponent from "../../components/_test/test.page";
|
||||
import GlobalFooter from "../../components/global-footer/global-footer.component.jsx";
|
||||
import HeaderContainer from "../../components/header/header.container";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
|
||||
import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container";
|
||||
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
|
||||
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors";
|
||||
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||
import { selectBodyshop, selectInstanceConflict, selectPartsManagementOnly } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
|
||||
import "./manage.page.styles.scss";
|
||||
import WssStatusDisplayComponent from "../../components/wss-status-display/wss-status-display.component.jsx";
|
||||
import { selectAlerts } from "../../redux/application/application.selectors.js";
|
||||
import { addAlerts } from "../../redux/application/application.actions.js";
|
||||
import { useNotification } from "../../contexts/Notifications/notificationContext.jsx";
|
||||
import { useSocket } from "../../contexts/SocketIO/useSocket.js";
|
||||
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
|
||||
|
||||
const PrintCenterModalContainer = lazy(
|
||||
() => import("../../components/print-center-modal/print-center-modal.container")
|
||||
);
|
||||
|
||||
const JobsPage = lazy(() => import("../jobs/jobs.page"));
|
||||
|
||||
@@ -104,83 +102,21 @@ const MyTasksPage = lazy(() => import("../tasks/myTasksPageContainer.jsx"));
|
||||
const AllTasksPage = lazy(() => import("../tasks/allTasksPageContainer.jsx"));
|
||||
|
||||
const TaskUpsertModalContainer = lazy(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
|
||||
const { Content, Footer } = Layout;
|
||||
const { Content } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
conflict: selectInstanceConflict,
|
||||
bodyshop: selectBodyshop,
|
||||
alerts: selectAlerts
|
||||
partsManagementOnly: selectPartsManagementOnly
|
||||
});
|
||||
|
||||
const ALERT_FILE_URL = InstanceRenderManager({
|
||||
imex: "https://images.imex.online/alerts/alerts-imex.json",
|
||||
rome: "https://images.imex.online/alerts/alerts-rome.json"
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setAlerts: (alerts) => dispatch(addAlerts(alerts))
|
||||
});
|
||||
|
||||
export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
|
||||
export function Manage({ conflict, bodyshop, partsManagementOnly }) {
|
||||
const { t } = useTranslation();
|
||||
const [chatVisible] = useState(false);
|
||||
const { socket, clientId } = useSocket();
|
||||
const notification = useNotification();
|
||||
|
||||
// State to track displayed alerts
|
||||
const [displayedAlertIds, setDisplayedAlertIds] = useState([]);
|
||||
// Centralized alerts handling (fetch + dedupe + notifications)
|
||||
useAlertsNotifications();
|
||||
|
||||
// Fetch displayed alerts from localStorage on mount
|
||||
useEffect(() => {
|
||||
const displayedAlerts = JSON.parse(localStorage.getItem("displayedAlerts") || "[]");
|
||||
setDisplayedAlertIds(displayedAlerts);
|
||||
}, []);
|
||||
|
||||
// Fetch alerts from the JSON file and dispatch to Redux store
|
||||
useEffect(() => {
|
||||
const fetchAlerts = async () => {
|
||||
try {
|
||||
const response = await fetch(ALERT_FILE_URL);
|
||||
const fetchedAlerts = await response.json();
|
||||
setAlerts(fetchedAlerts);
|
||||
} catch (error) {
|
||||
console.warn("Error fetching alerts:", error.message);
|
||||
}
|
||||
};
|
||||
|
||||
fetchAlerts().catch((err) => `Error fetching Bodyshop Alerts: ${err?.message || ""}`);
|
||||
}, [setAlerts]);
|
||||
|
||||
// Use useEffect to watch for new alerts
|
||||
useEffect(() => {
|
||||
if (alerts && Object.keys(alerts).length > 0) {
|
||||
// Convert the alerts object into an array
|
||||
const alertArray = Object.values(alerts);
|
||||
|
||||
// Filter out alerts that have already been dismissed
|
||||
const newAlerts = alertArray.filter((alert) => !displayedAlertIds.includes(alert.id));
|
||||
|
||||
newAlerts.forEach((alert) => {
|
||||
// Display the notification
|
||||
notification.open({
|
||||
key: "notification-alerts-" + alert.id,
|
||||
message: alert.message,
|
||||
description: alert.description,
|
||||
type: alert.type || "info",
|
||||
duration: 0,
|
||||
closable: true,
|
||||
onClose: () => {
|
||||
// When the notification is closed, update displayed alerts state and localStorage
|
||||
setDisplayedAlertIds((prevIds) => {
|
||||
const updatedIds = [...prevIds, alert.id];
|
||||
localStorage.setItem("displayedAlerts", JSON.stringify(updatedIds));
|
||||
return updatedIds;
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}, [alerts, displayedAlertIds, notification]);
|
||||
useEffect(() => {
|
||||
window.Canny("initChangelog", {
|
||||
appID: "680bd2c7ee501290377f6686",
|
||||
@@ -197,6 +133,13 @@ export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
// This is a required safety check to prevent parts management only users from accessing /manage based routes
|
||||
if (partsManagementOnly && !import.meta.env.DEV) {
|
||||
// This NEEDS to be done this way, DO NOT use the react router, it will cause a ton of side effects
|
||||
window.location = "/parts";
|
||||
return null; // Prevent further rendering
|
||||
}
|
||||
|
||||
const AppRouteTable = (
|
||||
<Suspense
|
||||
fallback={
|
||||
@@ -638,13 +581,6 @@ export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
|
||||
else if (bodyshop && bodyshop.sub_status !== "active") PageContent = <ShopSubStatusComponent />;
|
||||
else PageContent = AppRouteTable;
|
||||
|
||||
const broadcastMessage = () => {
|
||||
if (socket && bodyshop && bodyshop.id) {
|
||||
console.log(`Broadcasting message to bodyshop ${bodyshop.id}:`);
|
||||
socket.emit("broadcast-to-bodyshop", bodyshop.id, `Hello from ${clientId}`);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<ChatAffixContainer bodyshop={bodyshop} chatVisible={chatVisible} />
|
||||
@@ -659,41 +595,10 @@ export function Manage({ conflict, bodyshop, alerts, setAlerts }) {
|
||||
|
||||
<FloatButton.BackTop style={{ right: 100, bottom: 25 }} />
|
||||
</Content>
|
||||
<Footer>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
margin: "1rem 0rem"
|
||||
}}
|
||||
>
|
||||
<Link to="/manage/feature-request">
|
||||
<Button icon={<BulbOutlined />} type="text">
|
||||
{t("general.labels.feature-request")}
|
||||
</Button>
|
||||
</Link>
|
||||
<Space>
|
||||
<WssStatusDisplayComponent />
|
||||
<div onClick={broadcastMessage}>
|
||||
{`${InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline")
|
||||
})} - ${import.meta.env.VITE_APP_GIT_SHA_DATE}`}
|
||||
</div>
|
||||
<Button icon={<AlertOutlined />} data-canny-changelog type="text">
|
||||
{t("general.labels.changelog")}
|
||||
</Button>
|
||||
</Space>
|
||||
<Link to="/disclaimer" target="_blank" style={{ color: "#ccc" }}>
|
||||
Disclaimer & Notices
|
||||
</Link>
|
||||
</div>
|
||||
</Footer>
|
||||
<GlobalFooter />
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Manage);
|
||||
export default connect(mapStateToProps)(Manage);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
.content-container {
|
||||
padding: 1rem;
|
||||
}
|
||||
|
||||
.layout-container {
|
||||
// height: 100vh;
|
||||
// overflow-y: auto;
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Col, Divider, Row } from "antd";
|
||||
import React from "react";
|
||||
import OwnerDetailForm from "../../components/owner-detail-form/owner-detail-form.container";
|
||||
import OwnerDetailJobsComponent from "../../components/owner-detail-jobs/owner-detail-jobs.component";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -57,7 +57,7 @@ export function OwnersDetailContainer({ setBreadcrumbs, addRecentItem, setSelect
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.owners_by_pk) return <NotFound />;
|
||||
if (!data.owners_by_pk) return <NotFound />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="owners:detail">
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import OwnersListContainer from "../../components/owners-list/owners-list.container";
|
||||
|
||||
export default function OwnersPageComponent() {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import OwnersPageComponent from "./owners.page.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import PartsQueueDetailCard from "../../components/parts-queue-card/parts-queue-card.component";
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import { Tabs } from "antd";
|
||||
import queryString from "query-string";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import ShopVendorPageComponent from "../shop-vendor/shop-vendor.page.component";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import PartsShopInfoContainer from "../../components/parts-shop-info/parts-shop-info.container";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs))
|
||||
});
|
||||
|
||||
export function PartsSettingsPage({ setSelectedHeader, setBreadcrumbs }) {
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
const search = queryString.parse(useLocation().search);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.parts_settings", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("settings");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/parts",
|
||||
label: t("titles.bc.parts")
|
||||
},
|
||||
{
|
||||
link: "/parts/settings",
|
||||
label: t("titles.bc.parts_settings")
|
||||
}
|
||||
]);
|
||||
}, [t, setSelectedHeader, setBreadcrumbs]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!search.tab) history({ search: "?tab=shop" });
|
||||
}, [history, search]);
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: "shop",
|
||||
label: t("bodyshop.labels.parts_shop_management"),
|
||||
children: (
|
||||
<RbacWrapper action="shop:config">
|
||||
<PartsShopInfoContainer />
|
||||
</RbacWrapper>
|
||||
)
|
||||
},
|
||||
{
|
||||
key: "vendors",
|
||||
label: t("bodyshop.labels.parts_vendor_management"),
|
||||
children: (
|
||||
<RbacWrapper action="shop:vendors">
|
||||
<ShopVendorPageComponent />
|
||||
</RbacWrapper>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return <Tabs activeKey={search.tab} onChange={(key) => history({ search: `?tab=${key}` })} items={items} />;
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(PartsSettingsPage);
|
||||
@@ -3,7 +3,6 @@ import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Input, Space, Table, Typography } from "antd";
|
||||
import _ from "lodash";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
@@ -95,13 +94,13 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
title: t("phonebook.fields.phone1"),
|
||||
dataIndex: "phone1",
|
||||
key: "phone1",
|
||||
render: (text, record) => <ChatOpenButton phone={text} />
|
||||
render: (text) => <ChatOpenButton phone={text} />
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.phone2"),
|
||||
dataIndex: "phone2",
|
||||
key: "phone2",
|
||||
render: (text, record) => <ChatOpenButton phone={text} />
|
||||
render: (text) => <ChatOpenButton phone={text} />
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.address1"),
|
||||
@@ -179,12 +178,12 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
current: parseInt(page || 1, 10),
|
||||
total: data && data.search_phonebook_aggregate.aggregate.count
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_phonebook}
|
||||
dataSource={data?.search_phonebook}
|
||||
//scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
@@ -192,9 +191,9 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
type: "radio",
|
||||
selectedRowKeys: [phonebookentry]
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
onRow={(record) => {
|
||||
return {
|
||||
onClick: (event) => {
|
||||
onClick: () => {
|
||||
handleOnRowClick(record);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import React from "react";
|
||||
import ProductionBoardKanbanContainer from "../../components/production-board-kanban/production-board-kanban.container";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = () => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardComponent);
|
||||
@@ -19,7 +19,7 @@ export function ProductionBoardComponent({ bodyshop }) {
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Production_Use_View"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
splitKey: bodyshop?.imexshopid
|
||||
});
|
||||
|
||||
return <ProductionBoardKanbanContainer subscriptionType={Production_Use_View.treatment} />;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Card } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
@@ -7,20 +7,17 @@ import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.com
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import ProductionBoardComponent from "./production-board.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapStateToProps = createStructuredSelector({});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ProductionBoardContainer({ setBreadcrumbs, bodyshop, setSelectedHeader }) {
|
||||
export function ProductionBoardContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import NoteUpsertModal from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||
import ProductionListTable from "../../components/production-list-table/production-list-table.container";
|
||||
|
||||
@@ -6,10 +5,11 @@ import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = () => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ProductionListComponent);
|
||||
@@ -20,7 +20,7 @@ export function ProductionListComponent({ bodyshop }) {
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Production_Use_View"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
splitKey: bodyshop?.imexshopid
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
@@ -18,8 +18,7 @@ export function ProfileContainerPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
document.title = t("titles.profile", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
|
||||
rome: "$t(titles.romeonline)"
|
||||
})
|
||||
});
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Row } from "antd";
|
||||
import React from "react";
|
||||
import ProfileMyComponent from "../../components/profile-my/profile-my.component";
|
||||
import ProfileShopsContainer from "../../components/profile-shops/profile-shops.container";
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import UserRequestResetPw from "../../components/user-request-pw-reset/user-request-reset-pw.component";
|
||||
import UserValidatePwReset from "../../components/user-validate-pw-reset/user-validate-pw-reset.component";
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Row } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Drawer, Grid } from "antd";
|
||||
import React from "react";
|
||||
import { useNavigate, useSearchParams } from "react-router-dom";
|
||||
import VendorsFormContainer from "../../components/vendors-form/vendors-form.container";
|
||||
import VendorsListContainer from "../../components/vendors-list/vendors-list.container";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import ShopVendorPageComponent from "./shop-vendor.page.component";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Tabs } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
@@ -100,7 +100,7 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
|
||||
children: <ShopInfoConsentComponent bodyshop={bodyshop} />
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<RbacWrapper action="shop:config">
|
||||
<Tabs activeKey={search.tab} onChange={(key) => history({ search: `?tab=${key}` })} items={items} />
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import SignIn from "../../components/sign-in-form/sign-in-form.component";
|
||||
|
||||
export default function SignInPage() {
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
import { BarsOutlined, PrinterFilled, SyncOutlined, ToolFilled } from "@ant-design/icons";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Divider, Form, Space, Tabs } from "antd";
|
||||
import queryString from "query-string";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import FormFieldsChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component.jsx";
|
||||
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container.jsx";
|
||||
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container.jsx";
|
||||
import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component.jsx";
|
||||
import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component.jsx";
|
||||
import JobsDetailHeaderActions from "../../components/jobs-detail-header-actions/jobs-detail-header-actions.component.jsx";
|
||||
import JobsDetailHeader from "../../components/jobs-detail-header/jobs-detail-header.component.jsx";
|
||||
import JobsDetailPliContainer from "../../components/jobs-detail-pli/jobs-detail-pli.container.jsx";
|
||||
import { QUERY_PARTS_BILLS_BY_JOBID } from "../../graphql/bills.queries.js";
|
||||
import { selectIsPartsEntry, selectJobReadOnly } from "../../redux/application/application.selectors.js";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
jobRO: selectJobReadOnly,
|
||||
isPartsEntry: selectIsPartsEntry
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPrintCenterContext: (context) =>
|
||||
dispatch(
|
||||
setModalContext({
|
||||
context: context,
|
||||
modal: "printCenter"
|
||||
})
|
||||
)
|
||||
});
|
||||
|
||||
export function SimplifiedPartsJobDetailComponent({ setPrintCenterContext, jobRO, job, refetch, isPartsEntry }) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const history = useNavigate();
|
||||
const [loading] = useState(false);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
|
||||
const billsQuery = useQuery(QUERY_PARTS_BILLS_BY_JOBID, {
|
||||
variables: { jobid: job.id },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
//form.setFieldsValue(transormJobToForm(job));
|
||||
form.resetFields();
|
||||
}, [form, job]);
|
||||
|
||||
const handleBillOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.billid = record.id;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.billid;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
};
|
||||
|
||||
const handlePartsOrderOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.partsorderid = record.id;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.partsorderid;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}
|
||||
};
|
||||
|
||||
const handlePartsDispatchOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
search.partsdispatchid = record.id;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}
|
||||
} else {
|
||||
delete search.partsdispatchid;
|
||||
history.push({ search: queryString.stringify(search) });
|
||||
}
|
||||
};
|
||||
|
||||
const menuExtra = (
|
||||
<Space wrap>
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetch();
|
||||
}}
|
||||
key="refresh"
|
||||
>
|
||||
<SyncOutlined />
|
||||
{t("general.labels.refresh")}
|
||||
</Button>
|
||||
<JobsChangeStatus job={job} />
|
||||
<Button
|
||||
onClick={() => {
|
||||
setPrintCenterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {
|
||||
id: job.id,
|
||||
job: job,
|
||||
type: "job"
|
||||
}
|
||||
});
|
||||
}}
|
||||
key="printing"
|
||||
>
|
||||
<PrinterFilled />
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>
|
||||
|
||||
{!isPartsEntry && (
|
||||
<>
|
||||
<JobsDetailHeaderActions key="actions" job={job} refetch={refetch} />
|
||||
<Button type="primary" loading={loading} disabled={jobRO} onClick={() => form.submit()}>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<JobLineUpsertModalContainer />
|
||||
|
||||
<PageHeader title={<Space>{job.ro_number || t("general.labels.na")}</Space>} extra={menuExtra} />
|
||||
<JobsDetailHeader job={job} disabled={true} />
|
||||
<Divider type="horizontal" />
|
||||
<JobProfileDataWarning job={job} />
|
||||
<FormFieldsChanged form={form} />
|
||||
<Tabs
|
||||
defaultActiveKey={search.tab}
|
||||
onChange={(key) => history({ search: `?tab=${key}` })}
|
||||
tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }}
|
||||
items={[
|
||||
{
|
||||
key: "repairdata",
|
||||
icon: <BarsOutlined />,
|
||||
id: "job-details-repairdata",
|
||||
label: t("menus.jobsdetail.repairdata"),
|
||||
forceRender: true,
|
||||
children: (
|
||||
<JobsLinesContainer
|
||||
job={job}
|
||||
joblines={job.joblines}
|
||||
billsQuery={billsQuery}
|
||||
handleBillOnRowClick={handleBillOnRowClick}
|
||||
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
|
||||
refetch={refetch}
|
||||
form={form}
|
||||
/>
|
||||
)
|
||||
},
|
||||
|
||||
{
|
||||
key: "partssublet",
|
||||
id: "job-details-partssublet",
|
||||
icon: <ToolFilled />,
|
||||
label: t("menus.jobsdetail.partssublet"),
|
||||
children: (
|
||||
<JobsDetailPliContainer
|
||||
job={job}
|
||||
billsQuery={billsQuery}
|
||||
handleBillOnRowClick={handleBillOnRowClick}
|
||||
handlePartsOrderOnRowClick={handlePartsOrderOnRowClick}
|
||||
handlePartsDispatchOnRowClick={handlePartsDispatchOnRowClick}
|
||||
/>
|
||||
)
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SimplifiedPartsJobDetailComponent);
|
||||
@@ -0,0 +1,103 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import SpinComponent from "../../components/loading-spinner/loading-spinner.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
import {
|
||||
addRecentItem,
|
||||
setBreadcrumbs,
|
||||
setJobReadOnly,
|
||||
setSelectedHeader
|
||||
} from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import IsJobReadOnly from "../../utils/jobReadOnly";
|
||||
import SimplifiedPartsJobsDetailComponent from "./simplified-parts-jobs-detail.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool))
|
||||
});
|
||||
|
||||
function SimplifiedPartsJobsDetailContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader, setJobReadOnly }) {
|
||||
const { jobId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = loading
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline")
|
||||
})
|
||||
: error
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline")
|
||||
})
|
||||
: t("titles.jobsdetail", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
}),
|
||||
ro_number: (data.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na")
|
||||
});
|
||||
setBreadcrumbs([
|
||||
{ link: "/parts/", label: t("titles.bc.jobs") },
|
||||
{
|
||||
link: `/parts/jobs/${jobId}`,
|
||||
label: t("titles.bc.jobs-detail", {
|
||||
number: (data && data.jobs_by_pk && data.jobs_by_pk.ro_number) || t("general.labels.na")
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
jobId,
|
||||
"job",
|
||||
|
||||
`${data.jobs_by_pk.ro_number || t("general.labels.na")} | ${OwnerNameDisplayFunction(data.jobs_by_pk)}`,
|
||||
`/parts/jobs/${jobId}`
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [loading, data, t, error, setBreadcrumbs, jobId, addRecentItem, setSelectedHeader, setJobReadOnly]);
|
||||
|
||||
if (loading) return <SpinComponent />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!data.jobs_by_pk) return <NotFound />;
|
||||
|
||||
return data.jobs_by_pk ? (
|
||||
<RbacWrapper action="jobs:detail">
|
||||
<SimplifiedPartsJobsDetailComponent job={data.jobs_by_pk} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
) : (
|
||||
<AlertComponent message={t("jobs.errors.noaccess")} type="error" />
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SimplifiedPartsJobsDetailContainer);
|
||||
@@ -0,0 +1,36 @@
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import SimplifiedPartsJobsListContainer from "../../components/simplified-parts-jobs-list/simplified-parts-jobs-list.container";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function SimplifiedPartsJobsPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.simplified-parts-jobs", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("parts-queue");
|
||||
setBreadcrumbs([{ link: "/parts", label: t("titles.bc.simplified-parts-jobs") }]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:partsqueue">
|
||||
<SimplifiedPartsJobsListContainer />
|
||||
{/* <PartsQueueDetailCard /> */}
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(SimplifiedPartsJobsPage);
|
||||
@@ -0,0 +1,142 @@
|
||||
import * as Sentry from "@sentry/react";
|
||||
import { FloatButton, Layout, Spin } from "antd";
|
||||
import { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Route, Routes } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component.jsx";
|
||||
import ConflictComponent from "../../components/conflict/conflict.component.jsx";
|
||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component.jsx";
|
||||
import GlobalFooter from "../../components/global-footer/global-footer.component.jsx";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component.jsx";
|
||||
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component.jsx";
|
||||
import UpdateAlert from "../../components/update-alert/update-alert.component.jsx";
|
||||
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors.js";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
|
||||
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
|
||||
|
||||
const SimplifiedPartsJobsPage = lazy(() => import("../simplified-parts-jobs/simplified-parts-jobs.page.jsx"));
|
||||
const SimplifiedPartsJobsDetailPage = lazy(
|
||||
() => import("../simplified-parts-jobs-detail/simplified-parts-jobs-detail.container.jsx")
|
||||
);
|
||||
const PartsSettingsPage = lazy(() => import("../parts-settings/parts-settings.page.component.jsx"));
|
||||
const ShopVendorPageContainer = lazy(() => import("../shop-vendor/shop-vendor.page.container.jsx"));
|
||||
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx"));
|
||||
const ReportCenterModal = lazy(() => import("../../components/report-center-modal/report-center-modal.container.jsx"));
|
||||
const PrintCenterModalContainer = lazy(
|
||||
() => import("../../components/print-center-modal/print-center-modal.container")
|
||||
);
|
||||
const VehiclesContainer = lazy(() => import("../vehicles/vehicles.page.container.jsx"));
|
||||
const VehiclesDetailContainer = lazy(() => import("../vehicles-detail/vehicles-detail.page.container.jsx"));
|
||||
const { Content } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
conflict: selectInstanceConflict,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
export function SimplifiedPartsPage({ conflict, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// Centralized alerts handling (fetch + dedupe + notifications)
|
||||
useAlertsNotifications();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline")
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
const AppRouteTable = (
|
||||
<Suspense
|
||||
fallback={
|
||||
<LoadingSpinner
|
||||
message={t("general.labels.loadingapp", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)"
|
||||
})
|
||||
})}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<BreadCrumbs />
|
||||
<ReportCenterModal />
|
||||
<EmailOverlayContainer />
|
||||
<PrintCenterModalContainer />
|
||||
<Routes>
|
||||
<Route
|
||||
path="/"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<SimplifiedPartsJobsPage />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/jobs/:jobId"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<SimplifiedPartsJobsDetailPage />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/vehicles"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<VehiclesContainer />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/vehicles/:vehId"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<VehiclesDetailContainer />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/shop/vendors"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<ShopVendorPageContainer />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path="/settings"
|
||||
element={
|
||||
<Suspense fallback={<Spin />}>
|
||||
<PartsSettingsPage />
|
||||
</Suspense>
|
||||
}
|
||||
/>
|
||||
</Routes>
|
||||
</Suspense>
|
||||
);
|
||||
|
||||
let PageContent;
|
||||
|
||||
if (conflict) PageContent = <ConflictComponent />;
|
||||
else if (bodyshop && bodyshop.sub_status !== "active") PageContent = <ShopSubStatusComponent />;
|
||||
else PageContent = AppRouteTable;
|
||||
|
||||
return (
|
||||
<Layout style={{ minHeight: "100vh" }} className="layout-container">
|
||||
<UpdateAlert />
|
||||
<Content className="content-container">
|
||||
<Sentry.ErrorBoundary fallback={<ErrorBoundary />} showDialog>
|
||||
{PageContent}
|
||||
</Sentry.ErrorBoundary>
|
||||
<FloatButton.BackTop style={{ right: 100, bottom: 25 }} />
|
||||
</Content>
|
||||
<GlobalFooter />
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(SimplifiedPartsPage);
|
||||
@@ -0,0 +1,35 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
import { setBodyshop } from "../../redux/user/user.actions";
|
||||
import SimplifiedPartsPage from "./simplified-parts.page.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs))
|
||||
});
|
||||
|
||||
function SimplifiedPartsPageContainer({ setBodyshop }) {
|
||||
const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setBodyshop(data.bodyshops[0] || { notfound: true });
|
||||
}
|
||||
}, [data, setBodyshop]);
|
||||
|
||||
if (loading) return <LoadingSpinner message={t("general.labels.loadingshop")} />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return <SimplifiedPartsPage />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(SimplifiedPartsPageContainer);
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useState } from "react";
|
||||
import { useState } from "react";
|
||||
import { Button, Card, Input, Space, Table } from "antd";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -2,7 +2,6 @@ import { MinusCircleTwoTone, PlusCircleTwoTone, SyncOutlined } from "@ant-design
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Space, Table } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
@@ -20,7 +19,7 @@ const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
const mapDispatchToProps = () => ({});
|
||||
|
||||
export function TechDispatchedParts({ technician, bodyshop }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
@@ -83,12 +82,20 @@ export function TechDispatchedParts({ technician, bodyshop }) {
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => <Button onClick={() => {}}>{t("timetickets.actions.claimtasks")}</Button>
|
||||
render: () => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
// NO OP
|
||||
}}
|
||||
>
|
||||
{t("timetickets.actions.claimtasks")}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
]
|
||||
: [])
|
||||
];
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
const handleTableChange = (pagination) => {
|
||||
searchParams.page = pagination.current;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
};
|
||||
@@ -107,7 +114,7 @@ export function TechDispatchedParts({ technician, bodyshop }) {
|
||||
loading={loading}
|
||||
pagination={{
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
current: parseInt(page || 1, 10),
|
||||
total: data ? data.parts_dispatch_aggregate.aggregate.count : 0,
|
||||
showSizeChanger: false
|
||||
}}
|
||||
@@ -118,7 +125,7 @@ export function TechDispatchedParts({ technician, bodyshop }) {
|
||||
onChange={handleTableChange}
|
||||
expandable={{
|
||||
expandedRowRender: (record) => <PartsDispatchExpander dispatch={record} />,
|
||||
rowExpandable: (record) => true,
|
||||
rowExpandable: () => true,
|
||||
//expandRowByClick: true,
|
||||
expandIcon: ({ expanded, onExpand, record }) =>
|
||||
expanded ? (
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Divider } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import TechClockInFormContainer from "../../components/tech-job-clock-in-form/tech-job-clock-in-form.container";
|
||||
import TechClockedInList from "../../components/tech-job-clocked-in-list/tech-job-clocked-in-list.component";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RbacWrapperComponent from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TechLookupJobsList from "../../components/tech-lookup-jobs-list/tech-lookup-jobs-list.component";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Card, FloatButton, Layout } from "antd";
|
||||
import React, { lazy, Suspense, useEffect } from "react";
|
||||
import { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||
@@ -40,7 +40,7 @@ const { Content } = Layout;
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = () => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React from "react";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobsDocumentsContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
@@ -14,7 +13,7 @@ import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
const mapDispatchToProps = () => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TemporaryDocsComponent);
|
||||
@@ -25,7 +24,7 @@ export function TemporaryDocsComponent({ bodyshop }) {
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Imgproxy"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
splitKey: bodyshop?.imexshopid
|
||||
});
|
||||
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_TEMPORARY_DOCS, {
|
||||
@@ -41,14 +40,12 @@ export function TemporaryDocsComponent({ bodyshop }) {
|
||||
return <JobsDocumentsLocalGallery job={{ id: "temporary" }} />;
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<JobsDocumentsContainer
|
||||
documentsList={data ? data.documents : []}
|
||||
jobId={null}
|
||||
billId={null}
|
||||
refetchOverride={refetch}
|
||||
ignoreSizeLimit
|
||||
/>
|
||||
</>
|
||||
<JobsDocumentsContainer
|
||||
documentsList={data ? data.documents : []}
|
||||
jobId={null}
|
||||
billId={null}
|
||||
refetchOverride={refetch}
|
||||
ignoreSizeLimit
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Row, Space } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { Col, Divider, Row } from "antd";
|
||||
import React from "react";
|
||||
import VehicleDetailFormContainer from "../../components/vehicle-detail-form/vehicle-detail-form.container";
|
||||
import VehicleDetailJobsComponent from "../../components/vehicle-detail-jobs/vehicle-detail-jobs.component";
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import VehicleDetailComponent from "./vehicles-detail.page.component";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useParams } from "react-router-dom";
|
||||
@@ -11,6 +11,13 @@ import { connect } from "react-redux";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { selectIsPartsEntry } from "../../redux/application/application.selectors";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import getPartsBasePath from "../../utils/getPartsBasePath.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
isPartsEntry: selectIsPartsEntry
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
@@ -18,9 +25,10 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader }) {
|
||||
export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader, isPartsEntry }) {
|
||||
const { vehId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
const basePath = getPartsBasePath(isPartsEntry);
|
||||
|
||||
const { loading, data, error, refetch } = useQuery(QUERY_VEHICLE_BY_ID, {
|
||||
variables: { id: vehId },
|
||||
@@ -43,20 +51,22 @@ export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelec
|
||||
});
|
||||
setSelectedHeader("vehicles");
|
||||
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/vehicles", label: t("titles.bc.vehicles") },
|
||||
{
|
||||
link: `/manage/vehicles/${vehId}`,
|
||||
label: t("titles.bc.vehicle-details", {
|
||||
vehicle:
|
||||
data && data.vehicles_by_pk
|
||||
? `${(data.vehicles_by_pk && data.vehicles_by_pk.v_model_yr) || ""} ${
|
||||
(data.vehicles_by_pk && data.vehicles_by_pk.v_make_desc) || ""
|
||||
} ${(data.vehicles_by_pk && data.vehicles_by_pk.v_model_desc) || ""}`
|
||||
: ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
const crumbs = [];
|
||||
if (isPartsEntry) crumbs.push({ link: "/parts/", label: t("titles.bc.jobs") });
|
||||
crumbs.push({ link: `${basePath}/vehicles`, label: t("titles.bc.vehicles") });
|
||||
crumbs.push({
|
||||
link: `${basePath}/vehicles/${vehId}`,
|
||||
label: t("titles.bc.vehicle-details", {
|
||||
vehicle:
|
||||
data && data.vehicles_by_pk
|
||||
? `${(data.vehicles_by_pk && data.vehicles_by_pk.v_model_yr) || ""} ${
|
||||
(data.vehicles_by_pk && data.vehicles_by_pk.v_make_desc) || ""
|
||||
} ${(data.vehicles_by_pk && data.vehicles_by_pk.v_model_desc) || ""}`
|
||||
: ""
|
||||
})
|
||||
});
|
||||
|
||||
setBreadcrumbs(crumbs);
|
||||
|
||||
if (data && data.vehicles_by_pk)
|
||||
addRecentItem(
|
||||
@@ -66,10 +76,10 @@ export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelec
|
||||
`${data.vehicles_by_pk.v_vin || "N/A"} | ${
|
||||
data.vehicles_by_pk.v_model_yr || ""
|
||||
} ${data.vehicles_by_pk.v_make_desc || ""} ${data.vehicles_by_pk.v_model_desc || ""}`.trim(),
|
||||
`/manage/vehicles/${vehId}`
|
||||
`${basePath}/vehicles/${vehId}`
|
||||
)
|
||||
);
|
||||
}, [t, data, setBreadcrumbs, vehId, addRecentItem, setSelectedHeader]);
|
||||
}, [t, data, setBreadcrumbs, vehId, addRecentItem, setSelectedHeader, basePath, isPartsEntry]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
@@ -77,4 +87,4 @@ export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelec
|
||||
return <VehicleDetailComponent vehicle={data.vehicles_by_pk} refetch={refetch} />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(VehicleDetailContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VehicleDetailContainer);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import React from "react";
|
||||
import VehiclesListContainer from "../../components/vehicles-list/vehicles-list.container";
|
||||
|
||||
export default function VehiclesPageComponent() {
|
||||
|
||||
@@ -1,18 +1,26 @@
|
||||
import React, { useEffect } from "react";
|
||||
import { useEffect } from "react";
|
||||
import VehiclesPageComponent from "./vehicles.page.component";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectIsPartsEntry } from "../../redux/application/application.selectors.js";
|
||||
import getPartsBasePath from "../../utils/getPartsBasePath.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
isPartsEntry: selectIsPartsEntry
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function VehiclesPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
export function VehiclesPageContainer({ setBreadcrumbs, setSelectedHeader, isPartsEntry }) {
|
||||
const { t } = useTranslation();
|
||||
const basePath = getPartsBasePath(isPartsEntry);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.vehicles", {
|
||||
@@ -22,10 +30,18 @@ export function VehiclesPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
})
|
||||
});
|
||||
setSelectedHeader("vehicles");
|
||||
setBreadcrumbs([{ link: "/manage/vehicles", label: t("titles.bc.vehicles") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
if (isPartsEntry) {
|
||||
setBreadcrumbs([
|
||||
{ link: "/parts/", label: t("titles.bc.jobs") },
|
||||
{ link: `${basePath}/vehicles`, label: t("titles.bc.vehicles") }
|
||||
]);
|
||||
} else {
|
||||
setBreadcrumbs([{ link: `${basePath}/vehicles`, label: t("titles.bc.vehicles") }]);
|
||||
}
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, basePath, isPartsEntry]);
|
||||
|
||||
return <VehiclesPageComponent />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(VehiclesPageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(VehiclesPageContainer);
|
||||
|
||||
Reference in New Issue
Block a user