@@ -1,88 +1,71 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AccountingPayablesTable from "../../components/accounting-payables-table/accounting-payables-table.component";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {checkPartnerStatus} from "../../components/partner-ping/partner-ping.component";
|
||||
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_BILLS_FOR_EXPORT} from "../../graphql/accounting.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectPartnerVersion} from "../../redux/application/application.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { QUERY_BILLS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion,
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AccountingPayablesContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
partnerVersion,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function AccountingPayablesContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, partnerVersion }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-payables",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("payables");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payables",
|
||||
label: t("titles.bc.accounting-payables"),
|
||||
},
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(QUERY_BILLS_FOR_EXPORT, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-payables", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("payables");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payables",
|
||||
label: t("titles.bc.accounting-payables")
|
||||
}
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_BILLS_FOR_EXPORT, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(
|
||||
bodyshop &&
|
||||
(bodyshop.cdk_dealerid ||
|
||||
bodyshop.pbs_serialnumber ||
|
||||
bodyshop.accountingconfig.qbo)
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName='export'>
|
||||
<RbacWrapper action="accounting:payables">
|
||||
{noPath && (
|
||||
<AlertComponent
|
||||
type="error"
|
||||
message={t("general.messages.noacctfilepath")}
|
||||
/>
|
||||
)}
|
||||
<AccountingPayablesTable
|
||||
loadaing={loading}
|
||||
bills={data ? data.bills : []}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(bodyshop && (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || bodyshop.accountingconfig.qbo));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName="export">
|
||||
<RbacWrapper action="accounting:payables">
|
||||
{noPath && <AlertComponent type="error" message={t("general.messages.noacctfilepath")} />}
|
||||
<AccountingPayablesTable loadaing={loading} bills={data ? data.bills : []} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AccountingPayablesContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountingPayablesContainer);
|
||||
|
||||
@@ -1,88 +1,69 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AccountingPaymentsTable from "../../components/accounting-payments-table/accounting-payments-table.component";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {QUERY_PAYMENTS_FOR_EXPORT} from "../../graphql/accounting.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { QUERY_PAYMENTS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {checkPartnerStatus} from "../../components/partner-ping/partner-ping.component";
|
||||
import {selectPartnerVersion} from "../../redux/application/application.selectors";
|
||||
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion,
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AccountingPaymentsContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
partnerVersion,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function AccountingPaymentsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, partnerVersion }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-payments", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("payments");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payments",
|
||||
label: t("titles.bc.accounting-payments"),
|
||||
},
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-payments", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("payments");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payments",
|
||||
label: t("titles.bc.accounting-payments")
|
||||
}
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_PAYMENTS_FOR_EXPORT,
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
}
|
||||
);
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_PAYMENTS_FOR_EXPORT, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(
|
||||
bodyshop &&
|
||||
(bodyshop.cdk_dealerid ||
|
||||
bodyshop.pbs_serialnumber ||
|
||||
bodyshop.accountingconfig.qbo)
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName='export'>
|
||||
<RbacWrapper action="accounting:payments">
|
||||
{noPath && (
|
||||
<AlertComponent
|
||||
type="error"
|
||||
message={t("general.messages.noacctfilepath")}
|
||||
/>
|
||||
)}
|
||||
<AccountingPaymentsTable
|
||||
loadaing={loading}
|
||||
payments={data ? data.payments : []}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(bodyshop && (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || bodyshop.accountingconfig.qbo));
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName="export">
|
||||
<RbacWrapper action="accounting:payments">
|
||||
{noPath && <AlertComponent type="error" message={t("general.messages.noacctfilepath")} />}
|
||||
<AccountingPaymentsTable loadaing={loading} payments={data ? data.payments : []} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AccountingPaymentsContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountingPaymentsContainer);
|
||||
|
||||
@@ -1,46 +1,39 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { 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";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AccountingReceivablesContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function AccountingReceivablesContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-qbo");
|
||||
setSelectedHeader("qbo");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/qbo",
|
||||
label: t("titles.bc.accounting-qbo"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-qbo");
|
||||
setSelectedHeader("qbo");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/qbo",
|
||||
label: t("titles.bc.accounting-qbo")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<QboAuthorizeComponent/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<QboAuthorizeComponent />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AccountingReceivablesContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountingReceivablesContainer);
|
||||
|
||||
@@ -1,91 +1,74 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import AccountingReceivablesTable
|
||||
from "../../components/accounting-receivables-table/accounting-receivables-table.component";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AccountingReceivablesTable from "../../components/accounting-receivables-table/accounting-receivables-table.component";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {QUERY_JOBS_FOR_EXPORT} from "../../graphql/accounting.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { QUERY_JOBS_FOR_EXPORT } from "../../graphql/accounting.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {checkPartnerStatus} from "../../components/partner-ping/partner-ping.component";
|
||||
import {selectPartnerVersion} from "../../redux/application/application.selectors";
|
||||
import { checkPartnerStatus } from "../../components/partner-ping/partner-ping.component";
|
||||
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion,
|
||||
bodyshop: selectBodyshop,
|
||||
partnerVersion: selectPartnerVersion
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AccountingReceivablesContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
partnerVersion,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function AccountingReceivablesContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, partnerVersion }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-receivables",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("receivables");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/receivables",
|
||||
label: t("titles.bc.accounting-receivables"),
|
||||
},
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(QUERY_JOBS_FOR_EXPORT, {
|
||||
variables: {
|
||||
invoicedStatus: bodyshop.md_ro_statuses.default_invoiced || "Invoiced*",
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
useEffect(() => {
|
||||
document.title = t("titles.accounting-receivables", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("receivables");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/receivables",
|
||||
label: t("titles.bc.accounting-receivables")
|
||||
}
|
||||
]);
|
||||
checkPartnerStatus(bodyshop, true);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader, bodyshop]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_JOBS_FOR_EXPORT, {
|
||||
variables: {
|
||||
invoicedStatus: bodyshop.md_ro_statuses.default_invoiced || "Invoiced*"
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(
|
||||
bodyshop &&
|
||||
(bodyshop.cdk_dealerid ||
|
||||
bodyshop.pbs_serialnumber ||
|
||||
bodyshop.accountingconfig.qbo)
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName="export">
|
||||
<RbacWrapper action="accounting:receivables">
|
||||
{noPath && (
|
||||
<AlertComponent
|
||||
type="error"
|
||||
message={t("general.messages.noacctfilepath")}
|
||||
/>
|
||||
)}
|
||||
<AccountingReceivablesTable
|
||||
loadaing={loading}
|
||||
jobs={data ? data.jobs : []}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
const noPath =
|
||||
!partnerVersion?.qbpath &&
|
||||
!(bodyshop && (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber || bodyshop.accountingconfig.qbo));
|
||||
|
||||
return (
|
||||
<div>
|
||||
<FeatureWrapperComponent featureName="export">
|
||||
<RbacWrapper action="accounting:receivables">
|
||||
{noPath && <AlertComponent type="error" message={t("general.messages.noacctfilepath")} />}
|
||||
<AccountingReceivablesTable loadaing={loading} jobs={data ? data.jobs : []} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(AccountingReceivablesContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccountingReceivablesContainer);
|
||||
|
||||
@@ -1,318 +1,291 @@
|
||||
import {EditFilled, SyncOutlined} from "@ant-design/icons";
|
||||
import {Button, Card, Checkbox, Input, Space, Table, Typography} from "antd";
|
||||
import { EditFilled, SyncOutlined } from "@ant-design/icons";
|
||||
import { Button, Card, Checkbox, Input, Space, Table, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {Link, useLocation, useNavigate} from "react-router-dom";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link, useLocation, useNavigate } from "react-router-dom";
|
||||
import BillDeleteButton from "../../components/bill-delete-button/bill-delete-button.component";
|
||||
import PartsOrderModalContainer from "../../components/parts-order-modal/parts-order-modal.container";
|
||||
import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.component";
|
||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import CurrencyFormatter from "../../utils/CurrencyFormatter";
|
||||
import {DateFormatter} from "../../utils/DateFormatter";
|
||||
import {TemplateList} from "../../utils/TemplateConstants";
|
||||
import {alphaSort, dateSort} from "../../utils/sorters";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import { DateFormatter } from "../../utils/DateFormatter";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
import { alphaSort, dateSort } from "../../utils/sorters";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPartsOrderContext: (context) =>
|
||||
dispatch(setModalContext({context: context, modal: "partsOrder"})),
|
||||
setBillEnterContext: (context) =>
|
||||
dispatch(setModalContext({context: context, modal: "billEnter"})),
|
||||
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,
|
||||
}) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const {page} = search;
|
||||
const history = useNavigate();
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: {text: ""},
|
||||
});
|
||||
const Templates = TemplateList("bill");
|
||||
const {t} = useTranslation();
|
||||
const columns = [
|
||||
{
|
||||
title: t("bills.fields.vendorname"),
|
||||
dataIndex: "vendorname",
|
||||
key: "vendorname",
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// vendor: {
|
||||
// name: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
render: (text, record) => <span>{record.vendor.name}</span>,
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.invoice_number"),
|
||||
dataIndex: "invoice_number",
|
||||
key: "invoice_number",
|
||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "invoice_number" &&
|
||||
state.sortedInfo.order,
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// job: {
|
||||
// ro_number: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
render: (text, record) =>
|
||||
record.job && (
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
{record.job.ro_number}
|
||||
</Link>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.date"),
|
||||
dataIndex: "date",
|
||||
key: "date",
|
||||
sorter: (a, b) => dateSort(a.date, b.date),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
|
||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>,
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.total"),
|
||||
dataIndex: "total",
|
||||
key: "total",
|
||||
sorter: (a, b) => a.total - b.total,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<CurrencyFormatter>{record.total}</CurrencyFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.is_credit_memo"),
|
||||
dataIndex: "is_credit_memo",
|
||||
key: "is_credit_memo",
|
||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "is_credit_memo" &&
|
||||
state.sortedInfo.order,
|
||||
render: (text, record) => (
|
||||
<Checkbox checked={record.is_credit_memo}/>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.exported"),
|
||||
dataIndex: "exported",
|
||||
key: "exported",
|
||||
sorter: (a, b) => a.exported - b.exported,
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
|
||||
render: (text, record) => <Checkbox checked={record.exported}/>,
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Space wrap>
|
||||
<Link to={`/manage/bills?billid=${record.id}`}>
|
||||
<Button>
|
||||
<EditFilled/>
|
||||
</Button>
|
||||
</Link>
|
||||
{
|
||||
// <Button
|
||||
// disabled={record.is_credit_memo}
|
||||
// onClick={() =>
|
||||
// setPartsOrderContext({
|
||||
// actions: {},
|
||||
// context: {
|
||||
// jobId: record.jobid,
|
||||
// vendorId: record.vendorid,
|
||||
// returnFromBill: record.id,
|
||||
// invoiceNumber: record.invoice_number,
|
||||
// linesToOrder: record.billlines.map((i) => {
|
||||
// return {
|
||||
// line_desc: i.line_desc,
|
||||
// // db_price: i.actual_price,
|
||||
// act_price: i.actual_price,
|
||||
// cost: i.actual_cost,
|
||||
// quantity: i.quantity,
|
||||
// joblineid: i.joblineid,
|
||||
// };
|
||||
// }),
|
||||
// isReturn: true,
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
// >
|
||||
// {t("bills.actions.return")}
|
||||
// </Button>
|
||||
}
|
||||
<BillDeleteButton
|
||||
bill={record}
|
||||
callback={(deletedBillid) => {
|
||||
//Filter out the state and set it again.
|
||||
setOpenSearchResults((currentResults) =>
|
||||
currentResults.filter((bill) => bill.id !== deletedBillid)
|
||||
);
|
||||
}}
|
||||
/>
|
||||
{record.isinhouse && (
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: Templates.inhouse_invoice.key,
|
||||
variables: {id: record.id},
|
||||
}}
|
||||
messageObject={{subject: Templates.inhouse_invoice.subject}}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
),
|
||||
},
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({...state, filteredInfo: filters, sortedInfo: sorter});
|
||||
search.page = pagination.current;
|
||||
if (sorter && sorter.column && sorter.column.sortObject) {
|
||||
search.searchObj = JSON.stringify(sorter.column.sortObject(sorter.order));
|
||||
} else {
|
||||
delete search.searchObj;
|
||||
search.sortcolumn = sorter.order ? sorter.columnKey : null;
|
||||
search.sortorder = sorter.order;
|
||||
}
|
||||
search.sort = JSON.stringify({[sorter.columnKey]: sorter.order});
|
||||
history({search: queryString.stringify(search)});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchBills();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchBills(value) {
|
||||
try {
|
||||
setSearchLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: value || search.search,
|
||||
index: "bills",
|
||||
});
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setSearchLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t("bills.labels.bills")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
{search.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", {search: search.search})}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete search.search;
|
||||
delete search.page;
|
||||
history({search: queryString.stringify(search)});
|
||||
}}
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined/>
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setBillEnterContext({
|
||||
actions: {refetch: refetch},
|
||||
context: {},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.postbills")}
|
||||
</Button>
|
||||
|
||||
<Input.Search
|
||||
placeholder={search.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
search.search = value;
|
||||
history({search: queryString.stringify(search)});
|
||||
searchBills(value);
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<PartsOrderModalContainer/>
|
||||
|
||||
<Table
|
||||
loading={loading || searchLoading}
|
||||
// scroll={{
|
||||
// x: "50%", // y: "40rem"
|
||||
// }}
|
||||
scroll={{x: true}}
|
||||
pagination={
|
||||
search?.search
|
||||
? {
|
||||
pageSize: pageLimit,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
: {
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false,
|
||||
}
|
||||
}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={search?.search ? openSearchResults : data}
|
||||
onChange={handleTableChange}
|
||||
export function BillsListPage({ loading, data, refetch, total, setPartsOrderContext, setBillEnterContext }) {
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const [openSearchResults, setOpenSearchResults] = useState([]);
|
||||
const [searchLoading, setSearchLoading] = useState(false);
|
||||
const { page } = search;
|
||||
const history = useNavigate();
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: { text: "" }
|
||||
});
|
||||
const Templates = TemplateList("bill");
|
||||
const { t } = useTranslation();
|
||||
const columns = [
|
||||
{
|
||||
title: t("bills.fields.vendorname"),
|
||||
dataIndex: "vendorname",
|
||||
key: "vendorname",
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// vendor: {
|
||||
// name: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.vendor.name, b.vendor.name),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "vendorname" && state.sortedInfo.order,
|
||||
render: (text, record) => <span>{record.vendor.name}</span>
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.invoice_number"),
|
||||
dataIndex: "invoice_number",
|
||||
key: "invoice_number",
|
||||
sorter: (a, b) => alphaSort(a.invoice_number, b.invoice_number),
|
||||
sortOrder: state.sortedInfo.columnKey === "invoice_number" && state.sortedInfo.order
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
// sortObject: (direction) => {
|
||||
// return {
|
||||
// job: {
|
||||
// ro_number: direction
|
||||
// ? direction === "descend"
|
||||
// ? "desc"
|
||||
// : "asc"
|
||||
// : "desc",
|
||||
// },
|
||||
// };
|
||||
// },
|
||||
// sorter: (a, b) => alphaSort(a.job.ro_number, b.job.ro_number),
|
||||
// sortOrder:
|
||||
// state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
render: (text, record) => record.job && <Link to={`/manage/jobs/${record.job.id}`}>{record.job.ro_number}</Link>
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.date"),
|
||||
dataIndex: "date",
|
||||
key: "date",
|
||||
sorter: (a, b) => dateSort(a.date, b.date),
|
||||
sortOrder: state.sortedInfo.columnKey === "date" && state.sortedInfo.order,
|
||||
render: (text, record) => <DateFormatter>{record.date}</DateFormatter>
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.total"),
|
||||
dataIndex: "total",
|
||||
key: "total",
|
||||
sorter: (a, b) => a.total - b.total,
|
||||
sortOrder: state.sortedInfo.columnKey === "total" && state.sortedInfo.order,
|
||||
render: (text, record) => <CurrencyFormatter>{record.total}</CurrencyFormatter>
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.is_credit_memo"),
|
||||
dataIndex: "is_credit_memo",
|
||||
key: "is_credit_memo",
|
||||
sorter: (a, b) => a.is_credit_memo - b.is_credit_memo,
|
||||
sortOrder: state.sortedInfo.columnKey === "is_credit_memo" && state.sortedInfo.order,
|
||||
render: (text, record) => <Checkbox checked={record.is_credit_memo} />
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.exported"),
|
||||
dataIndex: "exported",
|
||||
key: "exported",
|
||||
sorter: (a, b) => a.exported - b.exported,
|
||||
sortOrder: state.sortedInfo.columnKey === "exported" && state.sortedInfo.order,
|
||||
render: (text, record) => <Checkbox checked={record.exported} />
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Space wrap>
|
||||
<Link to={`/manage/bills?billid=${record.id}`}>
|
||||
<Button>
|
||||
<EditFilled />
|
||||
</Button>
|
||||
</Link>
|
||||
{
|
||||
// <Button
|
||||
// disabled={record.is_credit_memo}
|
||||
// onClick={() =>
|
||||
// setPartsOrderContext({
|
||||
// actions: {},
|
||||
// context: {
|
||||
// jobId: record.jobid,
|
||||
// vendorId: record.vendorid,
|
||||
// returnFromBill: record.id,
|
||||
// invoiceNumber: record.invoice_number,
|
||||
// linesToOrder: record.billlines.map((i) => {
|
||||
// return {
|
||||
// line_desc: i.line_desc,
|
||||
// // db_price: i.actual_price,
|
||||
// act_price: i.actual_price,
|
||||
// cost: i.actual_cost,
|
||||
// quantity: i.quantity,
|
||||
// joblineid: i.joblineid,
|
||||
// };
|
||||
// }),
|
||||
// isReturn: true,
|
||||
// },
|
||||
// })
|
||||
// }
|
||||
// >
|
||||
// {t("bills.actions.return")}
|
||||
// </Button>
|
||||
}
|
||||
<BillDeleteButton
|
||||
bill={record}
|
||||
callback={(deletedBillid) => {
|
||||
//Filter out the state and set it again.
|
||||
setOpenSearchResults((currentResults) => currentResults.filter((bill) => bill.id !== deletedBillid));
|
||||
}}
|
||||
/>
|
||||
{record.isinhouse && (
|
||||
<PrintWrapperComponent
|
||||
templateObject={{
|
||||
name: Templates.inhouse_invoice.key,
|
||||
variables: { id: record.id }
|
||||
}}
|
||||
messageObject={{ subject: Templates.inhouse_invoice.subject }}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
)}
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
search.page = pagination.current;
|
||||
if (sorter && sorter.column && sorter.column.sortObject) {
|
||||
search.searchObj = JSON.stringify(sorter.column.sortObject(sorter.order));
|
||||
} else {
|
||||
delete search.searchObj;
|
||||
search.sortcolumn = sorter.order ? sorter.columnKey : null;
|
||||
search.sortorder = sorter.order;
|
||||
}
|
||||
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
|
||||
history({ search: queryString.stringify(search) });
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (search.search && search.search.trim() !== "") {
|
||||
searchBills();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
async function searchBills(value) {
|
||||
try {
|
||||
setSearchLoading(true);
|
||||
const searchData = await axios.post("/search", {
|
||||
search: value || search.search,
|
||||
index: "bills"
|
||||
});
|
||||
setOpenSearchResults(searchData.data.hits.hits.map((s) => s._source));
|
||||
} catch (error) {
|
||||
console.log("Error while fetching search results", error);
|
||||
} finally {
|
||||
setSearchLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card
|
||||
title={t("bills.labels.bills")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
{search.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", { search: search.search })}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete search.search;
|
||||
delete search.page;
|
||||
history({ search: queryString.stringify(search) });
|
||||
}}
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setBillEnterContext({
|
||||
actions: { refetch: refetch },
|
||||
context: {}
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("jobs.actions.postbills")}
|
||||
</Button>
|
||||
|
||||
<Input.Search
|
||||
placeholder={search.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
search.search = value;
|
||||
history({ search: queryString.stringify(search) });
|
||||
searchBills(value);
|
||||
}}
|
||||
loading={loading || searchLoading}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<PartsOrderModalContainer />
|
||||
|
||||
<Table
|
||||
loading={loading || searchLoading}
|
||||
// scroll={{
|
||||
// x: "50%", // y: "40rem"
|
||||
// }}
|
||||
scroll={{ x: true }}
|
||||
pagination={
|
||||
search?.search
|
||||
? {
|
||||
pageSize: pageLimit,
|
||||
showSizeChanger: false
|
||||
}
|
||||
: {
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: total,
|
||||
showSizeChanger: false
|
||||
}
|
||||
}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={search?.search ? openSearchResults : data}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(BillsListPage);
|
||||
|
||||
@@ -1,77 +1,74 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation} from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import BillDetailEditContainer from "../../components/bill-detail-edit/bill-detail-edit.container";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_ALL_BILLS_PAGINATED} from "../../graphql/bills.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { QUERY_ALL_BILLS_PAGINATED } from "../../graphql/bills.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import BillsPageComponent from "./bills.page.component";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function BillsPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder, searchObj} = searchParams;
|
||||
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, searchObj } = searchParams;
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.bills-list",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("bills");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/bills", label: t("titles.bc.bills-list")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.bills-list", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("bills");
|
||||
setBreadcrumbs([{ link: "/manage/bills", label: t("titles.bc.bills-list") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_ALL_BILLS_PAGINATED,
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
searchObj
|
||||
? JSON.parse(searchObj)
|
||||
: {
|
||||
[sortcolumn || "date"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_BILLS_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
searchObj
|
||||
? JSON.parse(searchObj)
|
||||
: {
|
||||
[sortcolumn || "date"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='bills'>
|
||||
<RbacWrapper action="bills:list">
|
||||
<div>
|
||||
<BillsPageComponent
|
||||
data={data ? data.bills : []}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
total={data ? data.bills_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="bills">
|
||||
<RbacWrapper action="bills:list">
|
||||
<div>
|
||||
<BillsPageComponent
|
||||
data={data ? data.bills : []}
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
total={data ? data.bills_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
|
||||
<BillDetailEditContainer/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
<BillDetailEditContainer />
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(BillsPageContainer);
|
||||
|
||||
@@ -1,70 +1,58 @@
|
||||
import {Button, Col, Form, Row, Space, Switch} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
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 { useTranslation } from "react-i18next";
|
||||
import ContractCarsContainer from "../../components/contract-cars/contract-cars.container";
|
||||
import ContractFormComponent from "../../components/contract-form/contract-form.component";
|
||||
import ContractJobsContainer from "../../components/contract-jobs/contract-jobs.container";
|
||||
|
||||
export default function ContractCreatePageComponent({
|
||||
form,
|
||||
selectedJobState,
|
||||
selectedCarState,
|
||||
loading,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export default function ContractCreatePageComponent({ form, selectedJobState, selectedCarState, loading }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const CreateButton = (
|
||||
<Space size="large">
|
||||
{selectedJobState[0] && selectedCarState[0] && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.addtoproduction")}
|
||||
name="addtoproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch/>
|
||||
</Form.Item>
|
||||
)}
|
||||
<Button
|
||||
disabled={!selectedJobState[0] || !selectedCarState[0]}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
{t("general.actions.create")}
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
const CreateButton = (
|
||||
<Space size="large">
|
||||
{selectedJobState[0] && selectedCarState[0] && (
|
||||
<Form.Item label={t("jobs.actions.addtoproduction")} name="addtoproduction" valuePropName="checked">
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
<Button
|
||||
disabled={!selectedJobState[0] || !selectedCarState[0]}
|
||||
type="primary"
|
||||
onClick={() => form.submit()}
|
||||
loading={loading}
|
||||
>
|
||||
{t("general.actions.create")}
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<ContractJobsContainer selectedJobState={selectedJobState}/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<ContractCarsContainer
|
||||
selectedCarState={selectedCarState}
|
||||
form={form}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<div
|
||||
style={{
|
||||
display: selectedJobState[0] && selectedCarState[0] ? "" : "none",
|
||||
}}
|
||||
>
|
||||
<ContractFormComponent
|
||||
create
|
||||
form={form}
|
||||
selectedJobState={selectedJobState}
|
||||
selectedCar={selectedCarState[0]}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<PageHeader extra={CreateButton}/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<ContractJobsContainer selectedJobState={selectedJobState} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<ContractCarsContainer selectedCarState={selectedCarState} form={form} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<div
|
||||
style={{
|
||||
display: selectedJobState[0] && selectedCarState[0] ? "" : "none"
|
||||
}}
|
||||
>
|
||||
<ContractFormComponent
|
||||
create
|
||||
form={form}
|
||||
selectedJobState={selectedJobState}
|
||||
selectedCar={selectedCarState[0]}
|
||||
/>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
<PageHeader extra={CreateButton} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,149 +1,139 @@
|
||||
import {useMutation} from "@apollo/client";
|
||||
import {Form, notification} from "antd";
|
||||
import React, {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 { useMutation } from "@apollo/client";
|
||||
import { Form, notification } from "antd";
|
||||
import React, { 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 RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {INSERT_NEW_CONTRACT} from "../../graphql/cccontracts.queries";
|
||||
import {UPDATE_JOB} from "../../graphql/jobs.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ContractCreatePageComponent from "./contract-create.page.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ContractCreatePageContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const {t} = useTranslation();
|
||||
export function ContractCreatePageContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const [form] = Form.useForm();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const history = useNavigate();
|
||||
const location = useLocation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const selectedCarState = useState(null);
|
||||
const selectedJobState = useState(
|
||||
(location.state && location.state.jobId) || null
|
||||
);
|
||||
const history = useNavigate();
|
||||
const location = useLocation();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const selectedCarState = useState(null);
|
||||
const selectedJobState = useState((location.state && location.state.jobId) || null);
|
||||
|
||||
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
|
||||
const [intakeJob] = useMutation(UPDATE_JOB);
|
||||
const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
|
||||
const [intakeJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
const handleFinish = async ({addtoproduction, ...values}) => {
|
||||
if (!!selectedCarState[0] && !!selectedJobState[0]) {
|
||||
setLoading(true);
|
||||
const result = await insertContract({
|
||||
variables: {
|
||||
ccId: selectedCarState[0].id,
|
||||
damage: values.damage,
|
||||
mileage: values.kmstart,
|
||||
contract: {
|
||||
...values,
|
||||
status: "contracts.status.out",
|
||||
courtesycarid: selectedCarState[0].id,
|
||||
jobid: selectedJobState[0],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
if (!result.errors) {
|
||||
//Update the courtesy car to have the damage.
|
||||
notification["success"]({
|
||||
message: t("contracts.successes.saved"),
|
||||
});
|
||||
|
||||
//Intake the job if required
|
||||
if (addtoproduction) {
|
||||
const result2 = await intakeJob({
|
||||
variables: {
|
||||
jobId: selectedJobState[0],
|
||||
job: {
|
||||
actual_in: new Date(),
|
||||
inproduction: true,
|
||||
status: bodyshop.md_ro_statuses.default_arrived,
|
||||
},
|
||||
},
|
||||
});
|
||||
if (result2.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.saving", {
|
||||
error: JSON.stringify(!result2.errors),
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
history(
|
||||
`/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}`
|
||||
);
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
error: JSON.stringify(!result.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.selectjobandcar"),
|
||||
});
|
||||
const handleFinish = async ({ addtoproduction, ...values }) => {
|
||||
if (!!selectedCarState[0] && !!selectedJobState[0]) {
|
||||
setLoading(true);
|
||||
const result = await insertContract({
|
||||
variables: {
|
||||
ccId: selectedCarState[0].id,
|
||||
damage: values.damage,
|
||||
mileage: values.kmstart,
|
||||
contract: {
|
||||
...values,
|
||||
status: "contracts.status.out",
|
||||
courtesycarid: selectedCarState[0].id,
|
||||
jobid: selectedJobState[0]
|
||||
}
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.contracts-create",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("newcontract");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/courtesycars", label: t("titles.bc.courtesycars")},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts"),
|
||||
},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts/new",
|
||||
label: t("titles.bc.contracts-create"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
if (!result.errors) {
|
||||
//Update the courtesy car to have the damage.
|
||||
notification["success"]({
|
||||
message: t("contracts.successes.saved")
|
||||
});
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='courtesycars'>
|
||||
<RbacWrapper action="contracts:create">
|
||||
<Form
|
||||
form={form}
|
||||
layout="vertical"
|
||||
autoComplete="no"
|
||||
onFinish={handleFinish}
|
||||
>
|
||||
<ContractCreatePageComponent
|
||||
loading={loading}
|
||||
form={form}
|
||||
selectedJobState={selectedJobState}
|
||||
selectedCarState={selectedCarState}
|
||||
/>
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
//Intake the job if required
|
||||
if (addtoproduction) {
|
||||
const result2 = await intakeJob({
|
||||
variables: {
|
||||
jobId: selectedJobState[0],
|
||||
job: {
|
||||
actual_in: new Date(),
|
||||
inproduction: true,
|
||||
status: bodyshop.md_ro_statuses.default_arrived
|
||||
}
|
||||
}
|
||||
});
|
||||
if (result2.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.saving", {
|
||||
error: JSON.stringify(!result2.errors)
|
||||
})
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
history(`/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}`);
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
error: JSON.stringify(!result.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.selectjobandcar")
|
||||
});
|
||||
}
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.contracts-create", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("newcontract");
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts")
|
||||
},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts/new",
|
||||
label: t("titles.bc.contracts-create")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<RbacWrapper action="contracts:create">
|
||||
<Form form={form} layout="vertical" autoComplete="no" onFinish={handleFinish}>
|
||||
<ContractCreatePageComponent
|
||||
loading={loading}
|
||||
form={form}
|
||||
selectedJobState={selectedJobState}
|
||||
selectedCarState={selectedCarState}
|
||||
/>
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ContractCreatePageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ContractCreatePageContainer);
|
||||
|
||||
@@ -1,126 +1,115 @@
|
||||
import {Button, Col, Dropdown, Form, Row, Space, Typography,} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
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 { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import ContractConvertToRo from "../../components/contract-convert-to-ro/contract-convert-to-ro.component";
|
||||
import ContractCourtesyCarBlock
|
||||
from "../../components/contract-courtesy-car-block/contract-courtesy-car-block.component";
|
||||
import ContractCourtesyCarBlock from "../../components/contract-courtesy-car-block/contract-courtesy-car-block.component";
|
||||
import ContractFormComponent from "../../components/contract-form/contract-form.component";
|
||||
import ContractJobBlock from "../../components/contract-job-block/contract-job-block.component";
|
||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
import {GenerateDocument} from "../../utils/RenderTemplate";
|
||||
import {TemplateList} from "../../utils/TemplateConstants";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
import { GenerateDocument } from "../../utils/RenderTemplate";
|
||||
import { TemplateList } from "../../utils/TemplateConstants";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setCourtesyCarReturnModalContext: (context) =>
|
||||
dispatch(setModalContext({context: context, modal: "courtesyCarReturn"})),
|
||||
setCourtesyCarReturnModalContext: (context) =>
|
||||
dispatch(setModalContext({ context: context, modal: "courtesyCarReturn" }))
|
||||
});
|
||||
|
||||
export function ContractDetailPage({
|
||||
contract,
|
||||
job,
|
||||
courtesyCar,
|
||||
setCourtesyCarReturnModalContext,
|
||||
refetch,
|
||||
form,
|
||||
saveLoading
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<Row align="middle">
|
||||
<Typography.Title></Typography.Title>
|
||||
</Row>
|
||||
<PageHeader
|
||||
title={t("contracts.labels.agreement", {
|
||||
agreement_num: contract && contract.agreementnumber,
|
||||
status: t(contract && contract.status),
|
||||
})}
|
||||
extra={
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
const menu = {
|
||||
onClick: (e) => {
|
||||
GenerateDocument(
|
||||
{
|
||||
name: TemplateList("courtesycarcontract")[e.key].key,
|
||||
variables: {id: contract.id},
|
||||
},
|
||||
{},
|
||||
"p"
|
||||
);
|
||||
},
|
||||
items: [
|
||||
{
|
||||
key: "courtesy_car_contract",
|
||||
label: t("contracts.actions.printcontract"),
|
||||
},
|
||||
{
|
||||
key: "courtesy_car_terms",
|
||||
label: t("printcenter.courtesycarcontract.courtesy_car_terms"),
|
||||
},
|
||||
{
|
||||
key: "courtesy_car_impound",
|
||||
label: t("printcenter.courtesycarcontract.courtesy_car_impound"),
|
||||
},
|
||||
]
|
||||
};
|
||||
contract,
|
||||
job,
|
||||
courtesyCar,
|
||||
setCourtesyCarReturnModalContext,
|
||||
refetch,
|
||||
form,
|
||||
saveLoading
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>
|
||||
<Row align="middle">
|
||||
<Typography.Title></Typography.Title>
|
||||
</Row>
|
||||
<PageHeader
|
||||
title={t("contracts.labels.agreement", {
|
||||
agreement_num: contract && contract.agreementnumber,
|
||||
status: t(contract && contract.status)
|
||||
})}
|
||||
extra={
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
const menu = {
|
||||
onClick: (e) => {
|
||||
GenerateDocument(
|
||||
{
|
||||
name: TemplateList("courtesycarcontract")[e.key].key,
|
||||
variables: { id: contract.id }
|
||||
},
|
||||
{},
|
||||
"p"
|
||||
);
|
||||
},
|
||||
items: [
|
||||
{
|
||||
key: "courtesy_car_contract",
|
||||
label: t("contracts.actions.printcontract")
|
||||
},
|
||||
{
|
||||
key: "courtesy_car_terms",
|
||||
label: t("printcenter.courtesycarcontract.courtesy_car_terms")
|
||||
},
|
||||
{
|
||||
key: "courtesy_car_impound",
|
||||
label: t("printcenter.courtesycarcontract.courtesy_car_impound")
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<Space>
|
||||
<Button
|
||||
type="primary"
|
||||
htmlType="submit"
|
||||
loading={saveLoading}
|
||||
>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={
|
||||
!!!contract ||
|
||||
(contract && contract.status !== "contracts.status.out")
|
||||
}
|
||||
onClick={() => {
|
||||
setCourtesyCarReturnModalContext({
|
||||
actions: {refetch},
|
||||
context: {
|
||||
contractId: contract.id,
|
||||
courtesyCarId: courtesyCar.id,
|
||||
},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("courtesycars.actions.return")}
|
||||
</Button>
|
||||
<Dropdown trigger="click" menu={menu}>
|
||||
<Button>{t("general.labels.print")}</Button>
|
||||
</Dropdown>
|
||||
return (
|
||||
<Space>
|
||||
<Button type="primary" htmlType="submit" loading={saveLoading}>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={!!!contract || (contract && contract.status !== "contracts.status.out")}
|
||||
onClick={() => {
|
||||
setCourtesyCarReturnModalContext({
|
||||
actions: { refetch },
|
||||
context: {
|
||||
contractId: contract.id,
|
||||
courtesyCarId: courtesyCar.id
|
||||
}
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("courtesycars.actions.return")}
|
||||
</Button>
|
||||
<Dropdown trigger="click" menu={menu}>
|
||||
<Button>{t("general.labels.print")}</Button>
|
||||
</Dropdown>
|
||||
|
||||
<ContractConvertToRo
|
||||
contract={contract}
|
||||
disabled={form.isFieldsTouched()}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
}
|
||||
/>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col sm={24} md={12}>
|
||||
<ContractJobBlock job={job}/>
|
||||
</Col>
|
||||
<Col sm={24} md={12}>
|
||||
<ContractCourtesyCarBlock courtesyCar={courtesyCar}/>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<ContractFormComponent form={form}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
<ContractConvertToRo contract={contract} disabled={form.isFieldsTouched()} />
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
}
|
||||
/>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col sm={24} md={12}>
|
||||
<ContractJobBlock job={job} />
|
||||
</Col>
|
||||
<Col sm={24} md={12}>
|
||||
<ContractCourtesyCarBlock courtesyCar={courtesyCar} />
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<ContractFormComponent form={form} />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ContractDetailPage);
|
||||
|
||||
@@ -1,170 +1,150 @@
|
||||
import {useMutation, useQuery} from "@apollo/client";
|
||||
import {Form, notification} from "antd";
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { Form, notification } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import CourtesyCarReturnModalContainer
|
||||
from "../../components/courtesy-car-return-modal/courtesy-car-return-modal.container";
|
||||
import CourtesyCarReturnModalContainer from "../../components/courtesy-car-return-modal/courtesy-car-return-modal.container";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_CONTRACT_BY_PK, UPDATE_CONTRACT,} from "../../graphql/cccontracts.queries";
|
||||
import {addRecentItem, setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {CreateRecentItem} from "../../utils/create-recent-item";
|
||||
import { QUERY_CONTRACT_BY_PK, UPDATE_CONTRACT } from "../../graphql/cccontracts.queries";
|
||||
import { addRecentItem, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import ContractDetailPageComponent from "./contract-detail.page.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ContractDetailPageContainer({
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const [updateContract] = useMutation(UPDATE_CONTRACT);
|
||||
const [saveLoading, setsaveLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const {contractId} = useParams();
|
||||
export function ContractDetailPageContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const [updateContract] = useMutation(UPDATE_CONTRACT);
|
||||
const [saveLoading, setsaveLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const { contractId } = useParams();
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(QUERY_CONTRACT_BY_PK, {
|
||||
variables: {id: contractId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_CONTRACT_BY_PK, {
|
||||
variables: { id: contractId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedHeader("contracts");
|
||||
document.title = loading
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: error
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: t("titles.contracts-detail", {
|
||||
id:
|
||||
(data &&
|
||||
data.cccontracts_by_pk &&
|
||||
data.cccontracts_by_pk.agreementnumber) ||
|
||||
"",
|
||||
});
|
||||
useEffect(() => {
|
||||
setSelectedHeader("contracts");
|
||||
document.title = loading
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: error
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: t("titles.contracts-detail", {
|
||||
id: (data && data.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
});
|
||||
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/courtesycars", label: t("titles.bc.courtesycars")},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts"),
|
||||
},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts/new",
|
||||
label: t("titles.bc.contracts-detail", {
|
||||
number:
|
||||
(data &&
|
||||
data.cccontracts_by_pk &&
|
||||
data.cccontracts_by_pk.agreementnumber) ||
|
||||
"",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
if (data && data.cccontracts_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
contractId,
|
||||
"contract",
|
||||
data.cccontracts_by_pk.agreementnumber,
|
||||
`/manage/courtesycars/contracts/${contractId}`
|
||||
)
|
||||
);
|
||||
}, [
|
||||
t,
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
contractId,
|
||||
setSelectedHeader,
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts")
|
||||
},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts/new",
|
||||
label: t("titles.bc.contracts-detail", {
|
||||
number: (data && data.cccontracts_by_pk && data.cccontracts_by_pk.agreementnumber) || ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setsaveLoading(true);
|
||||
const result = await updateContract({
|
||||
variables: {cccontract: {...values}, contractId: contractId},
|
||||
});
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification["success"]({message: t("contracts.successes.saved")});
|
||||
if (refetch) await refetch();
|
||||
setsaveLoading(false);
|
||||
if (data && data.cccontracts_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
contractId,
|
||||
"contract",
|
||||
data.cccontracts_by_pk.agreementnumber,
|
||||
`/manage/courtesycars/contracts/${contractId}`
|
||||
)
|
||||
);
|
||||
}, [t, data, error, loading, setBreadcrumbs, addRecentItem, contractId, setSelectedHeader]);
|
||||
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
};
|
||||
const handleFinish = async (values) => {
|
||||
setsaveLoading(true);
|
||||
const result = await updateContract({
|
||||
variables: { cccontract: { ...values }, contractId: contractId }
|
||||
});
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("contracts.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
return;
|
||||
}
|
||||
notification["success"]({ message: t("contracts.successes.saved") });
|
||||
if (refetch) await refetch();
|
||||
setsaveLoading(false);
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.cccontracts_by_pk) form.resetFields();
|
||||
}, [data, form]);
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
};
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
useEffect(() => {
|
||||
if (data && data.cccontracts_by_pk) form.resetFields();
|
||||
}, [data, form]);
|
||||
|
||||
if (!!!data.cccontracts_by_pk) return <NotFound/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (loading) return <LoadingSpinner />;
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='courtesycars'>
|
||||
<RbacWrapper action="contracts:detail">
|
||||
<div>
|
||||
<CourtesyCarReturnModalContainer/>
|
||||
<Form
|
||||
form={form}
|
||||
autoComplete="no"
|
||||
layout="vertical"
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
...data.cccontracts_by_pk,
|
||||
start: data.cccontracts_by_pk.start
|
||||
? dayjs(data.cccontracts_by_pk.start)
|
||||
: null,
|
||||
scheduledreturn: data.cccontracts_by_pk.scheduledreturn
|
||||
? dayjs(data.cccontracts_by_pk.scheduledreturn)
|
||||
: null,
|
||||
actualreturn: data.cccontracts_by_pk.actualreturn
|
||||
? dayjs(data.cccontracts_by_pk.actualreturn)
|
||||
: null,
|
||||
driver_dlexpiry: data.cccontracts_by_pk.driver_dlexpiry
|
||||
? dayjs(data.cccontracts_by_pk.driver_dlexpiry)
|
||||
: null,
|
||||
driver_dob: data.cccontracts_by_pk.driver_dob
|
||||
? dayjs(data.cccontracts_by_pk.driver_dob)
|
||||
: null,
|
||||
}}
|
||||
>
|
||||
<ContractDetailPageComponent
|
||||
contract={data ? data.cccontracts_by_pk : null}
|
||||
job={data ? data.cccontracts_by_pk.job : null}
|
||||
courtesyCar={data ? data.cccontracts_by_pk.courtesycar : null}
|
||||
refetch={refetch}
|
||||
form={form}
|
||||
saveLoading={saveLoading}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
if (!!!data.cccontracts_by_pk) return <NotFound />;
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<RbacWrapper action="contracts:detail">
|
||||
<div>
|
||||
<CourtesyCarReturnModalContainer />
|
||||
<Form
|
||||
form={form}
|
||||
autoComplete="no"
|
||||
layout="vertical"
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
...data.cccontracts_by_pk,
|
||||
start: data.cccontracts_by_pk.start ? dayjs(data.cccontracts_by_pk.start) : null,
|
||||
scheduledreturn: data.cccontracts_by_pk.scheduledreturn
|
||||
? dayjs(data.cccontracts_by_pk.scheduledreturn)
|
||||
: null,
|
||||
actualreturn: data.cccontracts_by_pk.actualreturn ? dayjs(data.cccontracts_by_pk.actualreturn) : null,
|
||||
driver_dlexpiry: data.cccontracts_by_pk.driver_dlexpiry
|
||||
? dayjs(data.cccontracts_by_pk.driver_dlexpiry)
|
||||
: null,
|
||||
driver_dob: data.cccontracts_by_pk.driver_dob ? dayjs(data.cccontracts_by_pk.driver_dob) : null
|
||||
}}
|
||||
>
|
||||
<ContractDetailPageComponent
|
||||
contract={data ? data.cccontracts_by_pk : null}
|
||||
job={data ? data.cccontracts_by_pk.job : null}
|
||||
courtesyCar={data ? data.cccontracts_by_pk.courtesycar : null}
|
||||
refetch={refetch}
|
||||
form={form}
|
||||
saveLoading={saveLoading}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ContractDetailPageContainer);
|
||||
|
||||
@@ -1,18 +1,6 @@
|
||||
import React from "react";
|
||||
import ContractsList from "../../components/contracts-list/contracts-list.component";
|
||||
|
||||
export default function ContractsPageComponent({
|
||||
loading,
|
||||
data,
|
||||
refetch,
|
||||
total,
|
||||
}) {
|
||||
return (
|
||||
<ContractsList
|
||||
loading={loading}
|
||||
contracts={data}
|
||||
refetch={refetch}
|
||||
total={total}
|
||||
/>
|
||||
);
|
||||
export default function ContractsPageComponent({ loading, data, refetch, total }) {
|
||||
return <ContractsList loading={loading} contracts={data} refetch={refetch} total={total} />;
|
||||
}
|
||||
|
||||
@@ -1,74 +1,73 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation} from "react-router-dom";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_ACTIVE_CONTRACTS_PAGINATED} from "../../graphql/cccontracts.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { QUERY_ACTIVE_CONTRACTS_PAGINATED } from "../../graphql/cccontracts.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import ContractsPageComponent from "./contracts.page.component";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ContractsPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {search, page, sortcolumn, sortorder} = searchParams;
|
||||
export function ContractsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { search, page, sortcolumn, sortorder } = searchParams;
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_ACTIVE_CONTRACTS_PAGINATED,
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ACTIVE_CONTRACTS_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "start"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
[sortcolumn || "start"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
);
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.contracts", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("contracts");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/courtesycars", label: t("titles.bc.courtesycars")},
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
]
|
||||
}
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.contracts", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("contracts");
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
|
||||
{
|
||||
link: "/manage/courtesycars/contracts",
|
||||
label: t("titles.bc.contracts")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<RbacWrapper action="contracts:list">
|
||||
<ContractsPageComponent
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
data={data ? data.search_cccontracts : []}
|
||||
total={data ? data.search_cccontracts_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<RbacWrapper action="contracts:list">
|
||||
<ContractsPageComponent
|
||||
loading={loading}
|
||||
refetch={refetch}
|
||||
data={data ? data.search_cccontracts : []}
|
||||
total={data ? data.search_cccontracts_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ContractsPageContainer);
|
||||
|
||||
@@ -1,85 +1,82 @@
|
||||
import {useMutation} from "@apollo/client";
|
||||
import {Form, notification} from "antd";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useMutation } from "@apollo/client";
|
||||
import { Form, notification } from "antd";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import CourtesyCarFormComponent from "../../components/courtesy-car-form/courtesy-car-form.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {INSERT_NEW_COURTESY_CAR} from "../../graphql/courtesy-car.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { INSERT_NEW_COURTESY_CAR } from "../../graphql/courtesy-car.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function CourtesyCarCreateContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [insertCourtesyCar] = useMutation(INSERT_NEW_COURTESY_CAR);
|
||||
const {t} = useTranslation();
|
||||
const history = useNavigate();
|
||||
export function CourtesyCarCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const [form] = Form.useForm();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [insertCourtesyCar] = useMutation(INSERT_NEW_COURTESY_CAR);
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const result = await insertCourtesyCar({
|
||||
variables: {courtesycar: {...values, bodyshopid: bodyshop.id}},
|
||||
});
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const result = await insertCourtesyCar({
|
||||
variables: { courtesycar: { ...values, bodyshopid: bodyshop.id } }
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", {
|
||||
message: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
setLoading(false);
|
||||
} else {
|
||||
setLoading(false);
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
notification["success"]({message: t("courtesycars.successes.saved")});
|
||||
history(
|
||||
`/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}`
|
||||
);
|
||||
}
|
||||
};
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", {
|
||||
message: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
setLoading(false);
|
||||
} else {
|
||||
setLoading(false);
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
notification["success"]({ message: t("courtesycars.successes.saved") });
|
||||
history(`/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}`);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedHeader("courtesycarsall");
|
||||
document.title = t("titles.courtesycars-create",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/courtesycars", label: t("titles.bc.courtesycars")},
|
||||
{
|
||||
link: "/manage/courtesycars/new",
|
||||
label: t("titles.bc.courtesycars-new"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
setSelectedHeader("courtesycarsall");
|
||||
document.title = t("titles.courtesycars-create", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") },
|
||||
{
|
||||
link: "/manage/courtesycars/new",
|
||||
label: t("titles.bc.courtesycars-new")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:create">
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<Form form={form} autoComplete="new-password" onFinish={handleFinish} layout="vertical">
|
||||
<CourtesyCarFormComponent form={form} saveLoading={loading} />
|
||||
</Form>
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:create">
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<Form form={form} autoComplete="new-password" onFinish={handleFinish} layout="vertical">
|
||||
<CourtesyCarFormComponent form={form} saveLoading={loading} />
|
||||
</Form>
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(CourtesyCarCreateContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CourtesyCarCreateContainer);
|
||||
|
||||
@@ -1,27 +1,18 @@
|
||||
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";
|
||||
import CourtesyCarContractListComponent from "../../components/courtesy-car-contract-list/courtesy-car-contract-list.component";
|
||||
import { Col, Divider, Row } from "antd";
|
||||
|
||||
export default function CourtesyCarDetailPageComponent({
|
||||
contracts,
|
||||
form,
|
||||
saveLoading,
|
||||
totalContracts,
|
||||
}) {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<CourtesyCarCreateFormComponent form={form} saveLoading={saveLoading}/>
|
||||
</Col>
|
||||
<Divider type="horizontal"/>
|
||||
<Col span={24}>
|
||||
<CourtesyCarContractListComponent
|
||||
contracts={contracts}
|
||||
totalContracts={totalContracts}
|
||||
/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
export default function CourtesyCarDetailPageComponent({ contracts, form, saveLoading, totalContracts }) {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<CourtesyCarCreateFormComponent form={form} saveLoading={saveLoading} />
|
||||
</Col>
|
||||
<Divider type="horizontal" />
|
||||
<Col span={24}>
|
||||
<CourtesyCarContractListComponent contracts={contracts} totalContracts={totalContracts} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,201 +1,175 @@
|
||||
import {useMutation, useQuery} from "@apollo/client";
|
||||
import {Form, notification} from "antd";
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import { Form, notification } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation, useParams} from "react-router-dom";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_CC_BY_PK, UPDATE_CC} from "../../graphql/courtesy-car.queries";
|
||||
import {addRecentItem, setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {CreateRecentItem} from "../../utils/create-recent-item";
|
||||
import { QUERY_CC_BY_PK, UPDATE_CC } from "../../graphql/courtesy-car.queries";
|
||||
import { addRecentItem, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import UndefinedToNull from "./../../utils/undefinedtonull";
|
||||
import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import queryString from "query-string";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function CourtesyCarDetailPageContainer({
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder} = searchParams;
|
||||
export function CourtesyCarDetailPageContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder } = searchParams;
|
||||
|
||||
const {t} = useTranslation();
|
||||
const [updateCourtesyCar] = useMutation(UPDATE_CC);
|
||||
const [form] = Form.useForm();
|
||||
const {ccId} = useParams();
|
||||
const [saveLoading, setSaveLoading] = useState(false);
|
||||
const {loading, error, data} = useQuery(QUERY_CC_BY_PK, {
|
||||
variables: {
|
||||
id: ccId,
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "start"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const [updateCourtesyCar] = useMutation(UPDATE_CC);
|
||||
const [form] = Form.useForm();
|
||||
const { ccId } = useParams();
|
||||
const [saveLoading, setSaveLoading] = useState(false);
|
||||
const { loading, error, data } = useQuery(QUERY_CC_BY_PK, {
|
||||
variables: {
|
||||
id: ccId,
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "start"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
]
|
||||
},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedHeader("courtesycarsall");
|
||||
useEffect(() => {
|
||||
setSelectedHeader("courtesycarsall");
|
||||
|
||||
document.title = loading
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: error
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: t("titles.courtesycars-detail", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
id:
|
||||
(data &&
|
||||
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) || ""
|
||||
}`,
|
||||
label: t("titles.bc.courtesycars-detail", {
|
||||
number:
|
||||
(data &&
|
||||
data.courtesycars_by_pk &&
|
||||
data.courtesycars_by_pk.fleetnumber) ||
|
||||
"",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
if (data && data.courtesycars_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
ccId,
|
||||
"courtesycar",
|
||||
data.courtesycars_by_pk.fleet_number || data.courtesycars_by_pk.vin,
|
||||
`/manage/courtesycars/${ccId}`
|
||||
)
|
||||
);
|
||||
}, [
|
||||
t,
|
||||
data,
|
||||
error,
|
||||
loading,
|
||||
setBreadcrumbs,
|
||||
ccId,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
document.title = loading
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: error
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: t("titles.courtesycars-detail", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
id: (data && 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) || ""}`,
|
||||
label: t("titles.bc.courtesycars-detail", {
|
||||
number: (data && data.courtesycars_by_pk && data.courtesycars_by_pk.fleetnumber) || ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setSaveLoading(true);
|
||||
if (data && data.courtesycars_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
ccId,
|
||||
"courtesycar",
|
||||
data.courtesycars_by_pk.fleet_number || data.courtesycars_by_pk.vin,
|
||||
`/manage/courtesycars/${ccId}`
|
||||
)
|
||||
);
|
||||
}, [t, data, error, loading, setBreadcrumbs, ccId, addRecentItem, setSelectedHeader]);
|
||||
|
||||
const result = await updateCourtesyCar({
|
||||
variables: {
|
||||
cc: {...UndefinedToNull(values, ["readiness"])},
|
||||
ccId: ccId,
|
||||
},
|
||||
refetchQueries: ["QUERY_CC_BY_PK"],
|
||||
awaitRefetchQueries: true,
|
||||
});
|
||||
const handleFinish = async (values) => {
|
||||
setSaveLoading(true);
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", {error: error}),
|
||||
});
|
||||
const result = await updateCourtesyCar({
|
||||
variables: {
|
||||
cc: { ...UndefinedToNull(values, ["readiness"]) },
|
||||
ccId: ccId
|
||||
},
|
||||
refetchQueries: ["QUERY_CC_BY_PK"],
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
if (!!result.errors) {
|
||||
notification["error"]({
|
||||
message: t("courtesycars.errors.saving", { error: error })
|
||||
});
|
||||
}
|
||||
|
||||
notification["success"]({
|
||||
message: t("courtesycars.successes.saved")
|
||||
});
|
||||
|
||||
setSaveLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.courtesycars_by_pk) {
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
}
|
||||
}, [data, form]);
|
||||
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (!!!data.courtesycars_by_pk) return <NotFound />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:detail">
|
||||
<Form
|
||||
form={form}
|
||||
autoComplete="no"
|
||||
onFinish={handleFinish}
|
||||
layout="vertical"
|
||||
initialValues={
|
||||
data
|
||||
? {
|
||||
...data.courtesycars_by_pk,
|
||||
purchasedate: data.courtesycars_by_pk.purchasedate ? dayjs(data.courtesycars_by_pk.purchasedate) : null,
|
||||
servicestartdate: data.courtesycars_by_pk.servicestartdate
|
||||
? dayjs(data.courtesycars_by_pk.servicestartdate)
|
||||
: null,
|
||||
serviceenddate: data.courtesycars_by_pk.serviceenddate
|
||||
? dayjs(data.courtesycars_by_pk.serviceenddate)
|
||||
: null,
|
||||
leaseenddate: data.courtesycars_by_pk.leaseenddate ? dayjs(data.courtesycars_by_pk.leaseenddate) : null,
|
||||
nextservicedate: data.courtesycars_by_pk.nextservicedate
|
||||
? dayjs(data.courtesycars_by_pk.nextservicedate)
|
||||
: null,
|
||||
registrationexpires: data.courtesycars_by_pk.registrationexpires
|
||||
? dayjs(data.courtesycars_by_pk.registrationexpires)
|
||||
: null,
|
||||
insuranceexpires: data.courtesycars_by_pk.insuranceexpires
|
||||
? dayjs(data.courtesycars_by_pk.insuranceexpires)
|
||||
: null
|
||||
}
|
||||
: {}
|
||||
}
|
||||
|
||||
notification["success"]({
|
||||
message: t("courtesycars.successes.saved"),
|
||||
});
|
||||
|
||||
setSaveLoading(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (data && data.courtesycars_by_pk) {
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
}
|
||||
}, [data, form]);
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
|
||||
if (!!!data.courtesycars_by_pk) return <NotFound/>;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:detail">
|
||||
<Form
|
||||
form={form}
|
||||
autoComplete="no"
|
||||
onFinish={handleFinish}
|
||||
layout="vertical"
|
||||
initialValues={
|
||||
data
|
||||
? {
|
||||
...data.courtesycars_by_pk,
|
||||
purchasedate: data.courtesycars_by_pk.purchasedate
|
||||
? dayjs(data.courtesycars_by_pk.purchasedate)
|
||||
: null,
|
||||
servicestartdate: data.courtesycars_by_pk.servicestartdate
|
||||
? dayjs(data.courtesycars_by_pk.servicestartdate)
|
||||
: null,
|
||||
serviceenddate: data.courtesycars_by_pk.serviceenddate
|
||||
? dayjs(data.courtesycars_by_pk.serviceenddate)
|
||||
: null,
|
||||
leaseenddate: data.courtesycars_by_pk.leaseenddate
|
||||
? dayjs(data.courtesycars_by_pk.leaseenddate)
|
||||
: null,
|
||||
nextservicedate: data.courtesycars_by_pk.nextservicedate
|
||||
? dayjs(data.courtesycars_by_pk.nextservicedate)
|
||||
: null,
|
||||
registrationexpires: data.courtesycars_by_pk.registrationexpires
|
||||
? dayjs(data.courtesycars_by_pk.registrationexpires)
|
||||
: null,
|
||||
insuranceexpires: data.courtesycars_by_pk.insuranceexpires
|
||||
? dayjs(data.courtesycars_by_pk.insuranceexpires)
|
||||
: null,
|
||||
}
|
||||
: {}
|
||||
}
|
||||
>
|
||||
<CourtesyCarDetailPageComponent
|
||||
contracts={data ? data.courtesycars_by_pk.cccontracts : []}
|
||||
form={form}
|
||||
saveLoading={saveLoading}
|
||||
totalContracts={
|
||||
data
|
||||
? data.courtesycars_by_pk.cccontracts_aggregate.aggregate.count
|
||||
: 0
|
||||
}
|
||||
/>
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
);
|
||||
>
|
||||
<CourtesyCarDetailPageComponent
|
||||
contracts={data ? data.courtesycars_by_pk.cccontracts : []}
|
||||
form={form}
|
||||
saveLoading={saveLoading}
|
||||
totalContracts={data ? data.courtesycars_by_pk.cccontracts_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
null,
|
||||
mapDispatchToProps
|
||||
)(CourtesyCarDetailPageContainer);
|
||||
export default connect(null, mapDispatchToProps)(CourtesyCarDetailPageContainer);
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import React from "react";
|
||||
import CourtesyCarsListComponent from "../../components/courtesy-cars-list/courtesy-cars-list.component";
|
||||
|
||||
export default function CourtesyCarsPageComponent({loading, data, refetch}) {
|
||||
return (
|
||||
<CourtesyCarsListComponent
|
||||
loading={loading}
|
||||
courtesycars={data}
|
||||
refetch={refetch}
|
||||
/>
|
||||
);
|
||||
export default function CourtesyCarsPageComponent({ loading, data, refetch }) {
|
||||
return <CourtesyCarsListComponent loading={loading} courtesycars={data} refetch={refetch} />;
|
||||
}
|
||||
|
||||
@@ -1,49 +1,46 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_ALL_CC} from "../../graphql/courtesy-car.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { QUERY_ALL_CC } from "../../graphql/courtesy-car.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import CourtesyCarsPageComponent from "./courtesy-cars.page.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function CourtesyCarsPageContainer({
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {loading, error, data, refetch} = useQuery(QUERY_ALL_CC, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function CourtesyCarsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_CC, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.courtesycars", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.courtesycars",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})});
|
||||
setSelectedHeader("courtesycarsall");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/courtesycars", label: t("titles.bc.courtesycars")},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
setSelectedHeader("courtesycarsall");
|
||||
setBreadcrumbs([{ link: "/manage/courtesycars", label: t("titles.bc.courtesycars") }]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:list">
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<CourtesyCarsPageComponent
|
||||
loading={loading}
|
||||
data={(data && data.courtesycars) || []}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<RbacWrapper action="courtesycar:list">
|
||||
<FeatureWrapperComponent featureName="courtesycars">
|
||||
<CourtesyCarsPageComponent loading={loading} data={(data && data.courtesycars) || []} refetch={refetch} />
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(CourtesyCarsPageContainer);
|
||||
|
||||
@@ -1,255 +1,243 @@
|
||||
//import {useMutation, useQuery } from "@apollo/client";
|
||||
import {Button, Form, Layout, Result, Typography} from "antd";
|
||||
import { Button, Form, Layout, Result, Typography } from "antd";
|
||||
import axios from "axios";
|
||||
import React, {useCallback, useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useCallback, useEffect, useState } 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 ConfigFormComponents from "../../components/config-form-components/config-form-components.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import {selectCurrentUser} from "../../redux/user/user.selectors";
|
||||
import {DateTimeFormat} from "./../../utils/DateFormatter";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { DateTimeFormat } from "./../../utils/DateFormatter";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
currentUser: selectCurrentUser
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(CsiContainerPage);
|
||||
|
||||
export function CsiContainerPage({currentUser}) {
|
||||
const {surveyId} = useParams();
|
||||
const [form] = Form.useForm();
|
||||
const [axiosResponse, setAxiosResponse] = useState(null);
|
||||
const [submitting, setSubmitting] = useState({
|
||||
loading: false,
|
||||
submitted: false,
|
||||
});
|
||||
export function CsiContainerPage({ currentUser }) {
|
||||
const { surveyId } = useParams();
|
||||
const [form] = Form.useForm();
|
||||
const [axiosResponse, setAxiosResponse] = useState(null);
|
||||
const [submitting, setSubmitting] = useState({
|
||||
loading: false,
|
||||
submitted: false
|
||||
});
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const getAxiosData = useCallback(async () => {
|
||||
try {
|
||||
try {
|
||||
window.$crisp.push(["do", "chat:hide"]);
|
||||
} catch {
|
||||
console.log("Unable to attach to crisp instance. ");
|
||||
}
|
||||
setSubmitting((prevSubmitting) => ({ ...prevSubmitting, loading: true }));
|
||||
|
||||
const {t} = useTranslation();
|
||||
|
||||
|
||||
const getAxiosData = useCallback(async () => {
|
||||
try {
|
||||
try {
|
||||
window.$crisp.push(["do", "chat:hide"]);
|
||||
} catch {
|
||||
console.log("Unable to attach to crisp instance. ");
|
||||
}
|
||||
setSubmitting((prevSubmitting) => ({...prevSubmitting, loading: true}));
|
||||
|
||||
const response = await axios.post("/csi/lookup", {
|
||||
surveyId
|
||||
});
|
||||
setSubmitting((prevSubmitting) => ({
|
||||
...prevSubmitting,
|
||||
loading: false,
|
||||
}));
|
||||
setAxiosResponse(response.data);
|
||||
} catch (error) {
|
||||
console.error(`Something went wrong...: ${error.message}`);
|
||||
console.dir({
|
||||
stack: error?.stack,
|
||||
message:
|
||||
error?.message,
|
||||
});
|
||||
}
|
||||
}, [setAxiosResponse, surveyId]);
|
||||
|
||||
useEffect(() => {
|
||||
getAxiosData().catch((err) =>
|
||||
console.error(
|
||||
`Something went wrong fetching axios data: ${err.message || ""}`
|
||||
)
|
||||
);
|
||||
}, [getAxiosData]);
|
||||
|
||||
// Return if authorized
|
||||
if (currentUser && currentUser.authorized) {
|
||||
return (
|
||||
<Layout
|
||||
style={{height: "100vh", display: "flex", flexDirection: "column"}}
|
||||
>
|
||||
<Result
|
||||
status="error"
|
||||
title={t("csi.labels.nologgedinuser", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}
|
||||
subTitle={t("csi.labels.nologgedinuser_sub",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}
|
||||
/>
|
||||
</Layout>
|
||||
);
|
||||
const response = await axios.post("/csi/lookup", {
|
||||
surveyId
|
||||
});
|
||||
setSubmitting((prevSubmitting) => ({
|
||||
...prevSubmitting,
|
||||
loading: false
|
||||
}));
|
||||
setAxiosResponse(response.data);
|
||||
} catch (error) {
|
||||
console.error(`Something went wrong...: ${error.message}`);
|
||||
console.dir({
|
||||
stack: error?.stack,
|
||||
message: error?.message
|
||||
});
|
||||
}
|
||||
}, [setAxiosResponse, surveyId]);
|
||||
|
||||
if (submitting.loading) return <LoadingSpinner/>;
|
||||
useEffect(() => {
|
||||
getAxiosData().catch((err) => console.error(`Something went wrong fetching axios data: ${err.message || ""}`));
|
||||
}, [getAxiosData]);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
try {
|
||||
setSubmitting({...submitting, loading: true, submitting: true});
|
||||
const result = await axios.post("/csi/submit", {surveyId, values});
|
||||
console.log("result", result);
|
||||
if (!!!result.errors && result.data.update_csi.affected_rows > 0) {
|
||||
setSubmitting({...submitting, loading: false, submitted: true});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Something went wrong...: ${error.message}`);
|
||||
console.dir({
|
||||
stack: error?.stack,
|
||||
message: error?.message,
|
||||
});
|
||||
}
|
||||
};
|
||||
// Return if authorized
|
||||
if (currentUser && currentUser.authorized) {
|
||||
return (
|
||||
<Layout style={{ height: "100vh", display: "flex", flexDirection: "column" }}>
|
||||
<Result
|
||||
status="error"
|
||||
title={t("csi.labels.nologgedinuser", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
})}
|
||||
subTitle={t("csi.labels.nologgedinuser_sub", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
})}
|
||||
/>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
if (!axiosResponse || axiosResponse.csi_by_pk === null) {
|
||||
// Do something here , this is where you would return a loading box or something
|
||||
return (
|
||||
<>
|
||||
<Layout style={{display: "flex", flexDirection: "column"}}>
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto",
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<Form>
|
||||
<Result
|
||||
status="error"
|
||||
title={t("csi.errors.notfoundtitle")}
|
||||
subTitle={t("csi.errors.notfoundsubtitle")}
|
||||
/>
|
||||
</Form>
|
||||
</Layout.Content>
|
||||
<Layout.Footer>
|
||||
{t("csi.labels.copyright")}{" "}
|
||||
{t("csi.fields.surveyid", {surveyId: surveyId})}
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
if (submitting.loading) return <LoadingSpinner />;
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
try {
|
||||
setSubmitting({ ...submitting, loading: true, submitting: true });
|
||||
const result = await axios.post("/csi/submit", { surveyId, values });
|
||||
console.log("result", result);
|
||||
if (!!!result.errors && result.data.update_csi.affected_rows > 0) {
|
||||
setSubmitting({ ...submitting, loading: false, submitted: true });
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Something went wrong...: ${error.message}`);
|
||||
console.dir({
|
||||
stack: error?.stack,
|
||||
message: error?.message
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
if (!axiosResponse || axiosResponse.csi_by_pk === null) {
|
||||
// Do something here , this is where you would return a loading box or something
|
||||
return (
|
||||
<>
|
||||
<Layout style={{ display: "flex", flexDirection: "column" }}>
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto",
|
||||
textAlign: "center",
|
||||
display: "flex",
|
||||
justifyContent: "center",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<Form>
|
||||
<Result
|
||||
status="error"
|
||||
title={t("csi.errors.notfoundtitle")}
|
||||
subTitle={t("csi.errors.notfoundsubtitle")}
|
||||
/>
|
||||
</Form>
|
||||
</Layout.Content>
|
||||
<Layout.Footer>
|
||||
{t("csi.labels.copyright")} {t("csi.fields.surveyid", { surveyId: surveyId })}
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
} else {
|
||||
const {
|
||||
relateddata: {bodyshop, job},
|
||||
csiquestion: {config: csiquestions},
|
||||
relateddata: { bodyshop, job },
|
||||
csiquestion: { config: csiquestions }
|
||||
} = axiosResponse.csi_by_pk;
|
||||
|
||||
return (
|
||||
<Layout style={{display: "flex", flexDirection: "column"}}>
|
||||
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
}}
|
||||
>
|
||||
<div style={{display: "flex", alignItems: "center", margin: "2em"}}>
|
||||
{bodyshop.logo_img_path && bodyshop.logo_img_path.src ? (
|
||||
<img src={bodyshop.logo_img_path.src} alt={bodyshop.shopname.concat("Logo")}
|
||||
height={bodyshop.logo_img_path.height}
|
||||
width={bodyshop.logo_img_path.width}
|
||||
/>) : null}
|
||||
<div style={{margin: "2em", verticalAlign: "middle"}}>
|
||||
<Typography.Title level={4} style={{margin: 0}}>
|
||||
{bodyshop.shopname || ""}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph style={{margin: 0}}>
|
||||
{`${bodyshop.address1 || ""}${bodyshop.address2 ? ", " : ""}${
|
||||
bodyshop.address2 || ""
|
||||
}`.trim()}
|
||||
</Typography.Paragraph>
|
||||
<Typography.Paragraph style={{margin: 0}}>
|
||||
{`${bodyshop.city || ""}${
|
||||
bodyshop.city && bodyshop.state ? ", " : ""
|
||||
}${bodyshop.state || ""} ${bodyshop.zip_post || ""}`.trim()}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
<Typography.Title>{t("csi.labels.title")}</Typography.Title>
|
||||
<strong>{t("csi.labels.greeting", {
|
||||
name: job.ownr_co_nm || job.ownr_fn || "",
|
||||
})}</strong>
|
||||
<Typography.Paragraph>
|
||||
{t("csi.labels.intro", {
|
||||
shopname:
|
||||
bodyshop.shopname || ""
|
||||
})}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
|
||||
{submitting.error ? (
|
||||
<AlertComponent message={submitting.error} type="error"/>
|
||||
<Layout style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center"
|
||||
}}
|
||||
>
|
||||
<div style={{ display: "flex", alignItems: "center", margin: "2em" }}>
|
||||
{bodyshop.logo_img_path && bodyshop.logo_img_path.src ? (
|
||||
<img
|
||||
src={bodyshop.logo_img_path.src}
|
||||
alt={bodyshop.shopname.concat("Logo")}
|
||||
height={bodyshop.logo_img_path.height}
|
||||
width={bodyshop.logo_img_path.width}
|
||||
/>
|
||||
) : null}
|
||||
<div style={{ margin: "2em", verticalAlign: "middle" }}>
|
||||
<Typography.Title level={4} style={{ margin: 0 }}>
|
||||
{bodyshop.shopname || ""}
|
||||
</Typography.Title>
|
||||
<Typography.Paragraph style={{ margin: 0 }}>
|
||||
{`${bodyshop.address1 || ""}${bodyshop.address2 ? ", " : ""}${bodyshop.address2 || ""}`.trim()}
|
||||
</Typography.Paragraph>
|
||||
<Typography.Paragraph style={{ margin: 0 }}>
|
||||
{`${bodyshop.city || ""}${
|
||||
bodyshop.city && bodyshop.state ? ", " : ""
|
||||
}${bodyshop.state || ""} ${bodyshop.zip_post || ""}`.trim()}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
</div>
|
||||
<Typography.Title>{t("csi.labels.title")}</Typography.Title>
|
||||
<strong>
|
||||
{t("csi.labels.greeting", {
|
||||
name: job.ownr_co_nm || job.ownr_fn || ""
|
||||
})}
|
||||
</strong>
|
||||
<Typography.Paragraph>
|
||||
{t("csi.labels.intro", {
|
||||
shopname: bodyshop.shopname || ""
|
||||
})}
|
||||
</Typography.Paragraph>
|
||||
</div>
|
||||
|
||||
{submitting.submitted ? (
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
<Result
|
||||
status="success"
|
||||
title={t("csi.successes.submitted")}
|
||||
subTitle={t("csi.successes.submittedsub")}
|
||||
/>
|
||||
</Layout.Content>
|
||||
) : (
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto",
|
||||
}}
|
||||
>
|
||||
<Form form={form} onFinish={handleFinish}>
|
||||
{axiosResponse.csi_by_pk.valid ? (
|
||||
<><ConfigFormComponents componentList={csiquestions}/>
|
||||
<Button
|
||||
loading={submitting.loading}
|
||||
type="primary"
|
||||
htmlType="submit" style={{float: "right"}}
|
||||
>
|
||||
{t("general.actions.submit")}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Result
|
||||
title={t("csi.errors.surveycompletetitle")}
|
||||
status="warning"
|
||||
subTitle={t("csi.errors.surveycompletesubtitle", {
|
||||
date: DateTimeFormat(axiosResponse.csi_by_pk.completedon),
|
||||
})}
|
||||
/>
|
||||
<Typography.Paragraph
|
||||
type="secondary"
|
||||
style={{textAlign: "center"}}
|
||||
>
|
||||
{t("csi.successes.submittedsub")}
|
||||
</Typography.Paragraph>
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
</Layout.Content>
|
||||
{submitting.error ? <AlertComponent message={submitting.error} type="error" /> : null}
|
||||
|
||||
)}
|
||||
<Layout.Footer>
|
||||
{t("csi.labels.copyright")}{" "}
|
||||
{t("csi.fields.surveyid", {surveyId: surveyId})}
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
{submitting.submitted ? (
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto"
|
||||
}}
|
||||
>
|
||||
<Result status="success" title={t("csi.successes.submitted")} subTitle={t("csi.successes.submittedsub")} />
|
||||
</Layout.Content>
|
||||
) : (
|
||||
<Layout.Content
|
||||
style={{
|
||||
backgroundColor: "#fff",
|
||||
margin: "2em 4em",
|
||||
padding: "2em",
|
||||
overflowY: "auto"
|
||||
}}
|
||||
>
|
||||
<Form form={form} onFinish={handleFinish}>
|
||||
{axiosResponse.csi_by_pk.valid ? (
|
||||
<>
|
||||
<ConfigFormComponents componentList={csiquestions} />
|
||||
<Button loading={submitting.loading} type="primary" htmlType="submit" style={{ float: "right" }}>
|
||||
{t("general.actions.submit")}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<Result
|
||||
title={t("csi.errors.surveycompletetitle")}
|
||||
status="warning"
|
||||
subTitle={t("csi.errors.surveycompletesubtitle", {
|
||||
date: DateTimeFormat(axiosResponse.csi_by_pk.completedon)
|
||||
})}
|
||||
/>
|
||||
<Typography.Paragraph type="secondary" style={{ textAlign: "center" }}>
|
||||
{t("csi.successes.submittedsub")}
|
||||
</Typography.Paragraph>
|
||||
</>
|
||||
)}
|
||||
</Form>
|
||||
</Layout.Content>
|
||||
)}
|
||||
<Layout.Footer>
|
||||
{t("csi.labels.copyright")} {t("csi.fields.surveyid", { surveyId: surveyId })}
|
||||
</Layout.Footer>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,39 +1,44 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ExportsLogPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function ExportsLogPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dashboard", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})}
|
||||
);
|
||||
setSelectedHeader("dashboard");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/exportlogs",
|
||||
label: t("titles.bc.dashboard"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dashboard", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("dashboard");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/exportlogs",
|
||||
label: t("titles.bc.dashboard")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<FeatureWrapper featureName="dashboard">
|
||||
<RbacWrapper action="shop:dashboard">
|
||||
<DashboardGridComponent/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
return (
|
||||
<FeatureWrapper featureName="dashboard">
|
||||
<RbacWrapper action="shop:dashboard">
|
||||
<DashboardGridComponent />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ExportsLogPageContainer);
|
||||
|
||||
@@ -5,22 +5,20 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
export default function AboutPage() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div style={{ textAlign: "center", margin: "1rem 0rem" }}>
|
||||
<Typography.Title level={2}>{`${InstanceRenderMgr({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager"),
|
||||
})}Rome Online V.${import.meta.env.MODE}-${
|
||||
import.meta.env.VITE_APP_GIT_SHA
|
||||
}`}</Typography.Title>
|
||||
<Typography.Title level={2}>Third Party Notices</Typography.Title>
|
||||
<a href="/3rdparty-app.txt">
|
||||
<Typography.Title level={4}>Application</Typography.Title>
|
||||
</a>
|
||||
<a href="/3rdparty-api.txt">
|
||||
<Typography.Title level={4}>API</Typography.Title>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div style={{ textAlign: "center", margin: "1rem 0rem" }}>
|
||||
<Typography.Title level={2}>{`${InstanceRenderMgr({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})}Rome Online V.${import.meta.env.MODE}-${import.meta.env.VITE_APP_GIT_SHA}`}</Typography.Title>
|
||||
<Typography.Title level={2}>Third Party Notices</Typography.Title>
|
||||
<a href="/3rdparty-app.txt">
|
||||
<Typography.Title level={4}>Application</Typography.Title>
|
||||
</a>
|
||||
<a href="/3rdparty-api.txt">
|
||||
<Typography.Title level={4}>API</Typography.Title>
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,162 +1,162 @@
|
||||
import {Button, Card, Col, notification, Row, Select, Space} from "antd";
|
||||
import React, {useEffect, useRef, 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 { Button, Card, Col, notification, Row, Select, Space } from "antd";
|
||||
import React, { useEffect, useRef, 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 SocketIO from "socket.io-client";
|
||||
import DmsAllocationsSummaryApComponent
|
||||
from "../../components/dms-allocations-summary-ap/dms-allocations-summary-ap.component";
|
||||
import DmsAllocationsSummaryApComponent from "../../components/dms-allocations-summary-ap/dms-allocations-summary-ap.component";
|
||||
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 { 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";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
||||
|
||||
export const socket = SocketIO(
|
||||
import.meta.env.PROD
|
||||
? import.meta.env.VITE_APP_AXIOS_BASE_API_URL
|
||||
: window.location.origin,
|
||||
import.meta.env.PROD ? import.meta.env.VITE_APP_AXIOS_BASE_API_URL : window.location.origin,
|
||||
{
|
||||
path: "/ws",
|
||||
withCredentials: true,
|
||||
auth: async (callback) => {
|
||||
const token = auth.currentUser && (await auth.currentUser.getIdToken());
|
||||
callback({ token });
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export function DmsContainer({bodyshop, setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useNavigate();
|
||||
const [logs, setLogs] = useState([]);
|
||||
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useNavigate();
|
||||
const [logs, setLogs] = useState([]);
|
||||
|
||||
const {state} = useLocation();
|
||||
const { state } = useLocation();
|
||||
|
||||
const logsRef = useRef(null);
|
||||
const logsRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dms", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("dms");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payables",
|
||||
label: t("titles.bc.accounting-payables"),
|
||||
},
|
||||
{
|
||||
link: "/manage/dms",
|
||||
label: t("titles.bc.dms"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dms", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("dms");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/payables",
|
||||
label: t("titles.bc.accounting-payables")
|
||||
},
|
||||
{
|
||||
link: "/manage/dms",
|
||||
label: t("titles.bc.dms")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
socket.on("connect", () => socket.emit("set-log-level", logLevel));
|
||||
socket.on("reconnect", () => {
|
||||
setLogs((logs) => {
|
||||
return [
|
||||
...logs,
|
||||
{
|
||||
timestamp: new Date(),
|
||||
level: "WARNING",
|
||||
message: "Reconnected to CDK Export Service",
|
||||
},
|
||||
];
|
||||
});
|
||||
});
|
||||
useEffect(() => {
|
||||
socket.on("connect", () => socket.emit("set-log-level", logLevel));
|
||||
socket.on("reconnect", () => {
|
||||
setLogs((logs) => {
|
||||
return [
|
||||
...logs,
|
||||
{
|
||||
timestamp: new Date(),
|
||||
level: "WARNING",
|
||||
message: "Reconnected to CDK Export Service"
|
||||
}
|
||||
];
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("log-event", (payload) => {
|
||||
setLogs((logs) => {
|
||||
return [...logs, payload];
|
||||
});
|
||||
});
|
||||
socket.on("log-event", (payload) => {
|
||||
setLogs((logs) => {
|
||||
return [...logs, payload];
|
||||
});
|
||||
});
|
||||
|
||||
socket.on("ap-export-complete", (payload) => {
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: t("jobs.labels.dms.apexported"),
|
||||
});
|
||||
});
|
||||
socket.on("ap-export-complete", (payload) => {
|
||||
notification.open({
|
||||
type: "success",
|
||||
message: t("jobs.labels.dms.apexported")
|
||||
});
|
||||
});
|
||||
|
||||
if (socket.disconnected) socket.connect();
|
||||
return () => {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
if (socket.disconnected) socket.connect();
|
||||
return () => {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (!state?.billids) {
|
||||
history(`/manage/accounting/payables`);
|
||||
}
|
||||
if (!state?.billids) {
|
||||
history(`/manage/accounting/payables`);
|
||||
}
|
||||
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col md={24} lg={12}>
|
||||
<DmsAllocationsSummaryApComponent
|
||||
socket={socket}
|
||||
billids={state?.billids}
|
||||
/>
|
||||
</Col>
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col md={24} lg={12}>
|
||||
<DmsAllocationsSummaryApComponent socket={socket} billids={state?.billids} />
|
||||
</Col>
|
||||
|
||||
<Col md={24} lg={12}>
|
||||
<div ref={logsRef}>
|
||||
<Card
|
||||
title={t("jobs.labels.dms.logs")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Select
|
||||
placeholder="Log Level"
|
||||
value={logLevel}
|
||||
onChange={(value) => {
|
||||
setLogLevel(value);
|
||||
socket.emit("set-log-level", value);
|
||||
}}
|
||||
>
|
||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||
<Select.Option key="INFO">INFO</Select.Option>
|
||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||
</Select>
|
||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLogs([]);
|
||||
<Col md={24} lg={12}>
|
||||
<div ref={logsRef}>
|
||||
<Card
|
||||
title={t("jobs.labels.dms.logs")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Select
|
||||
placeholder="Log Level"
|
||||
value={logLevel}
|
||||
onChange={(value) => {
|
||||
setLogLevel(value);
|
||||
socket.emit("set-log-level", value);
|
||||
}}
|
||||
>
|
||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||
<Select.Option key="INFO">INFO</Select.Option>
|
||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||
</Select>
|
||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLogs([]);
|
||||
|
||||
socket.disconnect();
|
||||
socket.connect();
|
||||
}}
|
||||
>
|
||||
Reconnect
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<DmsLogEvents socket={socket} logs={logs}/>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
socket.disconnect();
|
||||
socket.connect();
|
||||
}}
|
||||
>
|
||||
Reconnect
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<DmsLogEvents socket={socket} logs={logs} />
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
export const determineDmsType = (bodyshop) => {
|
||||
if (bodyshop.cdk_dealerid) return "cdk";
|
||||
else {
|
||||
return "pbs";
|
||||
}
|
||||
if (bodyshop.cdk_dealerid) return "cdk";
|
||||
else {
|
||||
return "pbs";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Button, Card, Col, notification, Result, Row, Select, Space,} from "antd";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Button, Card, Col, notification, Result, Row, Select, Space } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect, useRef, useState} 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 React, { useEffect, useRef, useState } 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 SocketIO from "socket.io-client";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import DmsAllocationsSummary from "../../components/dms-allocations-summary/dms-allocations-summary.component";
|
||||
@@ -13,213 +13,197 @@ import DmsCustomerSelector from "../../components/dms-customer-selector/dms-cust
|
||||
import DmsLogEvents from "../../components/dms-log-events/dms-log-events.component";
|
||||
import DmsPostForm from "../../components/dms-post-form/dms-post-form.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import {OwnerNameDisplayFunction} from "../../components/owner-name-display/owner-name-display.component";
|
||||
import {auth} from "../../firebase/firebase.utils";
|
||||
import {QUERY_JOB_EXPORT_DMS} from "../../graphql/jobs.queries";
|
||||
import {
|
||||
insertAuditTrail,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
import { auth } from "../../firebase/firebase.utils";
|
||||
import { QUERY_JOB_EXPORT_DMS } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
insertAuditTrail: ({ jobid, operation, type }) =>
|
||||
dispatch(insertAuditTrail({ jobid, operation, type })),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(DmsContainer);
|
||||
|
||||
export const socket = SocketIO(
|
||||
import.meta.env.PROD
|
||||
? import.meta.env.VITE_APP_AXIOS_BASE_API_URL
|
||||
: "http://localhost:4000", // for dev testing,
|
||||
import.meta.env.PROD ? import.meta.env.VITE_APP_AXIOS_BASE_API_URL : "http://localhost:4000", // for dev testing,
|
||||
{
|
||||
path: "/ws",
|
||||
withCredentials: true,
|
||||
auth: async (callback) => {
|
||||
const token = auth.currentUser && (await auth.currentUser.getIdToken());
|
||||
callback({ token });
|
||||
},
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
export function DmsContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
insertAuditTrail,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useNavigate();
|
||||
const [logs, setLogs] = useState([]);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const {jobId} = search;
|
||||
export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader, insertAuditTrail }) {
|
||||
const { t } = useTranslation();
|
||||
const [logLevel, setLogLevel] = useState("DEBUG");
|
||||
const history = useNavigate();
|
||||
const [logs, setLogs] = useState([]);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const { jobId } = search;
|
||||
|
||||
const {loading, error, data} = useQuery(QUERY_JOB_EXPORT_DMS, {
|
||||
variables: {id: jobId},
|
||||
skip: !jobId,
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_EXPORT_DMS, {
|
||||
variables: { id: jobId },
|
||||
skip: !jobId,
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const logsRef = useRef(null);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dms", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
const logsRef = useRef(null);
|
||||
setSelectedHeader("dms");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/receivables",
|
||||
label: t("titles.bc.accounting-receivables")
|
||||
},
|
||||
{
|
||||
link: "/manage/dms",
|
||||
label: t("titles.bc.dms")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.dms",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("dms");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/receivables",
|
||||
label: t("titles.bc.accounting-receivables"),
|
||||
},
|
||||
{
|
||||
link: "/manage/dms",
|
||||
label: t("titles.bc.dms"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
socket.on("connect", () => socket.emit("set-log-level", logLevel));
|
||||
socket.on("reconnect", () => {
|
||||
setLogs((logs) => {
|
||||
return [
|
||||
...logs,
|
||||
{
|
||||
timestamp: new Date(),
|
||||
level: "WARNING",
|
||||
message: "Reconnected to CDK Export Service"
|
||||
}
|
||||
];
|
||||
});
|
||||
});
|
||||
socket.on("connect_error", (err) => {
|
||||
console.log(`connect_error due to ${err}`, err);
|
||||
notification.error({ message: err.message });
|
||||
});
|
||||
socket.on("log-event", (payload) => {
|
||||
setLogs((logs) => {
|
||||
return [...logs, payload];
|
||||
});
|
||||
});
|
||||
socket.on("export-success", (payload) => {
|
||||
notification.success({
|
||||
message: t("jobs.successes.exported")
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: payload,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
type: "jobexported"
|
||||
});
|
||||
history("/manage/accounting/receivables");
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
socket.on("connect", () => socket.emit("set-log-level", logLevel));
|
||||
socket.on("reconnect", () => {
|
||||
setLogs((logs) => {
|
||||
return [
|
||||
...logs,
|
||||
{
|
||||
timestamp: new Date(),
|
||||
level: "WARNING",
|
||||
message: "Reconnected to CDK Export Service",
|
||||
},
|
||||
];
|
||||
});
|
||||
});
|
||||
socket.on("connect_error", (err) => {
|
||||
console.log(`connect_error due to ${err}`, err);
|
||||
notification.error({message: err.message});
|
||||
});
|
||||
socket.on("log-event", (payload) => {
|
||||
setLogs((logs) => {
|
||||
return [...logs, payload];
|
||||
});
|
||||
});
|
||||
socket.on("export-success", (payload) => {
|
||||
notification.success({
|
||||
message: t("jobs.successes.exported"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: payload,
|
||||
operation: AuditTrailMapping.jobexported(),
|
||||
type: "jobexported",});
|
||||
history("/manage/accounting/receivables");
|
||||
});
|
||||
if (socket.disconnected) socket.connect();
|
||||
return () => {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
|
||||
if (socket.disconnected) socket.connect();
|
||||
return () => {
|
||||
socket.removeAllListeners();
|
||||
socket.disconnect();
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, []);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!jobId || !(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) || !(data && data.jobs_by_pk))
|
||||
return <Result status="404" title={t("general.errors.notfound")} />;
|
||||
|
||||
if (
|
||||
!jobId ||
|
||||
!(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) ||
|
||||
!(data && data.jobs_by_pk)
|
||||
)
|
||||
return <Result status="404" title={t("general.errors.notfound")}/>;
|
||||
if (data.jobs_by_pk && data.jobs_by_pk.date_exported)
|
||||
return <Result status="warning" title={t("dms.errors.alreadyexported")} />;
|
||||
|
||||
if (data.jobs_by_pk && data.jobs_by_pk.date_exported)
|
||||
return <Result status="warning" title={t("dms.errors.alreadyexported")}/>;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col md={24} lg={10}>
|
||||
<DmsAllocationsSummary
|
||||
title={
|
||||
<span>
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col md={24} lg={10}>
|
||||
<DmsAllocationsSummary
|
||||
title={
|
||||
<span>
|
||||
<Link to={`/manage/jobs/${data && data.jobs_by_pk.id}`}>{`${
|
||||
data && data.jobs_by_pk && data.jobs_by_pk.ro_number
|
||||
data && data.jobs_by_pk && data.jobs_by_pk.ro_number
|
||||
}`}</Link>
|
||||
{` | ${OwnerNameDisplayFunction(data.jobs_by_pk)} | ${
|
||||
data.jobs_by_pk.v_model_yr || ""
|
||||
} ${data.jobs_by_pk.v_make_desc || ""} ${
|
||||
data.jobs_by_pk.v_model_desc || ""
|
||||
}`}
|
||||
{` | ${OwnerNameDisplayFunction(data.jobs_by_pk)} | ${
|
||||
data.jobs_by_pk.v_model_yr || ""
|
||||
} ${data.jobs_by_pk.v_make_desc || ""} ${data.jobs_by_pk.v_model_desc || ""}`}
|
||||
</span>
|
||||
}
|
||||
socket={socket}
|
||||
jobId={jobId}
|
||||
/>
|
||||
</Col>
|
||||
<Col md={24} lg={14}>
|
||||
<DmsPostForm
|
||||
socket={socket}
|
||||
jobId={jobId}
|
||||
job={data && data.jobs_by_pk}
|
||||
logsRef={logsRef}
|
||||
/>
|
||||
</Col>
|
||||
}
|
||||
socket={socket}
|
||||
jobId={jobId}
|
||||
/>
|
||||
</Col>
|
||||
<Col md={24} lg={14}>
|
||||
<DmsPostForm socket={socket} jobId={jobId} job={data && data.jobs_by_pk} logsRef={logsRef} />
|
||||
</Col>
|
||||
|
||||
<DmsCustomerSelector/>
|
||||
<DmsCustomerSelector />
|
||||
|
||||
<Col span={24}>
|
||||
<div ref={logsRef}>
|
||||
<Card
|
||||
title={t("jobs.labels.dms.logs")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Select
|
||||
placeholder="Log Level"
|
||||
value={logLevel}
|
||||
onChange={(value) => {
|
||||
setLogLevel(value);
|
||||
socket.emit("set-log-level", value);
|
||||
}}
|
||||
>
|
||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||
<Select.Option key="INFO">INFO</Select.Option>
|
||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||
</Select>
|
||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLogs([]);
|
||||
socket.disconnect();
|
||||
socket.connect();
|
||||
}}
|
||||
>
|
||||
Reconnect
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<DmsLogEvents socket={socket} logs={logs}/>
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
<Col span={24}>
|
||||
<div ref={logsRef}>
|
||||
<Card
|
||||
title={t("jobs.labels.dms.logs")}
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Select
|
||||
placeholder="Log Level"
|
||||
value={logLevel}
|
||||
onChange={(value) => {
|
||||
setLogLevel(value);
|
||||
socket.emit("set-log-level", value);
|
||||
}}
|
||||
>
|
||||
<Select.Option key="TRACE">TRACE</Select.Option>
|
||||
<Select.Option key="DEBUG">DEBUG</Select.Option>
|
||||
<Select.Option key="INFO">INFO</Select.Option>
|
||||
<Select.Option key="WARNING">WARNING</Select.Option>
|
||||
<Select.Option key="ERROR">ERROR</Select.Option>
|
||||
</Select>
|
||||
<Button onClick={() => setLogs([])}>Clear Logs</Button>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setLogs([]);
|
||||
socket.disconnect();
|
||||
socket.connect();
|
||||
}}
|
||||
>
|
||||
Reconnect
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<DmsLogEvents socket={socket} logs={logs} />
|
||||
</Card>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export const determineDmsType = (bodyshop) => {
|
||||
if (bodyshop.cdk_dealerid) return "cdk";
|
||||
else {
|
||||
return "pbs";
|
||||
}
|
||||
if (bodyshop.cdk_dealerid) return "cdk";
|
||||
else {
|
||||
return "pbs";
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,168 +1,145 @@
|
||||
import {SyncOutlined} from "@ant-design/icons";
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Button, Card, Checkbox, Input, Space, Table, Typography} from "antd";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
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 { 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 { 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,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
export function ExportLogsPageComponent({bodyshop}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder, search} = searchParams;
|
||||
const history = useNavigate();
|
||||
export function ExportLogsPageComponent({ bodyshop }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search } = searchParams;
|
||||
const history = useNavigate();
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_EXPORT_LOG_PAGINATED,
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_EXPORT_LOG_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
...(sortcolumn === "ro_number"
|
||||
? {
|
||||
job: {
|
||||
[sortcolumn|| "created_at"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",},
|
||||
...(sortcolumn === "ro_number"
|
||||
? {
|
||||
job: {
|
||||
[sortcolumn || "created_at"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
: sortcolumn === "invoice_number"
|
||||
}
|
||||
: sortcolumn === "invoice_number"
|
||||
? {
|
||||
bill: {
|
||||
[sortcolumn || "created_at"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
[sortcolumn || "created_at"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
}
|
||||
: sortcolumn === "paymentnum"
|
||||
? {
|
||||
payment: {
|
||||
[sortcolumn || "created_at"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
}
|
||||
: {
|
||||
[sortcolumn || "created_at"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
? {
|
||||
payment: {
|
||||
[sortcolumn || "created_at"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
}
|
||||
: {
|
||||
[sortcolumn || "created_at"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
})
|
||||
}
|
||||
);
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
searchParams.sortcolumn = sorter.columnKey;
|
||||
searchParams.sortorder = sorter.order;
|
||||
if (filters.status) {
|
||||
searchParams.statusFilters = JSON.stringify(
|
||||
_.flattenDeep(filters.status)
|
||||
);
|
||||
} else {
|
||||
delete searchParams.statusFilters;
|
||||
}
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
};
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
searchParams.sortcolumn = sorter.columnKey;
|
||||
searchParams.sortorder = sorter.order;
|
||||
if (filters.status) {
|
||||
searchParams.statusFilters = JSON.stringify(_.flattenDeep(filters.status));
|
||||
} else {
|
||||
delete searchParams.statusFilters;
|
||||
}
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("general.labels.created_at"),
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
sorter: (a, b) => dateSort(a.created_at, b.created_at),
|
||||
sortOrder: sortcolumn === "created_at" && sortorder,render: (text, record) => (
|
||||
<DateTimeFormatter>{record.created_at}</DateTimeFormatter>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("employees.fields.user_email"),
|
||||
dataIndex: "useremail",
|
||||
key: "useremail",
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
const columns = [
|
||||
{
|
||||
title: t("general.labels.created_at"),
|
||||
dataIndex: "created_at",
|
||||
key: "created_at",
|
||||
sorter: (a, b) => dateSort(a.created_at, b.created_at),
|
||||
sortOrder: sortcolumn === "created_at" && sortorder,
|
||||
render: (text, record) => <DateTimeFormatter>{record.created_at}</DateTimeFormatter>
|
||||
},
|
||||
{
|
||||
title: t("employees.fields.user_email"),
|
||||
dataIndex: "useremail",
|
||||
key: "useremail"
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
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>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.invoice_number"),
|
||||
dataIndex: "invoice_number",
|
||||
key: "invoice_number",
|
||||
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>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("payments.fields.paymentnum"),
|
||||
dataIndex: "paymentnum",
|
||||
key: "paymentnum",sorter: (a, b) => alphaSort(a.paymentnum, b.paymentnum),
|
||||
render: (text, record) =>
|
||||
record.job && (
|
||||
<Link to={`/manage/jobs/${record.job.id}`}>
|
||||
{(record.job && record.job.ro_number) || t("general.labels.na")}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("bills.fields.invoice_number"),
|
||||
dataIndex: "invoice_number",
|
||||
key: "invoice_number",
|
||||
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>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("payments.fields.paymentnum"),
|
||||
dataIndex: "paymentnum",
|
||||
key: "paymentnum",
|
||||
sorter: (a, b) => alphaSort(a.paymentnum, b.paymentnum),
|
||||
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>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("general.labels.successful"),
|
||||
dataIndex: "successful",
|
||||
key: "successful",sorter: (a, b) => Number(a.successful) - Number(b.successful),
|
||||
render: (text, record) =>
|
||||
record.payment && (
|
||||
<Link to={"/manage/payments?search=" + (record.payment && record.payment.paymentnum)}>
|
||||
{record.payment && record.payment.paymentnum}
|
||||
</Link>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("general.labels.successful"),
|
||||
dataIndex: "successful",
|
||||
key: "successful",
|
||||
sorter: (a, b) => Number(a.successful) - Number(b.successful),
|
||||
sortOrder: sortcolumn === "successful" && sortorder,
|
||||
filters: [
|
||||
{ text: "True", value: true },
|
||||
{ text: "False", value: false },
|
||||
{ text: "False", value: false }
|
||||
],
|
||||
onFilter: (value, record) => record.successful === value,
|
||||
render: (text, record) => <Checkbox checked={record.successful} />,
|
||||
render: (text, record) => <Checkbox checked={record.successful} />
|
||||
},
|
||||
{
|
||||
title: t("general.labels.message"),
|
||||
@@ -177,61 +154,61 @@ sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
),
|
||||
},
|
||||
)
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
{searchParams.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", {
|
||||
search: searchParams.search,
|
||||
})}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete searchParams.search;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
}}
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined/>
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={searchParams.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
searchParams.search = value;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: data && data.search_exportlog_aggregate.aggregate.count,
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
{searchParams.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", {
|
||||
search: searchParams.search
|
||||
})}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete searchParams.search;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_exportlog}
|
||||
style={{height: "100%"}}
|
||||
scroll={{x: true}}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={searchParams.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
searchParams.search = value;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: data && data.search_exportlog_aggregate.aggregate.count
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_exportlog}
|
||||
style={{ height: "100%" }}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(ExportLogsPageComponent);
|
||||
|
||||
@@ -1,38 +1,44 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import ExportLogsPage from "./export-logs.page.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ExportsLogPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function ExportsLogPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.export-logs",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("export-logs");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/exportlogs",
|
||||
label: t("titles.bc.export-logs"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.export-logs", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("export-logs");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/accounting/exportlogs",
|
||||
label: t("titles.bc.export-logs")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='export'>
|
||||
<RbacWrapper action="accounting:exportlogs">
|
||||
<ExportLogsPage/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="export">
|
||||
<RbacWrapper action="accounting:exportlogs">
|
||||
<ExportLogsPage />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ExportsLogPageContainer);
|
||||
|
||||
@@ -2,9 +2,9 @@ import React from "react";
|
||||
import HelpRescue from "../../components/help-rescue/help-rescue.component";
|
||||
|
||||
export default function HelpPage() {
|
||||
return (
|
||||
<div>
|
||||
<HelpRescue/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<HelpRescue />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import InventoryList from "../../components/inventory-list/inventory-list.container";
|
||||
import InventoryUpsertModalContainer from "../../components/inventory-upsert-modal/inventory-upsert-modal.container";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function InventoryPage({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function InventoryPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.inventory",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("inventory");
|
||||
setBreadcrumbs([{link: "/manage/jobs", label: t("titles.bc.inventory")}]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.inventory", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("inventory");
|
||||
setBreadcrumbs([{ link: "/manage/jobs", label: t("titles.bc.inventory") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="inventory:list">
|
||||
<InventoryUpsertModalContainer/>
|
||||
<InventoryList/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="inventory:list">
|
||||
<InventoryUpsertModalContainer />
|
||||
<InventoryList />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(InventoryPage);
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Card, Col, Result, Row, Space, Typography} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Card, Col, Result, Row, Space, Typography } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component";
|
||||
import ScoreboardAddButton from "../../components/job-scoreboard-add-button/job-scoreboard-add-button.component";
|
||||
@@ -12,127 +12,121 @@ import JobsAdminClass from "../../components/jobs-admin-class/jobs-admin-class.c
|
||||
import JobsAdminDatesChange from "../../components/jobs-admin-dates/jobs-admin-dates.component";
|
||||
import JobsAdminDeleteIntake from "../../components/jobs-admin-delete-intake/jobs-admin-delete-intake.component";
|
||||
import JobsAdminMarkReexport from "../../components/jobs-admin-mark-reexport/jobs-admin-mark-reexport.component";
|
||||
import JobAdminOwnerReassociate
|
||||
from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component";
|
||||
import JobAdminOwnerReassociate from "../../components/jobs-admin-owner-reassociate/jobs-admin-owner-reassociate.component";
|
||||
import JobsAdminUnvoid from "../../components/jobs-admin-unvoid/jobs-admin-unvoid.component";
|
||||
import JobAdminVehicleReassociate
|
||||
from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component";
|
||||
import JobAdminVehicleReassociate from "../../components/jobs-admin-vehicle-reassociate/jobs-admin-vehicle-reassociate.component";
|
||||
import JobsAdminRemoveAR from "../../components/jobs-admin-remove-ar/jobs-admin-remove-ar.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {GET_JOB_BY_PK} from "../../graphql/jobs.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
|
||||
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)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
const colSpan = {
|
||||
sm: {span: 24},
|
||||
md: {span: 12},
|
||||
lg: {span: 8},
|
||||
xl: {span: 6},
|
||||
sm: { span: 24 },
|
||||
md: { span: 12 },
|
||||
lg: { span: 8 },
|
||||
xl: { span: 6 }
|
||||
};
|
||||
|
||||
const cardStyle = {
|
||||
height: "100%",
|
||||
height: "100%"
|
||||
};
|
||||
|
||||
export function JobsCloseContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {jobId} = useParams();
|
||||
const {loading, error, data} = useQuery(GET_JOB_BY_PK, {
|
||||
variables: {id: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(GET_JOB_BY_PK, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-admin", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
ro_number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-admin", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
ro_number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null,
|
||||
});
|
||||
|
||||
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 : null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/admin`,
|
||||
label: t("titles.bc.jobs-admin"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, setSelectedHeader]);
|
||||
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 : null
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/admin`,
|
||||
label: t("titles.bc.jobs-admin")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, 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.job_totals)
|
||||
return (
|
||||
<Result
|
||||
title={t("jobs.errors.nofinancial")}
|
||||
extra={<JobCalculateTotals job={data.jobs_by_pk}/>}
|
||||
/>
|
||||
);
|
||||
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.job_totals)
|
||||
return <Result title={t("jobs.errors.nofinancial")} extra={<JobCalculateTotals job={data.jobs_by_pk} />} />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:admin">
|
||||
<Typography.Title level={4} style={{color: "tomato"}}>
|
||||
{t("jobs.labels.adminwarning")}
|
||||
</Typography.Title>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<Space wrap>
|
||||
<ScoreboardAddButton
|
||||
job={data ? data.jobs_by_pk : {}}
|
||||
disabled={
|
||||
(data && data.jobs_by_pk.voided) ||
|
||||
(data.jobs_by_pk && !data.jobs_by_pk.converted)
|
||||
}
|
||||
/>
|
||||
<JobsAdminDeleteIntake job={data ? data.jobs_by_pk : {}}/>
|
||||
<JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}}/>
|
||||
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}}/>
|
||||
<JobsAdminStatus job={data ? data.jobs_by_pk : {}}/>
|
||||
<JobsAdminRemoveAR job={data ? data.jobs_by_pk : {}}/>
|
||||
</Space>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobsAdminClass job={data ? data.jobs_by_pk : {}}/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobAdminOwnerReassociate job={data ? data.jobs_by_pk : {}}/>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobAdminVehicleReassociate job={data ? data.jobs_by_pk : {}}/>
|
||||
</Card>
|
||||
</Col>
|
||||
return (
|
||||
<RbacWrapper action="jobs:admin">
|
||||
<Typography.Title level={4} style={{ color: "tomato" }}>
|
||||
{t("jobs.labels.adminwarning")}
|
||||
</Typography.Title>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<Space wrap>
|
||||
<ScoreboardAddButton
|
||||
job={data ? data.jobs_by_pk : {}}
|
||||
disabled={(data && data.jobs_by_pk.voided) || (data.jobs_by_pk && !data.jobs_by_pk.converted)}
|
||||
/>
|
||||
<JobsAdminDeleteIntake job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminMarkReexport job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminUnvoid job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminStatus job={data ? data.jobs_by_pk : {}} />
|
||||
<JobsAdminRemoveAR job={data ? data.jobs_by_pk : {}} />
|
||||
</Space>
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobsAdminClass job={data ? data.jobs_by_pk : {}} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobAdminOwnerReassociate job={data ? data.jobs_by_pk : {}} />
|
||||
</Card>
|
||||
</Col>
|
||||
<Col {...colSpan}>
|
||||
<Card style={cardStyle}>
|
||||
<JobAdminVehicleReassociate job={data ? data.jobs_by_pk : {}} />
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<Col span={24}>
|
||||
<Card style={cardStyle}>
|
||||
<JobsAdminDatesChange job={data ? data.jobs_by_pk : {}}/>
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
<Col span={24}>
|
||||
<Card style={cardStyle}>
|
||||
<JobsAdminDatesChange job={data ? data.jobs_by_pk : {}} />
|
||||
</Card>
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(JobsCloseContainer);
|
||||
|
||||
@@ -1,75 +1,72 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobsListPaginated from "../../components/jobs-list-paginated/jobs-list-paginated.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED} from "../../graphql/jobs.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//bodyshop: selectBodyshop,
|
||||
//bodyshop: selectBodyshop,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AllJobs({setBreadcrumbs, setSelectedHeader}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder, statusFilters} = searchParams;
|
||||
export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, statusFilters } = searchParams;
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED,
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_JOBS_PAGINATED_STATUS_FILTERED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
...(statusFilters ? { statusList: JSON.parse(statusFilters) } : {}),
|
||||
order: [
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
...(statusFilters ? {statusList: JSON.parse(statusFilters)} : {}),
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "ro_number"]:
|
||||
sortorder && sortorder !== "false"
|
||||
? (sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc")
|
||||
: "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
[sortcolumn || "ro_number"]:
|
||||
sortorder && sortorder !== "false" ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
);
|
||||
const {t} = useTranslation();
|
||||
]
|
||||
}
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-all", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("alljobs");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/jobs/all", label: t("titles.bc.jobs-all")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-all", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("alljobs");
|
||||
setBreadcrumbs([{ link: "/manage/jobs/all", label: t("titles.bc.jobs-all") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-all">
|
||||
<JobsListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.jobs_aggregate.aggregate.count : 0}
|
||||
jobs={data ? data.jobs : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-all">
|
||||
<JobsListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.jobs_aggregate.aggregate.count : 0}
|
||||
jobs={data ? data.jobs : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AllJobs);
|
||||
|
||||
@@ -1,66 +1,69 @@
|
||||
import {Button} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
import { Button } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {Link} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobsAvailableTableContainer from "../../components/jobs-available-table/jobs-available-table.container";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectPartnerVersion} from "../../redux/application/application.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectPartnerVersion } from "../../redux/application/application.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
partnerVersion: selectPartnerVersion,
|
||||
partnerVersion: selectPartnerVersion
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsAvailablePageContainer({
|
||||
partnerVersion,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function JobsAvailablePageContainer({ partnerVersion, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobsavailable", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("availablejobs");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/available", label: t("titles.bc.availablejobs")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobsavailable", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("availablejobs");
|
||||
setBreadcrumbs([{ link: "/manage/available", label: t("titles.bc.availablejobs") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:available-list">
|
||||
<div>
|
||||
<PageHeader
|
||||
title={t("titles.bc.availablejobs")}
|
||||
extra={
|
||||
<Link to="/manage/jobs/new">
|
||||
<Button>{t("jobs.actions.manualnew")}</Button>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
{!partnerVersion && (
|
||||
<AlertComponent
|
||||
type="warning"
|
||||
message={t("general.messages.partnernotrunning",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}
|
||||
/>
|
||||
)}
|
||||
<JobsAvailableTableContainer/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:available-list">
|
||||
<div>
|
||||
<PageHeader
|
||||
title={t("titles.bc.availablejobs")}
|
||||
extra={
|
||||
<Link to="/manage/jobs/new">
|
||||
<Button>{t("jobs.actions.manualnew")}</Button>
|
||||
</Link>
|
||||
}
|
||||
/>
|
||||
{!partnerVersion && (
|
||||
<AlertComponent
|
||||
type="warning"
|
||||
message={t("general.messages.partnernotrunning", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
})}
|
||||
/>
|
||||
)}
|
||||
<JobsAvailableTableContainer />
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsAvailablePageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsAvailablePageContainer);
|
||||
|
||||
@@ -1,126 +1,112 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Col, Row, Typography} from "antd";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Col, Row, Typography } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { 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 JobChecklistForm
|
||||
from "../../components/job-checklist/components/job-checklist-form/job-checklist-form.component";
|
||||
import JobChecklistForm from "../../components/job-checklist/components/job-checklist-form/job-checklist-form.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
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 { 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";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsChecklistViewContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const {jobId} = useParams();
|
||||
const {loading, error, data} = useQuery(QUERY_JOB_CHECKLISTS, {
|
||||
variables: {id: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function JobsChecklistViewContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_CHECKLISTS, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-checklist", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("activejobs");
|
||||
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) || ""
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/checklist`,
|
||||
label: t("titles.bc.jobs-checklist")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-checklist",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("activejobs");
|
||||
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) || "",
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/checklist`,
|
||||
label: t("titles.bc.jobs-checklist"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
//The Form is the actual config to use.
|
||||
|
||||
//The Form is the actual config to use.
|
||||
const CompletedBy = ({ checklist }) => (
|
||||
<div>
|
||||
<div>
|
||||
{t("jobs.labels.checklistcompletedby", {
|
||||
by: checklist.completed_by,
|
||||
at: dayjs(checklist.completed_at).format("MM/DD/YYYY @ h:mm a")
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const CompletedBy = ({checklist}) => (
|
||||
<div>
|
||||
<div>
|
||||
{t("jobs.labels.checklistcompletedby", {
|
||||
by: checklist.completed_by,
|
||||
at: dayjs(checklist.completed_at).format("MM/DD/YYYY @ h:mm a"),
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:checklist-view">
|
||||
<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 && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={
|
||||
data.jobs_by_pk.intakechecklist &&
|
||||
data.jobs_by_pk.intakechecklist.form
|
||||
}
|
||||
type="intake"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.intakechecklist}/>
|
||||
</>
|
||||
)}
|
||||
</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 && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={
|
||||
data.jobs_by_pk.deliverchecklist &&
|
||||
data.jobs_by_pk.deliverchecklist.form
|
||||
}
|
||||
type="deliver"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist}/>
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:checklist-view">
|
||||
<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 && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.intakechecklist && data.jobs_by_pk.intakechecklist.form}
|
||||
type="intake"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.intakechecklist} />
|
||||
</>
|
||||
)}
|
||||
</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 && (
|
||||
<>
|
||||
<JobChecklistForm
|
||||
formItems={data.jobs_by_pk.deliverchecklist && data.jobs_by_pk.deliverchecklist.form}
|
||||
type="deliver"
|
||||
job={data.jobs_by_pk}
|
||||
readOnly
|
||||
/>
|
||||
<CompletedBy checklist={data.jobs_by_pk.deliverchecklist} />
|
||||
</>
|
||||
)}
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsChecklistViewContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsChecklistViewContainer);
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
import {DeleteFilled} from "@ant-design/icons";
|
||||
import {useApolloClient, useMutation} from "@apollo/client";
|
||||
import { DeleteFilled } from "@ant-design/icons";
|
||||
import { useApolloClient, useMutation } from "@apollo/client";
|
||||
import {
|
||||
Alert,
|
||||
Button,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
notification,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Statistic,
|
||||
Switch,
|
||||
Typography,
|
||||
Alert,
|
||||
Button,
|
||||
Col,
|
||||
Divider,
|
||||
Form,
|
||||
Input,
|
||||
InputNumber,
|
||||
notification,
|
||||
Popconfirm,
|
||||
Row,
|
||||
Select,
|
||||
Space,
|
||||
Statistic,
|
||||
Switch,
|
||||
Typography
|
||||
} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React, {useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
// import { useNavigate } from 'react-router-dom';
|
||||
import {useSplitTreatments} from "@splitsoftware/splitio-react";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import Dinero from "dinero.js";
|
||||
import dayjs from "../../utils/day";
|
||||
import {Link} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { Link } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import DateTimePicker from "../../components/form-date-time-picker/form-date-time-picker.component";
|
||||
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
||||
import CurrencyInput from "../../components/form-items-formatted/currency-form-item.component";
|
||||
@@ -35,510 +35,450 @@ import JobsScoreboardAdd from "../../components/job-scoreboard-add-button/job-sc
|
||||
import JobsCloseAutoAllocate from "../../components/jobs-close-auto-allocate/jobs-close-auto-allocate.component";
|
||||
import JobsCloseLines from "../../components/jobs-close-lines/jobs-close-lines.component";
|
||||
import LayoutFormRow from "../../components/layout-form-row/layout-form-row.component";
|
||||
import {generateJobLinesUpdatesForInvoicing} from "../../graphql/jobs-lines.queries";
|
||||
import {UPDATE_JOB} from "../../graphql/jobs.queries";
|
||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||
import {selectJobReadOnly} from "../../redux/application/application.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { generateJobLinesUpdatesForInvoicing } from "../../graphql/jobs-lines.queries";
|
||||
import { UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import { insertAuditTrail } from "../../redux/application/application.actions";
|
||||
import { selectJobReadOnly } from "../../redux/application/application.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
insertAuditTrail: ({jobid, operation, type}) =>
|
||||
dispatch(insertAuditTrail({jobid, operation, type })),
|
||||
insertAuditTrail: ({ jobid, operation, type }) => dispatch(insertAuditTrail({ jobid, operation, type }))
|
||||
});
|
||||
|
||||
export function JobsCloseComponent({job, bodyshop, jobRO, insertAuditTrail}) {
|
||||
const {t} = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const client = useApolloClient();
|
||||
// const history = useNavigate();
|
||||
const [closeJob] = useMutation(UPDATE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
export function JobsCloseComponent({ job, bodyshop, jobRO, insertAuditTrail }) {
|
||||
const { t } = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const client = useApolloClient();
|
||||
// const history = useNavigate();
|
||||
const [closeJob] = useMutation(UPDATE_JOB);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
const {treatments: {Qb_Multi_Ar, ClosingPeriod}} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Qb_Multi_Ar", "ClosingPeriod"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid,
|
||||
const {
|
||||
treatments: { Qb_Multi_Ar, ClosingPeriod }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Qb_Multi_Ar", "ClosingPeriod"],
|
||||
splitKey: bodyshop && bodyshop.imexshopid
|
||||
});
|
||||
|
||||
const handleFinish = async ({ removefromproduction, ...values }) => {
|
||||
setLoading(true);
|
||||
const result = await client.mutate({
|
||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines)
|
||||
});
|
||||
if (result.errors) {
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: values.date_invoiced,
|
||||
actual_in: values.actual_in,
|
||||
actual_completion: values.actual_completion,
|
||||
actual_delivery: values.actual_delivery,
|
||||
kmin: values.kmin,
|
||||
kmout: values.kmout,
|
||||
dms_allocation: values.dms_allocation,
|
||||
...(removefromproduction ? { inproduction: false } : {}),
|
||||
...(values.qb_multiple_payers ? { qb_multiple_payers: values.qb_multiple_payers } : {})
|
||||
}
|
||||
},
|
||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||
awaitRefetchQueries: true
|
||||
});
|
||||
|
||||
const handleFinish = async ({removefromproduction, ...values}) => {
|
||||
setLoading(true);
|
||||
const result = await client.mutate({
|
||||
mutation: generateJobLinesUpdatesForInvoicing(values.joblines),
|
||||
});
|
||||
if (result.errors) {
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
if (!result.errors) {
|
||||
// notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("job.errors.saving", {
|
||||
error: JSON.stringify(result.errors)
|
||||
})
|
||||
});
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
|
||||
const closeResult = await closeJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
status: bodyshop.md_ro_statuses.default_invoiced || "",
|
||||
date_invoiced: values.date_invoiced,
|
||||
actual_in: values.actual_in,
|
||||
actual_completion: values.actual_completion,
|
||||
actual_delivery: values.actual_delivery,
|
||||
kmin: values.kmin,
|
||||
kmout: values.kmout,
|
||||
dms_allocation: values.dms_allocation,
|
||||
...(removefromproduction ? {inproduction: false} : {}),
|
||||
...(values.qb_multiple_payers
|
||||
? {qb_multiple_payers: values.qb_multiple_payers}
|
||||
: {}),
|
||||
},
|
||||
},
|
||||
refetchQueries: ["QUERY_JOB_CLOSE_DETAILS"],
|
||||
awaitRefetchQueries: true,
|
||||
});
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
|
||||
if (!result.errors) {
|
||||
// notification["success"]({ message: t("jobs.successes.save") });
|
||||
// form.resetFields();
|
||||
} else {
|
||||
notification["error"]({
|
||||
message: t("job.errors.saving", {
|
||||
error: JSON.stringify(result.errors),
|
||||
}),
|
||||
});
|
||||
return; // Abandon the rest of the close.
|
||||
}
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.closed")
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobinvoiced(),
|
||||
type: "jobinvoiced"
|
||||
});
|
||||
// history(`/manage/jobs/${job.id}`);
|
||||
} else {
|
||||
setLoading(false);
|
||||
notification["error"]({
|
||||
message: t("job.errors.closing", {
|
||||
error: JSON.stringify(closeResult.errors)
|
||||
})
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
|
||||
if (!closeResult.errors) {
|
||||
setLoading(false);
|
||||
setLoading(false);
|
||||
};
|
||||
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.closed"),
|
||||
});
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobinvoiced(),
|
||||
type: "jobinvoiced",});
|
||||
// history(`/manage/jobs/${job.id}`);
|
||||
} else {
|
||||
setLoading(false);
|
||||
notification["error"]({
|
||||
message: t("job.errors.closing", {
|
||||
error: JSON.stringify(closeResult.errors),
|
||||
}),
|
||||
});
|
||||
}
|
||||
form.resetFields();
|
||||
form.resetFields();
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
joblines: job.joblines,
|
||||
actual_in: job.actual_in ? dayjs(job.actual_in) : job.scheduled_in && dayjs(job.scheduled_in),
|
||||
actual_completion: job.actual_completion
|
||||
? dayjs(job.actual_completion)
|
||||
: job.scheduled_completion && dayjs(job.scheduled_completion),
|
||||
actual_delivery: job.actual_delivery
|
||||
? dayjs(job.actual_delivery)
|
||||
: job.scheduled_delivery && dayjs(job.scheduled_delivery),
|
||||
date_invoiced: job.date_invoiced ? dayjs(job.date_invoiced) : dayjs(),
|
||||
kmin: job.kmin,
|
||||
kmout: job.kmout,
|
||||
dms_allocation: job.dms_allocation,
|
||||
qb_multiple_payers: job.qb_multiple_payers
|
||||
}}
|
||||
scrollToFirstError
|
||||
>
|
||||
<PageHeader
|
||||
title={t("jobs.labels.closejob", { ro_number: job.ro_number })}
|
||||
extra={
|
||||
<Space>
|
||||
<JobsCloseAutoAllocate joblines={job.joblines} form={form} disabled={!!job.date_exported || jobRO} />
|
||||
|
||||
setLoading(false);
|
||||
};
|
||||
<Popconfirm
|
||||
onConfirm={() => form.submit()}
|
||||
disabled={jobRO}
|
||||
okText={t("general.labels.yes")}
|
||||
cancelText={t("general.labels.no")}
|
||||
title={t("jobs.labels.closeconfirm")}
|
||||
>
|
||||
<Button loading={loading} type="primary" danger disabled={jobRO}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
{(bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid) && (
|
||||
<Link to={`/manage/dms?jobId=${job.id}`}>
|
||||
<Button disabled={job.date_exported || !jobRO}>{t("jobs.actions.sendtodms")}</Button>
|
||||
</Link>
|
||||
)}
|
||||
<JobsScoreboardAdd job={job} disabled={false} />
|
||||
</Space>
|
||||
}
|
||||
/>
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Form
|
||||
layout="vertical"
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
initialValues={{
|
||||
joblines: job.joblines,
|
||||
actual_in: job.actual_in
|
||||
? dayjs(job.actual_in)
|
||||
: job.scheduled_in && dayjs(job.scheduled_in),
|
||||
actual_completion: job.actual_completion
|
||||
? dayjs(job.actual_completion)
|
||||
: job.scheduled_completion && dayjs(job.scheduled_completion),
|
||||
actual_delivery: job.actual_delivery
|
||||
? dayjs(job.actual_delivery)
|
||||
: job.scheduled_delivery && dayjs(job.scheduled_delivery),
|
||||
date_invoiced: job.date_invoiced
|
||||
? dayjs(job.date_invoiced)
|
||||
: dayjs(),
|
||||
kmin: job.kmin,
|
||||
kmout: job.kmout,
|
||||
dms_allocation: job.dms_allocation,
|
||||
qb_multiple_payers: job.qb_multiple_payers,
|
||||
}}
|
||||
scrollToFirstError
|
||||
>
|
||||
<PageHeader
|
||||
title={t("jobs.labels.closejob", {ro_number: job.ro_number})}
|
||||
extra={
|
||||
<Space>
|
||||
<JobsCloseAutoAllocate
|
||||
joblines={job.joblines}
|
||||
form={form}
|
||||
disabled={!!job.date_exported || jobRO}
|
||||
/>
|
||||
|
||||
<Popconfirm
|
||||
onConfirm={() => form.submit()}
|
||||
disabled={jobRO}
|
||||
okText={t("general.labels.yes")}
|
||||
cancelText={t("general.labels.no")}
|
||||
title={t("jobs.labels.closeconfirm")}
|
||||
>
|
||||
<Button loading={loading} type="primary" danger disabled={jobRO}>
|
||||
{t("general.actions.close")}
|
||||
</Button>
|
||||
</Popconfirm>
|
||||
{(bodyshop.pbs_serialnumber || bodyshop.cdk_dealerid) && (
|
||||
<Link to={`/manage/dms?jobId=${job.id}`}>
|
||||
<Button disabled={job.date_exported || !jobRO}>
|
||||
{t("jobs.actions.sendtodms")}
|
||||
</Button>
|
||||
</Link>
|
||||
)}
|
||||
<JobsScoreboardAdd job={job} disabled={false}/>
|
||||
</Space>
|
||||
<Space wrap direction="vertical" style={{ width: "100%" }}>
|
||||
<FormsFieldChanged form={form} />
|
||||
{!job.actual_in && job.scheduled_in && <Alert type="warning" message={t("jobs.labels.actual_in_inferred")} />}
|
||||
{!job.actual_completion && job.scheduled_completion && (
|
||||
<Alert type="warning" message={t("jobs.labels.actual_completion_inferred")} />
|
||||
)}
|
||||
{!job.actual_delivery && job.scheduled_delivery && (
|
||||
<Alert type="warning" message={t("jobs.labels.actual_delivery_inferred")} />
|
||||
)}
|
||||
</Space>
|
||||
<LayoutFormRow>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_in")}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
name="actual_in"
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_completion")}
|
||||
name="actual_completion"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_delivery")}
|
||||
name="actual_delivery"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} />
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_invoiced")}
|
||||
name="date_invoiced"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!bodyshop.cdk_dealerid) return Promise.resolve();
|
||||
if (!value || dayjs(value).isSameOrAfter(dayjs(), "day")) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(new Error(t("jobs.labels.dms.invoicedatefuture")));
|
||||
}
|
||||
}),
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (ClosingPeriod.treatment === "on" && bodyshop.accountingconfig.ClosingPeriod) {
|
||||
if (
|
||||
dayjs(value).isSameOrAfter(dayjs(bodyshop.accountingconfig.ClosingPeriod[0]).startOf("day")) &&
|
||||
dayjs(value).isSameOrBefore(dayjs(bodyshop.accountingconfig.ClosingPeriod[1]).endOf("day"))
|
||||
) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(new Error(t("jobs.labels.closingperiod")));
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO} onlyFuture={!!bodyshop.cdk_dealerid} />
|
||||
</Form.Item>
|
||||
{!jobRO && job.inproduction && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.removefromproduction")}
|
||||
name="removefromproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmin")}
|
||||
name="kmin"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmout")}
|
||||
name="kmout"
|
||||
dependencies={["kmin"]}
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
},
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("kmin") <= value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
/>
|
||||
|
||||
<Space wrap direction="vertical" style={{width: "100%"}}>
|
||||
<FormsFieldChanged form={form}/>
|
||||
{!job.actual_in && job.scheduled_in && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_in_inferred")}
|
||||
/>
|
||||
)}
|
||||
{!job.actual_completion && job.scheduled_completion && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_completion_inferred")}
|
||||
/>
|
||||
)}
|
||||
{!job.actual_delivery && job.scheduled_delivery && (
|
||||
<Alert
|
||||
type="warning"
|
||||
message={t("jobs.labels.actual_delivery_inferred")}
|
||||
/>
|
||||
)}
|
||||
</Space>
|
||||
<LayoutFormRow>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_in")}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
name="actual_in"
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
return (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_completion")}
|
||||
name="actual_completion"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
return Promise.reject(new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin")));
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.dms_allocation")}
|
||||
name="dms_allocation"
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<Input disabled />
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<>
|
||||
<Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col lg={8} md={24}>
|
||||
<Form.List
|
||||
name={["qb_multiple_payers"]}
|
||||
rules={[
|
||||
({ getFieldValue }) => ({
|
||||
validator(_, value) {
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100)
|
||||
})
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.actual_delivery")}
|
||||
name="actual_delivery"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<DateTimePicker disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.date_invoiced")}
|
||||
name="date_invoiced"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (!bodyshop.cdk_dealerid) return Promise.resolve();
|
||||
if (!value || dayjs(value).isSameOrAfter(dayjs(), "day")) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.dms.invoicedatefuture"))
|
||||
);
|
||||
},
|
||||
}),
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (
|
||||
ClosingPeriod.treatment === "on" &&
|
||||
bodyshop.accountingconfig.ClosingPeriod
|
||||
) {
|
||||
if (
|
||||
dayjs(value).isSameOrAfter(
|
||||
dayjs(
|
||||
bodyshop.accountingconfig.ClosingPeriod[0]
|
||||
).startOf("day")
|
||||
) &&
|
||||
dayjs(value).isSameOrBefore(
|
||||
dayjs(
|
||||
bodyshop.accountingconfig.ClosingPeriod[1]
|
||||
).endOf("day")
|
||||
)
|
||||
) {
|
||||
return Promise.resolve();
|
||||
} else {
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.closingperiod"))
|
||||
);
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve();
|
||||
}
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<DateTimePicker
|
||||
disabled={jobRO}
|
||||
onlyFuture={!!bodyshop.cdk_dealerid}
|
||||
/>
|
||||
</Form.Item>
|
||||
{!jobRO && job.inproduction && (
|
||||
<Form.Item
|
||||
label={t("jobs.actions.removefromproduction")}
|
||||
name="removefromproduction"
|
||||
valuePropName="checked"
|
||||
>
|
||||
<Switch/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmin")}
|
||||
name="kmin"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.kmout")}
|
||||
name="kmout"
|
||||
dependencies={["kmin"]}
|
||||
hasFeedback
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
if (!value || getFieldValue("kmin") <= value) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
new Error(t("jobs.labels.dms.kmoutnotgreaterthankmin"))
|
||||
);
|
||||
},
|
||||
}),
|
||||
]}
|
||||
>
|
||||
<InputNumber precision={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
)}
|
||||
{(bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) && (
|
||||
<Form.Item
|
||||
label={t("jobs.fields.dms_allocation")}
|
||||
name="dms_allocation"
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Input disabled/>
|
||||
</Form.Item>
|
||||
)}
|
||||
</LayoutFormRow>
|
||||
|
||||
{Qb_Multi_Ar.treatment === "on" && (
|
||||
<><Divider>{t("jobs.labels.multipayers")}</Divider>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col lg={8} md={24}>
|
||||
<Form.List
|
||||
name={["qb_multiple_payers"]}
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
|
||||
: Dinero();
|
||||
return discrep.getAmount() >= 0
|
||||
? Promise.resolve()
|
||||
: Promise.reject(new Error(t("jobs.labels.additionalpayeroverallocation")));
|
||||
}
|
||||
})
|
||||
]}
|
||||
>
|
||||
{(fields, { add, remove }) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<Space>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.name")}
|
||||
key={`${index}name`}
|
||||
name={[field.name, "name"]}
|
||||
rules={[
|
||||
({getFieldValue}) => ({
|
||||
validator(_, value) {
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100),
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(
|
||||
totalAllocated
|
||||
)
|
||||
: Dinero();
|
||||
return discrep.getAmount() >= 0
|
||||
? Promise.resolve()
|
||||
: Promise.reject(
|
||||
new Error(
|
||||
t("jobs.labels.additionalpayeroverallocation")
|
||||
)
|
||||
);
|
||||
},
|
||||
}),
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
{(fields, {add, remove}) => {
|
||||
return (
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<Form.Item key={field.key}>
|
||||
<Space>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.name")}
|
||||
key={`${index}name`}
|
||||
name={[field.name, "name"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<Select
|
||||
style={{minWidth: "12rem"}}
|
||||
disabled={jobRO}
|
||||
>
|
||||
{bodyshop.md_ins_cos.map((s) => (
|
||||
<Select.Option key={s.name} value={s.name}>
|
||||
{s.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
>
|
||||
<Select style={{ minWidth: "12rem" }} disabled={jobRO}>
|
||||
{bodyshop.md_ins_cos.map((s) => (
|
||||
<Select.Option key={s.name} value={s.name}>
|
||||
{s.name}
|
||||
</Select.Option>
|
||||
))}
|
||||
</Select>
|
||||
</Form.Item>
|
||||
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.amount")}
|
||||
key={`${index}amount`}
|
||||
name={[field.name, "amount"]}
|
||||
rules={[
|
||||
{
|
||||
required: true,
|
||||
},
|
||||
]}
|
||||
>
|
||||
<CurrencyInput min={0} disabled={jobRO}/>
|
||||
</Form.Item>
|
||||
<Form.Item
|
||||
label={t("jobs.fields.qb_multiple_payers.amount")}
|
||||
key={`${index}amount`}
|
||||
name={[field.name, "amount"]}
|
||||
rules={[
|
||||
{
|
||||
required: true
|
||||
}
|
||||
]}
|
||||
>
|
||||
<CurrencyInput min={0} disabled={jobRO} />
|
||||
</Form.Item>
|
||||
|
||||
<DeleteFilled
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
if(!jobRO){
|
||||
remove(field.name);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{width: "100%"}}
|
||||
>
|
||||
{t("jobs.actions.dms.addpayer")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
<DeleteFilled
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
if (!jobRO) {
|
||||
remove(field.name);
|
||||
}
|
||||
}}
|
||||
</Form.List>
|
||||
</Col>
|
||||
<Col lg={16} md={24}>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
//Perform Calculation to determine discrepancy.
|
||||
let totalAllocated = Dinero();
|
||||
/>
|
||||
</Space>
|
||||
</Form.Item>
|
||||
))}
|
||||
<Form.Item>
|
||||
<Button
|
||||
disabled={jobRO}
|
||||
onClick={() => {
|
||||
add();
|
||||
}}
|
||||
style={{ width: "100%" }}
|
||||
>
|
||||
{t("jobs.actions.dms.addpayer")}
|
||||
</Button>
|
||||
</Form.Item>
|
||||
</div>
|
||||
);
|
||||
}}
|
||||
</Form.List>
|
||||
</Col>
|
||||
<Col lg={16} md={24}>
|
||||
<Form.Item shouldUpdate>
|
||||
{() => {
|
||||
//Perform Calculation to determine discrepancy.
|
||||
let totalAllocated = Dinero();
|
||||
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100),
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(
|
||||
totalAllocated
|
||||
)
|
||||
: Dinero();
|
||||
return (
|
||||
<Space size="large" wrap align="center">
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_cust_payable")}
|
||||
value={(job.job_totals
|
||||
? Dinero(job.job_totals.totals.custPayable)
|
||||
: Dinero()
|
||||
).toFormat()}
|
||||
/>
|
||||
<Divider type="vertical"/>
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_repairs")}
|
||||
value={(job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs)
|
||||
: Dinero()
|
||||
).toFormat()}
|
||||
/>
|
||||
<Typography.Title>-</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.dms.totalallocated")}
|
||||
value={totalAllocated.toFormat()}
|
||||
/>
|
||||
<Typography.Title>=</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.pimraryamountpayable")}
|
||||
valueStyle={{
|
||||
color: discrep.getAmount() > 0 ? "green" : "red",
|
||||
}}
|
||||
value={discrep.toFormat()}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
<Divider/>
|
||||
<JobsCloseLines job={job}/>
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
const payers = form.getFieldValue("qb_multiple_payers");
|
||||
payers &&
|
||||
payers.forEach((payer) => {
|
||||
totalAllocated = totalAllocated.add(
|
||||
Dinero({
|
||||
amount: Math.round((payer?.amount || 0) * 100)
|
||||
})
|
||||
);
|
||||
});
|
||||
const discrep = job.job_totals
|
||||
? Dinero(job.job_totals.totals.total_repairs).subtract(totalAllocated)
|
||||
: Dinero();
|
||||
return (
|
||||
<Space size="large" wrap align="center">
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_cust_payable")}
|
||||
value={(job.job_totals ? Dinero(job.job_totals.totals.custPayable) : Dinero()).toFormat()}
|
||||
/>
|
||||
<Divider type="vertical" />
|
||||
<Statistic
|
||||
title={t("jobs.labels.total_repairs")}
|
||||
value={(job.job_totals ? Dinero(job.job_totals.totals.total_repairs) : Dinero()).toFormat()}
|
||||
/>
|
||||
<Typography.Title>-</Typography.Title>
|
||||
<Statistic title={t("jobs.labels.dms.totalallocated")} value={totalAllocated.toFormat()} />
|
||||
<Typography.Title>=</Typography.Title>
|
||||
<Statistic
|
||||
title={t("jobs.labels.pimraryamountpayable")}
|
||||
valueStyle={{
|
||||
color: discrep.getAmount() > 0 ? "green" : "red"
|
||||
}}
|
||||
value={discrep.toFormat()}
|
||||
/>
|
||||
</Space>
|
||||
);
|
||||
}}
|
||||
</Form.Item>
|
||||
</Col>
|
||||
</Row>
|
||||
</>
|
||||
)}
|
||||
<Divider />
|
||||
<JobsCloseLines job={job} />
|
||||
</Form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsCloseComponent);
|
||||
|
||||
@@ -1,87 +1,82 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Result} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Result } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobCalculateTotals from "../../components/job-calculate-totals/job-calculate-totals.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_JOB_CLOSE_DETAILS} from "../../graphql/jobs.queries";
|
||||
import {setBreadcrumbs, setJobReadOnly, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { QUERY_JOB_CLOSE_DETAILS } from "../../graphql/jobs.queries";
|
||||
import { setBreadcrumbs, setJobReadOnly, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import IsJobReadOnly from "../../utils/jobReadOnly";
|
||||
import JobsCloseComponent from "./jobs-close.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool))
|
||||
});
|
||||
|
||||
export function JobsCloseContainer({
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
setJobReadOnly,
|
||||
}) {
|
||||
const {jobId} = useParams();
|
||||
const {loading, error, data} = useQuery(QUERY_JOB_CLOSE_DETAILS, {
|
||||
variables: {id: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function JobsCloseContainer({ setBreadcrumbs, setSelectedHeader, setJobReadOnly }) {
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(QUERY_JOB_CLOSE_DETAILS, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
}
|
||||
}, [data, setJobReadOnly]);
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-close", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
}
|
||||
}, [data, setJobReadOnly]);
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = t("titles.jobs-close", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
number: data ? data.jobs_by_pk && data.jobs_by_pk.ro_number : null,
|
||||
});
|
||||
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
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 : null,
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/close`,
|
||||
label: t("titles.bc.jobs-close"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, setSelectedHeader]);
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/`,
|
||||
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 : null
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/close`,
|
||||
label: t("titles.bc.jobs-close")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, jobId, data, setSelectedHeader]);
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!!!data.jobs_by_pk) return <NotFound/>;
|
||||
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.job_totals)
|
||||
return (
|
||||
<Result
|
||||
title={t("jobs.errors.nofinancial")}
|
||||
extra={<JobCalculateTotals job={data.jobs_by_pk}/>}
|
||||
/>
|
||||
);
|
||||
if (!data.jobs_by_pk.job_totals)
|
||||
return <Result title={t("jobs.errors.nofinancial")} extra={<JobCalculateTotals job={data.jobs_by_pk} />} />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:close">
|
||||
<div>
|
||||
<JobsCloseComponent job={data ? data.jobs_by_pk : {}}/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:close">
|
||||
<div>
|
||||
<JobsCloseComponent job={data ? data.jobs_by_pk : {}} />
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(JobsCloseContainer);
|
||||
|
||||
@@ -1,168 +1,167 @@
|
||||
import {Button, Result, Space, Steps} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
import { Button, Result, Space, Steps } from "antd";
|
||||
import { PageHeader } from "@ant-design/pro-layout";
|
||||
|
||||
import React, {useContext, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {Link} from "react-router-dom";
|
||||
import React, { useContext, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobsCreateJobsInfo from "../../components/jobs-create-jobs-info/jobs-create-jobs-info.component";
|
||||
import JobsCreateOwnerInfoContainer from "../../components/jobs-create-owner-info/jobs-create-owner-info.container";
|
||||
import JobsCreateVehicleInfoContainer
|
||||
from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
|
||||
import JobsCreateVehicleInfoContainer from "../../components/jobs-create-vehicle-info/jobs-create-vehicle-info.container";
|
||||
import JobCreateContext from "../../pages/jobs-create/jobs-create.context";
|
||||
import FormsFieldChanged from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
||||
|
||||
export default function JobsCreateComponent({form}) {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
const [state] = useContext(JobCreateContext);
|
||||
export default function JobsCreateComponent({ form }) {
|
||||
const [pageIndex, setPageIndex] = useState(0);
|
||||
const [errorMessage, setErrorMessage] = useState(null);
|
||||
const [state] = useContext(JobCreateContext);
|
||||
|
||||
const {t} = useTranslation();
|
||||
const steps = [
|
||||
{
|
||||
title: t("jobs.labels.create.vehicleinfo"),
|
||||
content: <JobsCreateVehicleInfoContainer form={form}/>,
|
||||
validation:
|
||||
!!state.vehicle.new ||
|
||||
!!state.vehicle.selectedid ||
|
||||
!!state.vehicle.none,
|
||||
error: t("vehicles.errors.selectexistingornew"),
|
||||
},
|
||||
{
|
||||
title: t("jobs.labels.create.ownerinfo"),
|
||||
content: <JobsCreateOwnerInfoContainer/>,
|
||||
validation: !!state.owner.new || !!state.owner.selectedid,
|
||||
error: t("owners.errors.selectexistingornew"),
|
||||
},
|
||||
{
|
||||
title: t("jobs.labels.create.jobinfo"),
|
||||
content: <JobsCreateJobsInfo form={form} selected={pageIndex === 2}/>,
|
||||
},
|
||||
];
|
||||
const { t } = useTranslation();
|
||||
const steps = [
|
||||
{
|
||||
title: t("jobs.labels.create.vehicleinfo"),
|
||||
content: <JobsCreateVehicleInfoContainer form={form} />,
|
||||
validation: !!state.vehicle.new || !!state.vehicle.selectedid || !!state.vehicle.none,
|
||||
error: t("vehicles.errors.selectexistingornew")
|
||||
},
|
||||
{
|
||||
title: t("jobs.labels.create.ownerinfo"),
|
||||
content: <JobsCreateOwnerInfoContainer />,
|
||||
validation: !!state.owner.new || !!state.owner.selectedid,
|
||||
error: t("owners.errors.selectexistingornew")
|
||||
},
|
||||
{
|
||||
title: t("jobs.labels.create.jobinfo"),
|
||||
content: <JobsCreateJobsInfo form={form} selected={pageIndex === 2} />
|
||||
}
|
||||
];
|
||||
|
||||
const next = () => {
|
||||
setPageIndex(pageIndex + 1);
|
||||
console.log("NExt")
|
||||
};
|
||||
const prev = () => {
|
||||
setPageIndex(pageIndex - 1);
|
||||
};
|
||||
const {Step} = Steps;
|
||||
|
||||
const ProgressButtons = ({top}) => {
|
||||
return (
|
||||
<PageHeader
|
||||
extra={
|
||||
<Space wrap>
|
||||
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
|
||||
{pageIndex < steps.length - 1 && (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
next();
|
||||
// form
|
||||
// .validateFields()
|
||||
// .then((r) => {
|
||||
// if (steps[pageIndex].validation) {
|
||||
// setErrorMessage(null);
|
||||
// next();
|
||||
// } else {
|
||||
// setErrorMessage(steps[pageIndex].error);
|
||||
// }
|
||||
// })
|
||||
// .catch((error) => console.log("error", error));
|
||||
}}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
{pageIndex === steps.length - 1 && (
|
||||
<Button type="primary" onClick={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((r) => {
|
||||
|
||||
})
|
||||
.catch((error) => console.log("error", error));
|
||||
form.submit()}}>
|
||||
Done
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
{top && (
|
||||
<Steps current={pageIndex}>
|
||||
{steps.map((item, idx) => (
|
||||
<Step
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
fontWeight: idx === pageIndex && "bolder",
|
||||
}}
|
||||
onClick={() => { setPageIndex(idx);
|
||||
// form
|
||||
// .validateFields()
|
||||
// .then((r) => {
|
||||
// if (steps[pageIndex].validation) {
|
||||
// setErrorMessage(null);
|
||||
// setPageIndex(idx);
|
||||
// } else {
|
||||
// setErrorMessage(steps[pageIndex].error);
|
||||
// }
|
||||
// })
|
||||
// .catch((error) => console.log("error", error));
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Steps>
|
||||
)}
|
||||
</PageHeader>
|
||||
);
|
||||
};
|
||||
const next = () => {
|
||||
setPageIndex(pageIndex + 1);
|
||||
console.log("NExt");
|
||||
};
|
||||
const prev = () => {
|
||||
setPageIndex(pageIndex - 1);
|
||||
};
|
||||
const { Step } = Steps;
|
||||
|
||||
const ProgressButtons = ({ top }) => {
|
||||
return (
|
||||
<div>
|
||||
{state.created ? (
|
||||
<div>
|
||||
<Result
|
||||
status="success"
|
||||
title={t("jobs.successes.creatednoclick")}
|
||||
extra={[
|
||||
<Link to={`/manage/jobs/${state.newJobId}`} key="gotojob">
|
||||
<Button type="primary">{t("jobs.actions.gotojob")}</Button>
|
||||
</Link>,
|
||||
<Link to={`/manage/jobs/`} key="gotojoblist">
|
||||
<Button>{t("menus.header.activejobs")}</Button>
|
||||
</Link>,
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<ProgressButtons top/>
|
||||
<FormsFieldChanged form={form} />
|
||||
{errorMessage ? (
|
||||
<div>
|
||||
<AlertComponent message={errorMessage} type="error"/>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{steps.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
style={{
|
||||
display: idx === pageIndex ? "" : "none",
|
||||
margin: "1rem",
|
||||
}}
|
||||
>
|
||||
{item.content}
|
||||
</div>
|
||||
))}
|
||||
<ProgressButtons/>
|
||||
</div>
|
||||
<PageHeader
|
||||
extra={
|
||||
<Space wrap>
|
||||
{pageIndex > 0 && <Button onClick={() => prev()}>Previous</Button>}
|
||||
{pageIndex < steps.length - 1 && (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
next();
|
||||
// form
|
||||
// .validateFields()
|
||||
// .then((r) => {
|
||||
// if (steps[pageIndex].validation) {
|
||||
// setErrorMessage(null);
|
||||
// next();
|
||||
// } else {
|
||||
// setErrorMessage(steps[pageIndex].error);
|
||||
// }
|
||||
// })
|
||||
// .catch((error) => console.log("error", error));
|
||||
}}
|
||||
>
|
||||
Next
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{pageIndex === steps.length - 1 && (
|
||||
<Button
|
||||
type="primary"
|
||||
onClick={() => {
|
||||
form
|
||||
.validateFields()
|
||||
.then((r) => {})
|
||||
.catch((error) => console.log("error", error));
|
||||
form.submit();
|
||||
}}
|
||||
>
|
||||
Done
|
||||
</Button>
|
||||
)}
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
{top && (
|
||||
<Steps current={pageIndex}>
|
||||
{steps.map((item, idx) => (
|
||||
<Step
|
||||
key={item.title}
|
||||
title={item.title}
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
fontWeight: idx === pageIndex && "bolder"
|
||||
}}
|
||||
onClick={() => {
|
||||
setPageIndex(idx);
|
||||
// form
|
||||
// .validateFields()
|
||||
// .then((r) => {
|
||||
// if (steps[pageIndex].validation) {
|
||||
// setErrorMessage(null);
|
||||
// setPageIndex(idx);
|
||||
// } else {
|
||||
// setErrorMessage(steps[pageIndex].error);
|
||||
// }
|
||||
// })
|
||||
// .catch((error) => console.log("error", error));
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</Steps>
|
||||
)}
|
||||
</PageHeader>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
{state.created ? (
|
||||
<div>
|
||||
<Result
|
||||
status="success"
|
||||
title={t("jobs.successes.creatednoclick")}
|
||||
extra={[
|
||||
<Link to={`/manage/jobs/${state.newJobId}`} key="gotojob">
|
||||
<Button type="primary">{t("jobs.actions.gotojob")}</Button>
|
||||
</Link>,
|
||||
<Link to={`/manage/jobs/`} key="gotojoblist">
|
||||
<Button>{t("menus.header.activejobs")}</Button>
|
||||
</Link>
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
<ProgressButtons top />
|
||||
<FormsFieldChanged form={form} />
|
||||
{errorMessage ? (
|
||||
<div>
|
||||
<AlertComponent message={errorMessage} type="error" />
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{steps.map((item, idx) => (
|
||||
<div
|
||||
key={idx}
|
||||
style={{
|
||||
display: idx === pageIndex ? "" : "none",
|
||||
margin: "1rem"
|
||||
}}
|
||||
>
|
||||
{item.content}
|
||||
</div>
|
||||
))}
|
||||
<ProgressButtons />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,289 +1,287 @@
|
||||
import {useLazyQuery, useMutation} from "@apollo/client";
|
||||
import {Form, notification} from "antd";
|
||||
import { useLazyQuery, useMutation } from "@apollo/client";
|
||||
import { Form, notification } from "antd";
|
||||
import _ from "lodash";
|
||||
import React, {useEffect, useState} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {INSERT_NEW_JOB} from "../../graphql/jobs.queries";
|
||||
import {QUERY_OWNER_FOR_JOB_CREATION} from "../../graphql/owners.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { INSERT_NEW_JOB } from "../../graphql/jobs.queries";
|
||||
import { QUERY_OWNER_FOR_JOB_CREATION } from "../../graphql/owners.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import JobsCreateComponent from "./jobs-create.component";
|
||||
import JobCreateContext from "./jobs-create.context";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
function JobsCreateContainer({bodyshop, setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
const contextState = useState({
|
||||
vehicle: {
|
||||
new: false,
|
||||
search: "",
|
||||
selectedid: null,
|
||||
vehicleObj: null,
|
||||
none: false,
|
||||
},
|
||||
owner: {new: false, search: "", selectedid: null},
|
||||
job: null,
|
||||
created: false,
|
||||
error: null,
|
||||
newJobId: null,
|
||||
newJobEstNum: null,
|
||||
function JobsCreateContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const contextState = useState({
|
||||
vehicle: {
|
||||
new: false,
|
||||
search: "",
|
||||
selectedid: null,
|
||||
vehicleObj: null,
|
||||
none: false
|
||||
},
|
||||
owner: { new: false, search: "", selectedid: null },
|
||||
job: null,
|
||||
created: false,
|
||||
error: null,
|
||||
newJobId: null,
|
||||
newJobEstNum: null
|
||||
});
|
||||
const [form] = Form.useForm();
|
||||
const [state, setState] = contextState;
|
||||
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
||||
const [loadOwner, RemoteOwnerData] = useLazyQuery(QUERY_OWNER_FOR_JOB_CREATION);
|
||||
|
||||
useEffect(() => {
|
||||
if (!!state.owner.selectedid) {
|
||||
loadOwner({
|
||||
variables: { id: state.owner.selectedid }
|
||||
});
|
||||
}
|
||||
}, [state.owner.selectedid, loadOwner]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-create", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
const [form] = Form.useForm();
|
||||
const [state, setState] = contextState;
|
||||
const [insertJob] = useMutation(INSERT_NEW_JOB);
|
||||
const [loadOwner, RemoteOwnerData] = useLazyQuery(
|
||||
QUERY_OWNER_FOR_JOB_CREATION
|
||||
setSelectedHeader("newjob");
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/available", label: t("titles.bc.availablejobs") },
|
||||
{
|
||||
link: "/manage/jobs/new",
|
||||
label: t("titles.bc.jobs-new")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
const runInsertJob = (job) => {
|
||||
insertJob({ variables: { job: job } })
|
||||
.then((resp) => {
|
||||
setState({
|
||||
...state,
|
||||
created: true,
|
||||
error: null,
|
||||
newJobId: resp.data.insert_jobs.returning[0].id
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.creating", { error: error })
|
||||
});
|
||||
setState({ ...state, error: error });
|
||||
});
|
||||
};
|
||||
|
||||
const handleFinish = (values) => {
|
||||
let job = Object.assign(
|
||||
{},
|
||||
values,
|
||||
{ date_open: new Date() },
|
||||
{ date_estimated: new Date() },
|
||||
{
|
||||
vehicle: state.vehicle.selectedid || state.vehicle.none ? null : values.vehicle,
|
||||
vehicleid: state.vehicle.selectedid || null
|
||||
},
|
||||
{
|
||||
owner: state.owner.selectedid ? null : values.owner,
|
||||
ownerid: state.owner.selectedid || null
|
||||
},
|
||||
{
|
||||
status: bodyshop.md_ro_statuses.default_imported || "Open*",
|
||||
shopid: bodyshop.id
|
||||
}
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!!state.owner.selectedid) {
|
||||
loadOwner({
|
||||
variables: {id: state.owner.selectedid},
|
||||
});
|
||||
}
|
||||
}, [state.owner.selectedid, loadOwner]);
|
||||
let ownerData;
|
||||
if (!!!job.ownerid) {
|
||||
ownerData = job.owner.data;
|
||||
ownerData.shopid = bodyshop.id;
|
||||
delete ownerData.allow_text_message;
|
||||
delete ownerData.preferred_contact;
|
||||
delete job.ownerid;
|
||||
} else {
|
||||
ownerData = _.cloneDeep(RemoteOwnerData.data.owners_by_pk);
|
||||
delete ownerData.id;
|
||||
delete ownerData.__typename;
|
||||
}
|
||||
if (!state.vehicle.none) {
|
||||
if (!!!job.vehicleid) {
|
||||
delete job.vehicleid;
|
||||
job.vehicle.data.shopid = bodyshop.id;
|
||||
job.plate_no = job.vehicle.data.plate_no;
|
||||
job.plate_st = job.vehicle.data.plate_st;
|
||||
job.v_vin = job.vehicle.data.v_vin;
|
||||
job.v_model_yr = job.vehicle.data.v_model_yr;
|
||||
job.v_model_desc = job.vehicle.data.v_model_desc;
|
||||
job.v_make_desc = job.vehicle.data.v_make_desc;
|
||||
job.v_color = job.vehicle.data.v_color;
|
||||
} else {
|
||||
job.plate_no = state.vehicle.vehicleObj.plate_no;
|
||||
job.plate_st = state.vehicle.vehicleObj.plate_st;
|
||||
job.v_vin = state.vehicle.vehicleObj.v_vin;
|
||||
job.v_model_yr = state.vehicle.vehicleObj.v_model_yr;
|
||||
job.v_model_desc = state.vehicle.vehicleObj.v_model_desc;
|
||||
job.v_make_desc = state.vehicle.vehicleObj.v_make_desc;
|
||||
job.v_color = state.vehicle.vehicleObj.v_color;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-create",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("newjob");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/available", label: t("titles.bc.availablejobs")},
|
||||
{
|
||||
link: "/manage/jobs/new",
|
||||
label: t("titles.bc.jobs-new"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
job = { ...job, ...ownerData };
|
||||
|
||||
const runInsertJob = (job) => {
|
||||
insertJob({variables: {job: job}})
|
||||
.then((resp) => {
|
||||
setState({
|
||||
...state,
|
||||
created: true,
|
||||
error: null,
|
||||
newJobId: resp.data.insert_jobs.returning[0].id,
|
||||
});
|
||||
if (job.owner === null) delete job.owner;
|
||||
if (job.vehicle === null) delete job.vehicle;
|
||||
|
||||
runInsertJob(job);
|
||||
};
|
||||
|
||||
return (
|
||||
<JobCreateContext.Provider value={contextState}>
|
||||
<RbacWrapper action="jobs:create">
|
||||
<Form
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
layout="vertical"
|
||||
autoComplete={"off"}
|
||||
initialValues={{
|
||||
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
|
||||
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
|
||||
...InstanceRenderManager({
|
||||
imex: {
|
||||
parts_tax_rates: {
|
||||
PAA: {
|
||||
prt_type: "PAA",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAC: {
|
||||
prt_type: "PAC",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAG: {
|
||||
prt_type: "PAG",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAL: {
|
||||
prt_type: "PAL",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAM: {
|
||||
prt_type: "PAM",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAN: {
|
||||
prt_type: "PAN",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAR: {
|
||||
prt_type: "PAR",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAS: {
|
||||
prt_type: "PAS",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PASL: {
|
||||
prt_type: "PASL",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAP: {
|
||||
prt_type: "PAP",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
},
|
||||
PAO: {
|
||||
prt_type: "PAO",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100
|
||||
}
|
||||
},
|
||||
rome: {
|
||||
cieca_pft: {
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty5
|
||||
},
|
||||
materials: bodyshop.md_responsibility_centers.cieca_pfm,
|
||||
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
|
||||
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.creating", {error: error}),
|
||||
});
|
||||
setState({...state, error: error});
|
||||
});
|
||||
};
|
||||
|
||||
const handleFinish = (values) => {
|
||||
let job = Object.assign(
|
||||
{},
|
||||
values,
|
||||
{date_open: new Date()},
|
||||
{date_estimated: new Date()},
|
||||
{
|
||||
vehicle:
|
||||
state.vehicle.selectedid || state.vehicle.none
|
||||
? null
|
||||
: values.vehicle,
|
||||
vehicleid: state.vehicle.selectedid || null,
|
||||
},
|
||||
{
|
||||
owner: state.owner.selectedid ? null : values.owner,
|
||||
ownerid: state.owner.selectedid || null,
|
||||
},
|
||||
{
|
||||
status: bodyshop.md_ro_statuses.default_imported || "Open*",
|
||||
shopid: bodyshop.id,
|
||||
}
|
||||
);
|
||||
|
||||
let ownerData;
|
||||
if (!!!job.ownerid) {
|
||||
ownerData = job.owner.data;
|
||||
ownerData.shopid = bodyshop.id;
|
||||
delete ownerData.allow_text_message;
|
||||
delete ownerData.preferred_contact;
|
||||
delete job.ownerid;
|
||||
} else {
|
||||
ownerData = _.cloneDeep(RemoteOwnerData.data.owners_by_pk);
|
||||
delete ownerData.id;
|
||||
delete ownerData.__typename;
|
||||
}
|
||||
if (!state.vehicle.none) {
|
||||
if (!!!job.vehicleid) {
|
||||
delete job.vehicleid;
|
||||
job.vehicle.data.shopid = bodyshop.id;
|
||||
job.plate_no = job.vehicle.data.plate_no;
|
||||
job.plate_st = job.vehicle.data.plate_st;
|
||||
job.v_vin = job.vehicle.data.v_vin;
|
||||
job.v_model_yr = job.vehicle.data.v_model_yr;
|
||||
job.v_model_desc = job.vehicle.data.v_model_desc;
|
||||
job.v_make_desc = job.vehicle.data.v_make_desc;
|
||||
job.v_color = job.vehicle.data.v_color;
|
||||
} else {
|
||||
job.plate_no = state.vehicle.vehicleObj.plate_no;
|
||||
job.plate_st = state.vehicle.vehicleObj.plate_st;
|
||||
job.v_vin = state.vehicle.vehicleObj.v_vin;
|
||||
job.v_model_yr = state.vehicle.vehicleObj.v_model_yr;
|
||||
job.v_model_desc = state.vehicle.vehicleObj.v_model_desc;
|
||||
job.v_make_desc = state.vehicle.vehicleObj.v_make_desc;
|
||||
job.v_color = state.vehicle.vehicleObj.v_color;
|
||||
}
|
||||
}
|
||||
|
||||
job = {...job, ...ownerData};
|
||||
|
||||
if (job.owner === null) delete job.owner;
|
||||
if (job.vehicle === null) delete job.vehicle;
|
||||
|
||||
runInsertJob(job);
|
||||
};
|
||||
|
||||
return (
|
||||
<JobCreateContext.Provider value={contextState}>
|
||||
<RbacWrapper action="jobs:create">
|
||||
<Form
|
||||
|
||||
form={form}
|
||||
onFinish={handleFinish}
|
||||
layout="vertical"
|
||||
autoComplete={"off"}
|
||||
initialValues={{
|
||||
tax_tow_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_str_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_paint_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_shop_mat_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_sub_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_lbr_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
tax_levies_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
federal_tax_rate: bodyshop.bill_tax_rates.federal_tax_rate / 100,
|
||||
state_tax_rate: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
local_tax_rate: bodyshop.bill_tax_rates.local_tax_rate / 100,
|
||||
...InstanceRenderManager({imex: {
|
||||
parts_tax_rates: {
|
||||
PAA: {
|
||||
prt_type: "PAA",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAC: {
|
||||
prt_type: "PAC",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAG: {
|
||||
prt_type: "PAG",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAL: {
|
||||
prt_type: "PAL",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAM: {
|
||||
prt_type: "PAM",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAN: {
|
||||
prt_type: "PAN",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAR: {
|
||||
prt_type: "PAR",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAS: {
|
||||
prt_type: "PAS",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PASL: {
|
||||
prt_type: "PASL",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAP: {
|
||||
prt_type: "PAP",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
PAO: {
|
||||
prt_type: "PAO",
|
||||
prt_discp: 0,
|
||||
prt_mktyp: false,
|
||||
prt_mkupp: 0,
|
||||
prt_tax_in: true,
|
||||
prt_tax_rt: bodyshop.bill_tax_rates.state_tax_rate / 100,
|
||||
},
|
||||
|
||||
},
|
||||
rome: {
|
||||
cieca_pft: {
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty1,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty2,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty3,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty4,
|
||||
...bodyshop.md_responsibility_centers.taxes.tax_ty5,
|
||||
},
|
||||
materials: bodyshop.md_responsibility_centers.cieca_pfm,
|
||||
cieca_pfl: bodyshop.md_responsibility_centers.cieca_pfl,
|
||||
parts_tax_rates: bodyshop.md_responsibility_centers.parts_tax_rates,
|
||||
}
|
||||
}})
|
||||
}}
|
||||
>
|
||||
<JobsCreateComponent form={form}/>
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
</JobCreateContext.Provider>
|
||||
);
|
||||
}}
|
||||
>
|
||||
<JobsCreateComponent form={form} />
|
||||
</Form>
|
||||
</RbacWrapper>
|
||||
</JobCreateContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsCreateContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsCreateContainer);
|
||||
|
||||
@@ -1,80 +1,75 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { 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 LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_DELIVER_CHECKLIST} from "../../graphql/bodyshop.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { QUERY_DELIVER_CHECKLIST } from "../../graphql/bodyshop.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import JobchecklistComponent from "../../components/job-checklist/job-checklist.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsDeliverContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const {jobId} = useParams();
|
||||
const {loading, error, data} = useQuery(QUERY_DELIVER_CHECKLIST, {
|
||||
variables: {shopId: bodyshop.id, jobId: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
export function JobsDeliverContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const { jobId } = useParams();
|
||||
const { loading, error, data } = useQuery(QUERY_DELIVER_CHECKLIST, {
|
||||
variables: { shopId: bodyshop.id, jobId: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-deliver", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("activejobs");
|
||||
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) || ""
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/deliver`,
|
||||
label: t("titles.bc.jobs-deliver")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-deliver",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("activejobs");
|
||||
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) || "",
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/deliver`,
|
||||
label: t("titles.bc.jobs-deliver"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (data && !!!data.bodyshops_by_pk.deliverchecklist)
|
||||
return (
|
||||
<AlertComponent message={t("deliver.errors.nochecklist")} type="error"/>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:deliver">
|
||||
<div>
|
||||
<JobchecklistComponent
|
||||
type="deliver"
|
||||
checklistConfig={
|
||||
(data && data.bodyshops_by_pk.deliverchecklist) || {}
|
||||
}
|
||||
job={data ? data.jobs_by_pk : {}}
|
||||
/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (data && !!!data.bodyshops_by_pk.deliverchecklist)
|
||||
return <AlertComponent message={t("deliver.errors.nochecklist")} type="error" />;
|
||||
return (
|
||||
<RbacWrapper action="jobs:deliver">
|
||||
<div>
|
||||
<JobchecklistComponent
|
||||
type="deliver"
|
||||
checklistConfig={(data && data.bodyshops_by_pk.deliverchecklist) || {}}
|
||||
job={data ? data.jobs_by_pk : {}}
|
||||
/>
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsDeliverContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsDeliverContainer);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import Icon, {
|
||||
BarsOutlined,
|
||||
CalendarFilled,
|
||||
DollarCircleOutlined,
|
||||
FileImageFilled,
|
||||
HistoryOutlined,
|
||||
PrinterFilled,
|
||||
SyncOutlined,
|
||||
ToolFilled,
|
||||
BarsOutlined,
|
||||
CalendarFilled,
|
||||
DollarCircleOutlined,
|
||||
FileImageFilled,
|
||||
HistoryOutlined,
|
||||
PrinterFilled,
|
||||
SyncOutlined,
|
||||
ToolFilled
|
||||
} from "@ant-design/icons";
|
||||
import {Button, Divider, Form, notification, Space, Tabs,} from "antd";
|
||||
import {Button, Divider, Form, notification, Space, Tabs} from "antd";
|
||||
import {PageHeader} from "@ant-design/pro-layout";
|
||||
|
||||
import Axios from "axios";
|
||||
@@ -20,29 +20,38 @@ import {FaHardHat, FaRegStickyNote, FaShieldAlt, FaTasks} from "react-icons/fa";
|
||||
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";
|
||||
import FormFieldsChanged
|
||||
from "../../components/form-fields-changed-alert/form-fields-changed-alert.component";
|
||||
import JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
|
||||
import JobsLinesContainer from "../../components/job-detail-lines/job-lines.container";
|
||||
import JobLifecycleComponent from "../../components/job-lifecycle/job-lifecycle.component";
|
||||
import JobLineUpsertModalContainer from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
|
||||
import JobReconciliationModal from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
|
||||
import JobLineUpsertModalContainer
|
||||
from "../../components/job-lines-upsert-modal/job-lines-upsert-modal.container";
|
||||
import JobReconciliationModal
|
||||
from "../../components/job-reconciliation-modal/job-reconciliation.modal.container";
|
||||
import JobSyncButton from "../../components/job-sync-button/job-sync-button.component";
|
||||
import JobsChangeStatus from "../../components/jobs-change-status/jobs-change-status.component";
|
||||
import JobsConvertButton from "../../components/jobs-convert-button/jobs-convert-button.component";
|
||||
import JobsDetailDatesComponent from "../../components/jobs-detail-dates/jobs-detail-dates.component";
|
||||
import JobsDetailDatesComponent
|
||||
from "../../components/jobs-detail-dates/jobs-detail-dates.component";
|
||||
import JobsDetailGeneral from "../../components/jobs-detail-general/jobs-detail-general.component";
|
||||
import JobsDetailHeaderActions from "../../components/jobs-detail-header-actions/jobs-detail-header-actions.component";
|
||||
import JobsDetailHeaderActions
|
||||
from "../../components/jobs-detail-header-actions/jobs-detail-header-actions.component";
|
||||
import JobsDetailHeader from "../../components/jobs-detail-header/jobs-detail-header.component";
|
||||
import JobsDetailLaborContainer from "../../components/jobs-detail-labor/jobs-detail-labor.container";
|
||||
import JobsDetailLaborContainer
|
||||
from "../../components/jobs-detail-labor/jobs-detail-labor.container";
|
||||
import JobsDetailPliContainer from "../../components/jobs-detail-pli/jobs-detail-pli.container";
|
||||
import JobsDetailRates from "../../components/jobs-detail-rates/jobs-detail-rates.component";
|
||||
import JobsDetailTotals from "../../components/jobs-detail-totals/jobs-detail-totals.component";
|
||||
import JobsDocumentsGalleryContainer from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
|
||||
import JobsDocumentsGalleryContainer
|
||||
from "../../components/jobs-documents-gallery/jobs-documents-gallery.container";
|
||||
import JobsDocumentsLocalGallery
|
||||
from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
import JobNotesContainer from "../../components/jobs-notes/jobs-notes.container";
|
||||
import NoteUpsertModalComponent from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||
import ScheduleJobModalContainer from "../../components/schedule-job-modal/schedule-job-modal.container";
|
||||
import NoteUpsertModalComponent
|
||||
from "../../components/note-upsert-modal/note-upsert-modal.container";
|
||||
import ScheduleJobModalContainer
|
||||
from "../../components/schedule-job-modal/schedule-job-modal.container";
|
||||
import {insertAuditTrail} from "../../redux/application/application.actions";
|
||||
import {selectJobReadOnly} from "../../redux/application/application.selectors";
|
||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
@@ -50,341 +59,342 @@ import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import AuditTrailMapping from "../../utils/AuditTrailMappings";
|
||||
import UndefinedToNull from "../../utils/undefinedtonull";
|
||||
import _ from "lodash";
|
||||
import JobProfileDataWarning from "../../components/job-profile-data-warning/job-profile-data-warning.component";
|
||||
import JobProfileDataWarning
|
||||
from "../../components/job-profile-data-warning/job-profile-data-warning.component";
|
||||
import {DateTimeFormat} from "../../utils/DateFormatter";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import {HasFeatureAccess} from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import TaskListContainer from "../../components/task-list/task-list.container.jsx";
|
||||
import {QUERY_JOB_TASKS_PAGINATED} from "../../graphql/tasks.queries.js";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly,
|
||||
bodyshop: selectBodyshop,
|
||||
jobRO: selectJobReadOnly
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setPrintCenterContext: (context) =>
|
||||
dispatch(setModalContext({context: context, modal: "printCenter"})),
|
||||
insertAuditTrail: ({jobid, operation, type}) =>
|
||||
dispatch(insertAuditTrail({jobid, operation, type })),
|
||||
setPrintCenterContext: (context) => dispatch(setModalContext({
|
||||
context: context,
|
||||
modal: "printCenter"
|
||||
})),
|
||||
insertAuditTrail: ({jobid, operation, type}) => dispatch(insertAuditTrail({
|
||||
jobid,
|
||||
operation,
|
||||
type
|
||||
}))
|
||||
});
|
||||
|
||||
export function JobsDetailPage({
|
||||
bodyshop,
|
||||
setPrintCenterContext,
|
||||
jobRO,
|
||||
job,
|
||||
mutationUpdateJob,
|
||||
handleSubmit,
|
||||
insertAuditTrail,
|
||||
refetch,
|
||||
bodyshop,
|
||||
setPrintCenterContext,
|
||||
jobRO,
|
||||
job,
|
||||
mutationUpdateJob,
|
||||
handleSubmit,
|
||||
insertAuditTrail,
|
||||
refetch
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const history = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const formItemLayout = {
|
||||
layout: "vertical",
|
||||
};
|
||||
const {t} = useTranslation();
|
||||
const [form] = Form.useForm();
|
||||
const history = useNavigate();
|
||||
const [loading, setLoading] = useState(false);
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const formItemLayout = {
|
||||
layout: "vertical"
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
//form.setFieldsValue(transormJobToForm(job));
|
||||
form.resetFields();
|
||||
}, [form, job]);
|
||||
useEffect(() => {
|
||||
//form.setFieldsValue(transormJobToForm(job));
|
||||
form.resetFields();
|
||||
}, [form, job]);
|
||||
|
||||
//useKeyboardSaveShortcut(form.submit);
|
||||
//useKeyboardSaveShortcut(form.submit);
|
||||
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
const handleFinish = async (values) => {
|
||||
setLoading(true);
|
||||
|
||||
const result = await mutationUpdateJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
...UndefinedToNull(values, [
|
||||
"alt_transport",
|
||||
"category",
|
||||
"referral_source",
|
||||
]),
|
||||
// The union and spread is required to keep values coming in from the estimating system that aren't displayed.
|
||||
parts_tax_rates: _.union(
|
||||
Object.keys(job.parts_tax_rates),
|
||||
Object.keys(values.parts_tax_rates || {})
|
||||
).reduce((acc, val) => {
|
||||
acc[val] = {
|
||||
...job.parts_tax_rates[val],
|
||||
...values.parts_tax_rates?.[val], //TODO:AIO Verify that these still save for Rome Online with this null coalescing.
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
materials: _.union(
|
||||
Object.keys(job.materials),
|
||||
Object.keys(values.materials|| {})
|
||||
).reduce((acc, val) => {
|
||||
acc[val] = {
|
||||
...job.materials[val],
|
||||
...values.materials?.[val],
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
cieca_pfl: _.union(
|
||||
Object.keys(job.cieca_pfl),
|
||||
Object.keys(values.cieca_pfl|| {})
|
||||
).reduce((acc, val) => {
|
||||
acc[val] = {
|
||||
...job.cieca_pfl[val],
|
||||
...values.cieca_pfl?.[val],
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
cieca_pfo: {...job.cieca_pfo, ...values.cieca_pfo},
|
||||
},
|
||||
const result = await mutationUpdateJob({
|
||||
variables: {
|
||||
jobId: job.id,
|
||||
job: {
|
||||
...UndefinedToNull(values, ["alt_transport", "category", "referral_source"]),
|
||||
// The union and spread is required to keep values coming in from the estimating system that aren't displayed.
|
||||
parts_tax_rates: _.union(Object.keys(job.parts_tax_rates), Object.keys(values.parts_tax_rates || {})).reduce(
|
||||
(acc, val) => {
|
||||
acc[val] = {
|
||||
...job.parts_tax_rates[val],
|
||||
...values.parts_tax_rates?.[val] //TODO:AIO Verify that these still save for Rome Online with this null coalescing.
|
||||
};
|
||||
return acc;
|
||||
},
|
||||
});
|
||||
try {
|
||||
const newTotals = await Axios.post("/job/totalsssu", {
|
||||
id: job.id,
|
||||
});
|
||||
|
||||
if (newTotals.status !== 200 || result.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc"),
|
||||
});
|
||||
} else {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.savetitle"),
|
||||
});
|
||||
const changedAuditFields = form.getFieldsValue(
|
||||
[
|
||||
"scheduled_in",
|
||||
"actual_in",
|
||||
"scheduled_completion",
|
||||
"actual_completion",
|
||||
"scheduled_delivery",
|
||||
"actual_delivery",
|
||||
"date_invoiced",
|
||||
"ins_co_nm",
|
||||
"ded_amt",
|
||||
"ded_status",
|
||||
"date_exported",
|
||||
"special_coverage_policy",
|
||||
"ca_gst_registrant",
|
||||
"ca_bc_pvrt",
|
||||
"scheduled_in",
|
||||
"rate_la1",
|
||||
"rate_la2",
|
||||
"rate_la3",
|
||||
"rate_la4",
|
||||
"rate_laa",
|
||||
"rate_lab",
|
||||
"rate_lad",
|
||||
"rate_lae",
|
||||
"rate_laf",
|
||||
"rate_lag",
|
||||
"rate_lam",
|
||||
"rate_lar",
|
||||
"rate_las",
|
||||
"rate_lau",
|
||||
"rate_ma2s",
|
||||
"rate_ma2t",
|
||||
"rate_ma3s",
|
||||
"rate_mabl",
|
||||
"rate_macs",
|
||||
"rate_mapa",
|
||||
"rate_mahw",
|
||||
"rate_mash",
|
||||
"rate_matd",
|
||||
],
|
||||
(meta) => meta && meta.touched
|
||||
);
|
||||
|
||||
Object.keys(changedAuditFields).forEach((key) => {
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobfieldchange(
|
||||
key,
|
||||
changedAuditFields[key] instanceof dayjs
|
||||
? DateTimeFormat(changedAuditFields[key])
|
||||
: changedAuditFields[key]
|
||||
),
|
||||
type: "jobfieldchange",});
|
||||
});
|
||||
|
||||
await refetch();
|
||||
form.setFieldsValue(transformJobToForm(job));
|
||||
form.resetFields();
|
||||
}
|
||||
} catch (error) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc"),
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
{}
|
||||
),
|
||||
materials: _.union(Object.keys(job.materials), Object.keys(values.materials || {})).reduce((acc, val) => {
|
||||
acc[val] = {
|
||||
...job.materials[val],
|
||||
...values.materials?.[val]
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
cieca_pfl: _.union(Object.keys(job.cieca_pfl), Object.keys(values.cieca_pfl || {})).reduce((acc, val) => {
|
||||
acc[val] = {
|
||||
...job.cieca_pfl[val],
|
||||
...values.cieca_pfl?.[val]
|
||||
};
|
||||
return acc;
|
||||
}, {}),
|
||||
cieca_pfo: {...job.cieca_pfo, ...values.cieca_pfo}
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
try {
|
||||
const newTotals = await Axios.post("/job/totalsssu", {
|
||||
id: job.id
|
||||
});
|
||||
|
||||
const menuExtra = (
|
||||
<Space wrap>
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetch();
|
||||
}}
|
||||
key="refresh"
|
||||
>
|
||||
<SyncOutlined/>
|
||||
{t("general.labels.refresh")}
|
||||
</Button>
|
||||
<JobsChangeStatus job={job}/>
|
||||
<JobSyncButton job={job}/>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setPrintCenterContext({
|
||||
actions: {refetch: refetch},
|
||||
context: {
|
||||
id: job.id,
|
||||
job: job,
|
||||
type: "job",
|
||||
},
|
||||
});
|
||||
}}
|
||||
key="printing"
|
||||
>
|
||||
<PrinterFilled/>
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>
|
||||
<JobsConvertButton
|
||||
job={job}
|
||||
refetch={refetch}
|
||||
parentFormIsFieldsTouched={form.isFieldsTouched}
|
||||
/>
|
||||
<JobsDetailHeaderActions key="actions" job={job} refetch={refetch}/>
|
||||
<Button
|
||||
type="primary"
|
||||
loading={loading}
|
||||
disabled={jobRO}
|
||||
onClick={() => form.submit()}
|
||||
>
|
||||
{t("general.actions.save")}
|
||||
</Button>
|
||||
</Space>
|
||||
);
|
||||
if (newTotals.status !== 200 || result.errors) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc")
|
||||
});
|
||||
} else {
|
||||
notification["success"]({
|
||||
message: t("jobs.successes.savetitle")
|
||||
});
|
||||
const changedAuditFields = form.getFieldsValue(
|
||||
[
|
||||
"scheduled_in",
|
||||
"actual_in",
|
||||
"scheduled_completion",
|
||||
"actual_completion",
|
||||
"scheduled_delivery",
|
||||
"actual_delivery",
|
||||
"date_invoiced",
|
||||
"ins_co_nm",
|
||||
"ded_amt",
|
||||
"ded_status",
|
||||
"date_exported",
|
||||
"special_coverage_policy",
|
||||
"ca_gst_registrant",
|
||||
"ca_bc_pvrt",
|
||||
"scheduled_in",
|
||||
"rate_la1",
|
||||
"rate_la2",
|
||||
"rate_la3",
|
||||
"rate_la4",
|
||||
"rate_laa",
|
||||
"rate_lab",
|
||||
"rate_lad",
|
||||
"rate_lae",
|
||||
"rate_laf",
|
||||
"rate_lag",
|
||||
"rate_lam",
|
||||
"rate_lar",
|
||||
"rate_las",
|
||||
"rate_lau",
|
||||
"rate_ma2s",
|
||||
"rate_ma2t",
|
||||
"rate_ma3s",
|
||||
"rate_mabl",
|
||||
"rate_macs",
|
||||
"rate_mapa",
|
||||
"rate_mahw",
|
||||
"rate_mash",
|
||||
"rate_matd"
|
||||
],
|
||||
(meta) => meta && meta.touched
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ScheduleJobModalContainer/>
|
||||
<JobReconciliationModal/>
|
||||
<JobLineUpsertModalContainer/>
|
||||
<NoteUpsertModalComponent/>
|
||||
<Form
|
||||
form={form}
|
||||
name="JobDetailForm"
|
||||
onFinish={handleFinish}
|
||||
{...formItemLayout}
|
||||
autoComplete={"off"}
|
||||
initialValues={transformJobToForm(job)}
|
||||
>
|
||||
<PageHeader
|
||||
// onBack={() => window.history.back()}
|
||||
title={job.ro_number || t("general.labels.na")}
|
||||
extra={menuExtra}
|
||||
/>
|
||||
<JobsDetailHeader job={job}/>
|
||||
<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: "general",
|
||||
icon: <Icon component={FaShieldAlt}/>,
|
||||
label: t("menus.jobsdetail.general"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailGeneral job={job} form={form}/>,
|
||||
},
|
||||
{
|
||||
key: "repairdata",
|
||||
icon: <BarsOutlined/>,
|
||||
label: t("menus.jobsdetail.repairdata"),
|
||||
forceRender: true,
|
||||
children: (
|
||||
<JobsLinesContainer
|
||||
job={job}
|
||||
joblines={job.joblines}
|
||||
refetch={refetch}
|
||||
form={form}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
key: "rates",
|
||||
icon: <DollarCircleOutlined/>,
|
||||
label: t("menus.jobsdetail.rates"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailRates job={job} form={form}/>,
|
||||
},
|
||||
{
|
||||
key: "totals",
|
||||
icon: <DollarCircleOutlined/>,
|
||||
label: t("menus.jobsdetail.totals"),
|
||||
children: <JobsDetailTotals job={job} refetch={refetch}/>,
|
||||
},
|
||||
{
|
||||
key: "partssublet",
|
||||
icon: <ToolFilled/>,
|
||||
label: HasFeatureAccess({featureName: "bills", bodyshop}) ? t("menus.jobsdetail.partssublet") : t("menus.jobsdetail.parts"),
|
||||
children: <JobsDetailPliContainer job={job}/>,
|
||||
},
|
||||
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'timetickets', bodyshop }) }) ? [ {
|
||||
key: "labor",
|
||||
icon: <Icon component={FaHardHat}/>,
|
||||
label: t("menus.jobsdetail.labor"),
|
||||
children: <JobsDetailLaborContainer job={job} jobId={job.id}/>,
|
||||
},]: [],
|
||||
{
|
||||
key: 'lifecycle',
|
||||
icon: <BarsOutlined/>,
|
||||
label: t("menus.jobsdetail.lifecycle"),
|
||||
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>
|
||||
},
|
||||
{
|
||||
key: "dates",
|
||||
icon: <CalendarFilled/>,
|
||||
label: t("menus.jobsdetail.dates"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailDatesComponent job={job}/>,
|
||||
},
|
||||
...InstanceRenderManager({ imex: true, rome: true, promanager: HasFeatureAccess({ featureName: 'media', bodyshop }) }) ? [ {
|
||||
key: "documents",
|
||||
icon: <FileImageFilled/>,
|
||||
label: t("jobs.labels.documents"),
|
||||
children: bodyshop.uselocalmediaserver ? (
|
||||
<JobsDocumentsLocalGallery job={job}/>
|
||||
) : (
|
||||
<JobsDocumentsGalleryContainer jobId={job.id}/>
|
||||
),
|
||||
},]:[],
|
||||
{
|
||||
key: "notes",
|
||||
icon: <Icon component={FaRegStickyNote}/>,
|
||||
label: t("jobs.labels.notes"),
|
||||
children: <JobNotesContainer jobId={job.id}/>,
|
||||
},
|
||||
{
|
||||
key: "audit",
|
||||
icon: <HistoryOutlined/>,
|
||||
label: t("jobs.labels.audit"),
|
||||
children: <JobAuditTrail jobId={job.id}/>,
|
||||
},
|
||||
{
|
||||
key: 'tasks',
|
||||
icon: <FaTasks/>,
|
||||
label: t("menus.jobsdetail.tasks"),
|
||||
children: <TaskListContainer bodyshop={bodyshop} relationshipType={'jobid'} relationshipId={job.id} query={QUERY_JOB_TASKS_PAGINATED} titleTranslation='tasks.titles.job_tasks'/>
|
||||
},
|
||||
]}
|
||||
Object.keys(changedAuditFields).forEach((key) => {
|
||||
insertAuditTrail({
|
||||
jobid: job.id,
|
||||
operation: AuditTrailMapping.jobfieldchange(
|
||||
key,
|
||||
changedAuditFields[key] instanceof dayjs
|
||||
? DateTimeFormat(changedAuditFields[key])
|
||||
: changedAuditFields[key]
|
||||
),
|
||||
type: "jobfieldchange"
|
||||
});
|
||||
});
|
||||
|
||||
await refetch();
|
||||
form.setFieldsValue(transformJobToForm(job));
|
||||
form.resetFields();
|
||||
}
|
||||
} catch (error) {
|
||||
notification["error"]({
|
||||
message: t("jobs.errors.totalscalc")
|
||||
});
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const menuExtra = (
|
||||
<Space wrap>
|
||||
<Button
|
||||
onClick={() => {
|
||||
refetch();
|
||||
}}
|
||||
key="refresh"
|
||||
>
|
||||
<SyncOutlined/>
|
||||
{t("general.labels.refresh")}
|
||||
</Button>
|
||||
<JobsChangeStatus job={job}/>
|
||||
<JobSyncButton job={job}/>
|
||||
<Button
|
||||
onClick={() => {
|
||||
setPrintCenterContext({
|
||||
actions: {refetch: refetch},
|
||||
context: {
|
||||
id: job.id,
|
||||
job: job,
|
||||
type: "job"
|
||||
}
|
||||
});
|
||||
}}
|
||||
key="printing"
|
||||
>
|
||||
<PrinterFilled/>
|
||||
{t("jobs.actions.printCenter")}
|
||||
</Button>
|
||||
<JobsConvertButton job={job} refetch={refetch}
|
||||
parentFormIsFieldsTouched={form.isFieldsTouched}/>
|
||||
<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>
|
||||
<ScheduleJobModalContainer/>
|
||||
<JobReconciliationModal/>
|
||||
<JobLineUpsertModalContainer/>
|
||||
<NoteUpsertModalComponent/>
|
||||
<Form
|
||||
form={form}
|
||||
name="JobDetailForm"
|
||||
onFinish={handleFinish}
|
||||
{...formItemLayout}
|
||||
autoComplete={"off"}
|
||||
initialValues={transformJobToForm(job)}
|
||||
>
|
||||
<PageHeader
|
||||
// onBack={() => window.history.back()}
|
||||
title={job.ro_number || t("general.labels.na")}
|
||||
extra={menuExtra}
|
||||
/>
|
||||
<JobsDetailHeader job={job}/>
|
||||
<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: "general",
|
||||
icon: <Icon component={FaShieldAlt}/>,
|
||||
label: t("menus.jobsdetail.general"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailGeneral job={job} form={form}/>
|
||||
},
|
||||
{
|
||||
key: "repairdata",
|
||||
icon: <BarsOutlined/>,
|
||||
label: t("menus.jobsdetail.repairdata"),
|
||||
forceRender: true,
|
||||
children: <JobsLinesContainer job={job} joblines={job.joblines} refetch={refetch}
|
||||
form={form}/>
|
||||
},
|
||||
{
|
||||
key: "rates",
|
||||
icon: <DollarCircleOutlined/>,
|
||||
label: t("menus.jobsdetail.rates"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailRates job={job} form={form}/>
|
||||
},
|
||||
{
|
||||
key: "totals",
|
||||
icon: <DollarCircleOutlined/>,
|
||||
label: t("menus.jobsdetail.totals"),
|
||||
children: <JobsDetailTotals job={job} refetch={refetch}/>
|
||||
},
|
||||
{
|
||||
key: "partssublet",
|
||||
icon: <ToolFilled/>,
|
||||
label: HasFeatureAccess({featureName: "bills", bodyshop})
|
||||
? t("menus.jobsdetail.partssublet")
|
||||
: t("menus.jobsdetail.parts"),
|
||||
children: <JobsDetailPliContainer job={job}/>
|
||||
},
|
||||
...(InstanceRenderManager({
|
||||
imex: true,
|
||||
rome: true,
|
||||
promanager: HasFeatureAccess({featureName: "timetickets", bodyshop})
|
||||
})
|
||||
? [
|
||||
{
|
||||
key: "labor",
|
||||
icon: <Icon component={FaHardHat}/>,
|
||||
label: t("menus.jobsdetail.labor"),
|
||||
children: <JobsDetailLaborContainer job={job} jobId={job.id}/>
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: "lifecycle",
|
||||
icon: <BarsOutlined/>,
|
||||
label: t("menus.jobsdetail.lifecycle"),
|
||||
children: <JobLifecycleComponent job={job} statuses={bodyshop.md_ro_statuses}/>
|
||||
},
|
||||
{
|
||||
key: "dates",
|
||||
icon: <CalendarFilled/>,
|
||||
label: t("menus.jobsdetail.dates"),
|
||||
forceRender: true,
|
||||
children: <JobsDetailDatesComponent job={job}/>
|
||||
},
|
||||
...(InstanceRenderManager({
|
||||
imex: true,
|
||||
rome: true,
|
||||
promanager: HasFeatureAccess({featureName: "media", bodyshop})
|
||||
})
|
||||
? [
|
||||
{
|
||||
key: "documents",
|
||||
icon: <FileImageFilled/>,
|
||||
label: t("jobs.labels.documents"),
|
||||
children: bodyshop.uselocalmediaserver ? (
|
||||
<JobsDocumentsLocalGallery job={job}/>
|
||||
) : (
|
||||
<JobsDocumentsGalleryContainer jobId={job.id}/>
|
||||
)
|
||||
}
|
||||
]
|
||||
: []),
|
||||
{
|
||||
key: "notes",
|
||||
icon: <Icon component={FaRegStickyNote}/>,
|
||||
label: t("jobs.labels.notes"),
|
||||
children: <JobNotesContainer jobId={job.id}/>
|
||||
},
|
||||
{
|
||||
key: "audit",
|
||||
icon: <HistoryOutlined/>,
|
||||
label: t("jobs.labels.audit"),
|
||||
children: <JobAuditTrail jobId={job.id}/>
|
||||
},
|
||||
{
|
||||
key: 'tasks',
|
||||
icon: <FaTasks/>,
|
||||
label: t("menus.jobsdetail.tasks"),
|
||||
children: <TaskListContainer bodyshop={bodyshop} relationshipType={'jobid'} relationshipId={job.id} query={QUERY_JOB_TASKS_PAGINATED} titleTranslation='tasks.titles.job_tasks'/>
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</Form>
|
||||
</div>
|
||||
@@ -394,22 +404,24 @@ export function JobsDetailPage({
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailPage);
|
||||
|
||||
const transformJobToForm = (job) => {
|
||||
const transformedJob = {...job};
|
||||
const transformedJob = {...job};
|
||||
|
||||
transformedJob.parts_tax_rates = Object.keys(transformedJob.parts_tax_rates).reduce((acc, parttype) => {
|
||||
acc[parttype] = Object.keys(transformedJob.parts_tax_rates[parttype]).reduce((innerAcc, key) => {
|
||||
if (key.includes("tx_in")) {
|
||||
innerAcc[key] = transformedJob.parts_tax_rates[parttype][key] === "Y" || transformedJob.parts_tax_rates[parttype][key] === true;
|
||||
} else {
|
||||
innerAcc[key] = transformedJob.parts_tax_rates[parttype][key];
|
||||
}
|
||||
return innerAcc;
|
||||
}, {});
|
||||
return acc;
|
||||
transformedJob.parts_tax_rates = Object.keys(transformedJob.parts_tax_rates).reduce((acc, parttype) => {
|
||||
acc[parttype] = Object.keys(transformedJob.parts_tax_rates[parttype]).reduce((innerAcc, key) => {
|
||||
if (key.includes("tx_in")) {
|
||||
innerAcc[key] =
|
||||
transformedJob.parts_tax_rates[parttype][key] === "Y" ||
|
||||
transformedJob.parts_tax_rates[parttype][key] === true;
|
||||
} else {
|
||||
innerAcc[key] = transformedJob.parts_tax_rates[parttype][key];
|
||||
}
|
||||
return innerAcc;
|
||||
}, {});
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
transformedJob.loss_date = transformedJob.loss_date ? dayjs(transformedJob.loss_date) : null;
|
||||
transformedJob.date_estimated = transformedJob.date_estimated ? dayjs(transformedJob.date_estimated) : null;
|
||||
transformedJob.loss_date = transformedJob.loss_date ? dayjs(transformedJob.loss_date) : null;
|
||||
transformedJob.date_estimated = transformedJob.date_estimated ? dayjs(transformedJob.date_estimated) : null;
|
||||
|
||||
return transformedJob;
|
||||
return transformedJob;
|
||||
};
|
||||
|
||||
@@ -1,123 +1,107 @@
|
||||
import {useMutation, useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useMutation, useQuery } from "@apollo/client";
|
||||
import React, { 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 { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {GET_JOB_BY_PK, UPDATE_JOB} from "../../graphql/jobs.queries";
|
||||
import { GET_JOB_BY_PK, UPDATE_JOB } from "../../graphql/jobs.queries";
|
||||
import {
|
||||
addRecentItem,
|
||||
setBreadcrumbs,
|
||||
setJobReadOnly,
|
||||
setSelectedHeader,
|
||||
addRecentItem,
|
||||
setBreadcrumbs,
|
||||
setJobReadOnly,
|
||||
setSelectedHeader
|
||||
} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {CreateRecentItem} from "../../utils/create-recent-item";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import IsJobReadOnly from "../../utils/jobReadOnly";
|
||||
import JobsDetailPage from "./jobs-detail.page.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
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)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setJobReadOnly: (bool) => dispatch(setJobReadOnly(bool))
|
||||
});
|
||||
|
||||
function JobsDetailPageContainer({
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
setJobReadOnly,
|
||||
}) {
|
||||
const {jobId} = useParams();
|
||||
const {t} = useTranslation();
|
||||
function JobsDetailPageContainer({ 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",
|
||||
});
|
||||
const [mutationUpdateJob] = useMutation(UPDATE_JOB);
|
||||
const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, {
|
||||
variables: { id: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const [mutationUpdateJob] = useMutation(UPDATE_JOB);
|
||||
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = loading
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: error
|
||||
? InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")})
|
||||
: t("titles.jobsdetail", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
ro_number:
|
||||
(data.jobs_by_pk && 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"),
|
||||
}),
|
||||
},
|
||||
]);
|
||||
|
||||
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)}`,
|
||||
`/manage/jobs/${jobId}`
|
||||
)
|
||||
);
|
||||
}
|
||||
}, [
|
||||
loading,
|
||||
data,
|
||||
t,
|
||||
error,
|
||||
setBreadcrumbs,
|
||||
jobId,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
setJobReadOnly,
|
||||
useEffect(() => {
|
||||
setSelectedHeader("activejobs");
|
||||
document.title = loading
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: error
|
||||
? InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
})
|
||||
: t("titles.jobsdetail", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
ro_number: (data.jobs_by_pk && 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")
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
if (loading) return <SpinComponent/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!!!data.jobs_by_pk) return <NotFound/>;
|
||||
if (data && data.jobs_by_pk) {
|
||||
setJobReadOnly(IsJobReadOnly(data.jobs_by_pk));
|
||||
|
||||
return data.jobs_by_pk ? (
|
||||
<RbacWrapper action="jobs:detail">
|
||||
<JobsDetailPage
|
||||
job={data.jobs_by_pk}
|
||||
mutationUpdateJob={mutationUpdateJob}
|
||||
refetch={refetch}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
) : (
|
||||
<AlertComponent message={t("jobs.errors.noaccess")} type="error"/>
|
||||
);
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
jobId,
|
||||
"job",
|
||||
|
||||
`${data.jobs_by_pk.ro_number || t("general.labels.na")} | ${OwnerNameDisplayFunction(data.jobs_by_pk)}`,
|
||||
`/manage/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">
|
||||
<JobsDetailPage job={data.jobs_by_pk} mutationUpdateJob={mutationUpdateJob} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
) : (
|
||||
<AlertComponent message={t("jobs.errors.noaccess")} type="error" />
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsDetailPageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsDetailPageContainer);
|
||||
|
||||
@@ -1,94 +1,84 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { 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 JobChecklist from "../../components/job-checklist/job-checklist.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import {QUERY_INTAKE_CHECKLIST} from "../../graphql/bodyshop.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { QUERY_INTAKE_CHECKLIST } from "../../graphql/bodyshop.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {Result} from "antd";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { Result } from "antd";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop,
|
||||
//currentUser: selectCurrentUser
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsIntakeContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
const {jobId} = useParams();
|
||||
export function JobsIntakeContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const { jobId } = useParams();
|
||||
|
||||
const {loading, error, data} = useQuery(QUERY_INTAKE_CHECKLIST, {
|
||||
variables: {shopId: bodyshop.id, jobId: jobId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
const { loading, error, data } = useQuery(QUERY_INTAKE_CHECKLIST, {
|
||||
variables: { shopId: bodyshop.id, jobId: jobId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-intake", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("activejobs");
|
||||
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"))
|
||||
})
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/intake`,
|
||||
label: t("titles.bc.jobs-intake")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs-intake",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("activejobs");
|
||||
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")),
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: `/manage/jobs/${jobId}/intake`,
|
||||
label: t("titles.bc.jobs-intake"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, jobId, data, setSelectedHeader]);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (data && !!!data.bodyshops_by_pk.intakechecklist)
|
||||
return <AlertComponent message={t("intake.errors.nochecklist")} type="error" />;
|
||||
|
||||
if (data && !!!data.bodyshops_by_pk.intakechecklist)
|
||||
return (
|
||||
<AlertComponent message={t("intake.errors.nochecklist")} type="error"/>
|
||||
);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:intake">
|
||||
<div>
|
||||
{!!data.jobs_by_pk.intakechecklist ||
|
||||
!bodyshop.md_ro_statuses.pre_production_statuses.includes(
|
||||
data.jobs_by_pk.status
|
||||
) ? (
|
||||
<Result status="warning" title={t("jobs.errors.cannotintake")}/>
|
||||
) : (
|
||||
<JobChecklist
|
||||
type="intake"
|
||||
checklistConfig={
|
||||
(data && data.bodyshops_by_pk.intakechecklist) || {}
|
||||
}
|
||||
job={data && data.jobs_by_pk}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:intake">
|
||||
<div>
|
||||
{!!data.jobs_by_pk.intakechecklist ||
|
||||
!bodyshop.md_ro_statuses.pre_production_statuses.includes(data.jobs_by_pk.status) ? (
|
||||
<Result status="warning" title={t("jobs.errors.cannotintake")} />
|
||||
) : (
|
||||
<JobChecklist
|
||||
type="intake"
|
||||
checklistConfig={(data && data.bodyshops_by_pk.intakechecklist) || {}}
|
||||
job={data && data.jobs_by_pk}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(JobsIntakeContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(JobsIntakeContainer);
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
||||
import JobsReadyList from "../../components/jobs-ready-list/jobs-ready-list.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
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)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsReadyPage({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function JobsReadyPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.readyjobs",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("readyjobs");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/jobs", label: t("titles.bc.jobs-ready")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.readyjobs", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("readyjobs");
|
||||
setBreadcrumbs([{ link: "/manage/jobs", label: t("titles.bc.jobs-ready") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-ready">
|
||||
<JobsReadyList/>
|
||||
<JobDetailCards/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-ready">
|
||||
<JobsReadyList />
|
||||
<JobDetailCards />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(JobsReadyPage);
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import JobDetailCards from "../../components/job-detail-cards/job-detail-cards.component";
|
||||
import JobsList from "../../components/jobs-list/jobs-list.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
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)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function JobsPage({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function JobsPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("activejobs");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/jobs", label: t("titles.bc.jobs-active")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.jobs", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("activejobs");
|
||||
setBreadcrumbs([{ link: "/manage/jobs", label: t("titles.bc.jobs-active") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-active">
|
||||
<JobsList/>
|
||||
<JobDetailCards/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:list-active">
|
||||
<JobsList />
|
||||
<JobDetailCards />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(JobsPage);
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import React, { useEffect } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import { selectCurrentUser } from '../../redux/user/user.selectors';
|
||||
import { Spin } from 'antd';
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectCurrentUser } from "../../redux/user/user.selectors";
|
||||
import { Spin } from "antd";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
currentUser: selectCurrentUser,
|
||||
currentUser: selectCurrentUser
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(LandingPage);
|
||||
|
||||
export function LandingPage({ currentUser }) {
|
||||
const navigate = useNavigate();
|
||||
console.log('Main');
|
||||
console.log("Main");
|
||||
useEffect(() => {
|
||||
navigate('/manage/jobs');
|
||||
navigate("/manage/jobs");
|
||||
}, [currentUser, navigate]);
|
||||
return <Spin />;
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import React, {useEffect} from "react";
|
||||
import React, { useEffect } from "react";
|
||||
//import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component";
|
||||
import {useNavigate} from "react-router-dom";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
export default function ManageRootPageComponent() {
|
||||
//const client = useApolloClient();
|
||||
const navigate = useNavigate();
|
||||
//const client = useApolloClient();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
navigate('/manage/jobs');
|
||||
}, [navigate]);
|
||||
|
||||
return <div/>;
|
||||
// return (
|
||||
// <div>
|
||||
// <DashboardGridComponent />
|
||||
// </div>
|
||||
// );
|
||||
useEffect(() => {
|
||||
navigate("/manage/jobs");
|
||||
}, [navigate]);
|
||||
|
||||
return <div />;
|
||||
// return (
|
||||
// <div>
|
||||
// <DashboardGridComponent />
|
||||
// </div>
|
||||
// );
|
||||
}
|
||||
|
||||
@@ -1,31 +1,34 @@
|
||||
import React, {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 React, { 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';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs))
|
||||
});
|
||||
|
||||
export function ManageRootPageContainer({setBreadcrumbs, bodyshop}) {
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.manageroot",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setBreadcrumbs([]);
|
||||
}, [t, setBreadcrumbs]);
|
||||
export function ManageRootPageContainer({ setBreadcrumbs, bodyshop }) {
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.manageroot", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setBreadcrumbs([]);
|
||||
}, [t, setBreadcrumbs]);
|
||||
|
||||
return <ManageRootPageComponent/>;
|
||||
return <ManageRootPageComponent />;
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ManageRootPageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ManageRootPageContainer);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,36 +1,35 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { 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 { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
import { setBodyshop } from "../../redux/user/user.actions";
|
||||
import ManagePage from "./manage.page.component";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs)),
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs))
|
||||
});
|
||||
|
||||
function ManagePageContainer({setBodyshop}) {
|
||||
const {loading, error, data} = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
function ManagePageContainer({ setBodyshop }) {
|
||||
const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setBodyshop(data.bodyshops[0] || {notfound: true});
|
||||
}
|
||||
}, [data, setBodyshop]);
|
||||
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"/>;
|
||||
if (loading) return <LoadingSpinner message={t("general.labels.loadingshop")} />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return <ManagePage/>;
|
||||
return <ManagePage />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ManagePageContainer);
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
import {Col, Divider, Row} from "antd";
|
||||
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";
|
||||
|
||||
export default function OwnersDetailComponent({owner, refetch}) {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<OwnerDetailForm owner={owner} refetch={refetch}/>
|
||||
</Col>
|
||||
<Divider type="horizontal"/>
|
||||
<Col span={24}>
|
||||
<OwnerDetailJobsComponent owner={owner}/>
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
export default function OwnersDetailComponent({ owner, refetch }) {
|
||||
return (
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<OwnerDetailForm owner={owner} refetch={refetch} />
|
||||
</Col>
|
||||
<Divider type="horizontal" />
|
||||
<Col span={24}>
|
||||
<OwnerDetailJobsComponent owner={owner} />
|
||||
</Col>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,75 +1,70 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useParams} from 'react-router-dom';
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_OWNER_BY_ID} from "../../graphql/owners.queries";
|
||||
import {addRecentItem, setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {CreateRecentItem} from "../../utils/create-recent-item";
|
||||
import { QUERY_OWNER_BY_ID } from "../../graphql/owners.queries";
|
||||
import { addRecentItem, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { CreateRecentItem } from "../../utils/create-recent-item";
|
||||
import OwnersDetailComponent from "./owners-detail.page.component";
|
||||
import NotFound from "../../components/not-found/not-found.component";
|
||||
import {OwnerNameDisplayFunction} from "../../components/owner-name-display/owner-name-display.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { OwnerNameDisplayFunction } from "../../components/owner-name-display/owner-name-display.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function OwnersDetailContainer({
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {ownerId} = useParams();
|
||||
const {t} = useTranslation();
|
||||
export function OwnersDetailContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader }) {
|
||||
const { ownerId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {loading, data, error, refetch} = useQuery(QUERY_OWNER_BY_ID, {
|
||||
variables: {id: ownerId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
const { loading, data, error, refetch } = useQuery(QUERY_OWNER_BY_ID, {
|
||||
variables: { id: ownerId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.owners-detail", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : ""
|
||||
});
|
||||
setSelectedHeader("owners");
|
||||
setBreadcrumbs([
|
||||
{ link: "/manage/owners", label: t("titles.bc.owners") },
|
||||
{
|
||||
link: `/manage/owners/${ownerId}`,
|
||||
label: t("titles.bc.owner-detail", {
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.owners-detail", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||
});
|
||||
setSelectedHeader("owners");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/owners", label: t("titles.bc.owners")},
|
||||
{
|
||||
link: `/manage/owners/${ownerId}`,
|
||||
label: t("titles.bc.owner-detail", {
|
||||
name: data ? OwnerNameDisplayFunction(data.owners_by_pk) : "",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
if (data && data.owners_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(ownerId, "owner", OwnerNameDisplayFunction(data.owners_by_pk), `/manage/owners/${ownerId}`)
|
||||
);
|
||||
}, [setBreadcrumbs, t, data, ownerId, addRecentItem, setSelectedHeader]);
|
||||
|
||||
if (data && data.owners_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
ownerId,
|
||||
"owner",
|
||||
OwnerNameDisplayFunction(data.owners_by_pk),
|
||||
`/manage/owners/${ownerId}`
|
||||
)
|
||||
);
|
||||
}, [setBreadcrumbs, t, data, ownerId, addRecentItem, setSelectedHeader]);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!!!data.owners_by_pk) return <NotFound />;
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!!!data.owners_by_pk) return <NotFound/>;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="owners:detail">
|
||||
<OwnersDetailComponent owner={data.owners_by_pk} refetch={refetch}/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="owners:detail">
|
||||
<OwnersDetailComponent owner={data.owners_by_pk} refetch={refetch} />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(OwnersDetailContainer);
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from "react";
|
||||
import OwnersListContainer from "../../components/owners-list/owners-list.container";
|
||||
|
||||
export default function OwnersPageComponent() {
|
||||
return <OwnersListContainer/>;
|
||||
return <OwnersListContainer />;
|
||||
}
|
||||
|
||||
@@ -1,29 +1,35 @@
|
||||
import React, {useEffect} from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import OwnersPageComponent from "./owners.page.component";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {connect} from "react-redux";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function OwnersPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.owners",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("owners");
|
||||
setBreadcrumbs([{link: "/manage/owners", label: t("titles.bc.owners")}]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
export function OwnersPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.owners", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("owners");
|
||||
setBreadcrumbs([{ link: "/manage/owners", label: t("titles.bc.owners") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="owners:list">
|
||||
<OwnersPageComponent/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="owners:list">
|
||||
<OwnersPageComponent />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(OwnersPageContainer);
|
||||
|
||||
@@ -1,34 +1,38 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import PartsQueueDetailCard from "../../components/parts-queue-card/parts-queue-card.component";
|
||||
import PartsQueueList from "../../components/parts-queue-list/parts-queue.list.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
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)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function PartsQueuePageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function PartsQueuePageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.parts-queue",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("parts-queue");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/partsqueue", label: t("titles.bc.parts-queue")},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.parts-queue", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("parts-queue");
|
||||
setBreadcrumbs([{ link: "/manage/partsqueue", label: t("titles.bc.parts-queue") }]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="jobs:partsqueue">
|
||||
<PartsQueueList/>
|
||||
<PartsQueueDetailCard/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="jobs:partsqueue">
|
||||
<PartsQueueList />
|
||||
<PartsQueueDetailCard />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(PartsQueuePageContainer);
|
||||
|
||||
@@ -1,79 +1,76 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import PaymentsListPaginated from "../../components/payments-list-paginated/payment-list-paginated.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_ALL_PAYMENTS_PAGINATED} from "../../graphql/payments.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import { QUERY_ALL_PAYMENTS_PAGINATED } from "../../graphql/payments.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function AllJobs({bodyshop, setBreadcrumbs, setSelectedHeader}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder, searchObj} = searchParams;
|
||||
export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, searchObj } = searchParams;
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_ALL_PAYMENTS_PAGINATED,
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
searchObj
|
||||
? JSON.parse(searchObj)
|
||||
: {
|
||||
[sortcolumn || "date"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "desc",
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
);
|
||||
const {t} = useTranslation();
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_ALL_PAYMENTS_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
searchObj
|
||||
? JSON.parse(searchObj)
|
||||
: {
|
||||
[sortcolumn || "date"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "desc"
|
||||
}
|
||||
]
|
||||
}
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.payments-all",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("allpayments");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/payments", label: t("titles.bc.payments-all")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.payments-all", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("allpayments");
|
||||
setBreadcrumbs([{ link: "/manage/payments", label: t("titles.bc.payments-all") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='payments'>
|
||||
<RbacWrapper action="payments:list">
|
||||
<PaymentsListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.payments_aggregate.aggregate.count : 0}
|
||||
payments={data ? data.payments : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="payments">
|
||||
<RbacWrapper action="payments:list">
|
||||
<PaymentsListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
searchParams={searchParams}
|
||||
total={data ? data.payments_aggregate.aggregate.count : 0}
|
||||
payments={data ? data.payments : []}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AllJobs);
|
||||
|
||||
@@ -1,216 +1,207 @@
|
||||
import {SyncOutlined} from "@ant-design/icons";
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Button, Card, Input, Space, Table, Typography} from "antd";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
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";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {QUERY_PHONEBOOK_PAGINATED} from "../../graphql/phonebook.queries";
|
||||
import {selectAuthLevel, selectBodyshop,} from "../../redux/user/user.selectors";
|
||||
import { QUERY_PHONEBOOK_PAGINATED } from "../../graphql/phonebook.queries";
|
||||
import { selectAuthLevel, selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ChatOpenButton from "../../components/chat-open-button/chat-open-button.component";
|
||||
import {alphaSort} from "../../utils/sorters";
|
||||
import {HasRbacAccess} from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {pageLimit} from "../../utils/config";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { HasRbacAccess } from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import { pageLimit } from "../../utils/config";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
authLevel: selectAuthLevel,
|
||||
bodyshop: selectBodyshop,
|
||||
authLevel: selectAuthLevel
|
||||
});
|
||||
|
||||
export function PhonebookPageComponent({bodyshop, authLevel}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page, sortcolumn, sortorder, search, phonebookentry} = searchParams;
|
||||
const history = useNavigate();
|
||||
export function PhonebookPageComponent({ bodyshop, authLevel }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page, sortcolumn, sortorder, search, phonebookentry } = searchParams;
|
||||
const history = useNavigate();
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_PHONEBOOK_PAGINATED,
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_PHONEBOOK_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
variables: {
|
||||
search: search || "",
|
||||
offset: page ? (page - 1) * pageLimit : 0,
|
||||
limit: pageLimit,
|
||||
order: [
|
||||
{
|
||||
[sortcolumn || "lastname"]: sortorder
|
||||
? sortorder === "descend"
|
||||
? "desc"
|
||||
: "asc"
|
||||
: "asc",
|
||||
},
|
||||
],
|
||||
},
|
||||
[sortcolumn || "lastname"]: sortorder ? (sortorder === "descend" ? "desc" : "asc") : "asc"
|
||||
}
|
||||
);
|
||||
]
|
||||
}
|
||||
});
|
||||
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
searchParams.sortcolumn = sorter.columnKey;
|
||||
searchParams.sortorder = sorter.order;
|
||||
if (filters.status) {
|
||||
searchParams.statusFilters = JSON.stringify(
|
||||
_.flattenDeep(filters.status)
|
||||
);
|
||||
} else {
|
||||
delete searchParams.statusFilters;
|
||||
}
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
};
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
searchParams.sortcolumn = sorter.columnKey;
|
||||
searchParams.sortorder = sorter.order;
|
||||
if (filters.status) {
|
||||
searchParams.statusFilters = JSON.stringify(_.flattenDeep(filters.status));
|
||||
} else {
|
||||
delete searchParams.statusFilters;
|
||||
}
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
};
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("phonebook.fields.firstname"),
|
||||
dataIndex: "firstname",
|
||||
key: "firstname",
|
||||
sorter: (a, b) => alphaSort(a.firstname, b.firstname),
|
||||
sortOrder: sortcolumn === "firstname" && sortorder,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.lastname"),
|
||||
dataIndex: "lastname",
|
||||
key: "lastname",
|
||||
sorter: (a, b) => alphaSort(a.lastname, b.lastname),
|
||||
sortOrder: sortcolumn === "lastname" && sortorder,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.company"),
|
||||
dataIndex: "company",
|
||||
key: "company",
|
||||
sorter: (a, b) => alphaSort(a.company, b.company),
|
||||
sortOrder: sortcolumn === "company" && sortorder,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.category"),
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
sorter: (a, b) => alphaSort(a.category, b.category),
|
||||
sortOrder: sortcolumn === "category" && sortorder,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.email"),
|
||||
dataIndex: "email",
|
||||
key: "email",
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.phone1"),
|
||||
dataIndex: "phone1",
|
||||
key: "phone1",
|
||||
render: (text, record) => <ChatOpenButton phone={text}/>,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.phone2"),
|
||||
dataIndex: "phone2",
|
||||
key: "phone2",
|
||||
render: (text, record) => <ChatOpenButton phone={text}/>,
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.address1"),
|
||||
dataIndex: "address1",
|
||||
key: "address1",
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.city"),
|
||||
dataIndex: "city",
|
||||
key: "city",
|
||||
},
|
||||
];
|
||||
const columns = [
|
||||
{
|
||||
title: t("phonebook.fields.firstname"),
|
||||
dataIndex: "firstname",
|
||||
key: "firstname",
|
||||
sorter: (a, b) => alphaSort(a.firstname, b.firstname),
|
||||
sortOrder: sortcolumn === "firstname" && sortorder
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.lastname"),
|
||||
dataIndex: "lastname",
|
||||
key: "lastname",
|
||||
sorter: (a, b) => alphaSort(a.lastname, b.lastname),
|
||||
sortOrder: sortcolumn === "lastname" && sortorder
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.company"),
|
||||
dataIndex: "company",
|
||||
key: "company",
|
||||
sorter: (a, b) => alphaSort(a.company, b.company),
|
||||
sortOrder: sortcolumn === "company" && sortorder
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.category"),
|
||||
dataIndex: "category",
|
||||
key: "category",
|
||||
sorter: (a, b) => alphaSort(a.category, b.category),
|
||||
sortOrder: sortcolumn === "category" && sortorder
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.email"),
|
||||
dataIndex: "email",
|
||||
key: "email"
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.phone1"),
|
||||
dataIndex: "phone1",
|
||||
key: "phone1",
|
||||
render: (text, record) => <ChatOpenButton phone={text} />
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.phone2"),
|
||||
dataIndex: "phone2",
|
||||
key: "phone2",
|
||||
render: (text, record) => <ChatOpenButton phone={text} />
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.address1"),
|
||||
dataIndex: "address1",
|
||||
key: "address1"
|
||||
},
|
||||
{
|
||||
title: t("phonebook.fields.city"),
|
||||
dataIndex: "city",
|
||||
key: "city"
|
||||
}
|
||||
];
|
||||
|
||||
const handleNewPhonebook = () => {
|
||||
searchParams.phonebookentry = "new";
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
};
|
||||
const handleNewPhonebook = () => {
|
||||
searchParams.phonebookentry = "new";
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
};
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
if (record) {
|
||||
searchParams.phonebookentry = record.id;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
} else {
|
||||
delete searchParams.phonebookentry;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
}
|
||||
};
|
||||
const hasNoAccess = !HasRbacAccess({
|
||||
bodyshop,
|
||||
authLevel,
|
||||
action: "phonebook:edit",
|
||||
});
|
||||
const handleOnRowClick = (record) => {
|
||||
if (record) {
|
||||
searchParams.phonebookentry = record.id;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
} else {
|
||||
delete searchParams.phonebookentry;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
}
|
||||
};
|
||||
const hasNoAccess = !HasRbacAccess({
|
||||
bodyshop,
|
||||
authLevel,
|
||||
action: "phonebook:edit"
|
||||
});
|
||||
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
{searchParams.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", {
|
||||
search: searchParams.search,
|
||||
})}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete searchParams.search;
|
||||
searchParams.page = 1;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
}}
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button disabled={hasNoAccess} onClick={handleNewPhonebook}>
|
||||
{t("phonebook.actions.new")}
|
||||
</Button>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined/>
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={searchParams.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
searchParams.search = value;
|
||||
searchParams.page = 1;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
{searchParams.search && (
|
||||
<>
|
||||
<Typography.Title level={4}>
|
||||
{t("general.labels.searchresults", {
|
||||
search: searchParams.search
|
||||
})}
|
||||
</Typography.Title>
|
||||
<Button
|
||||
onClick={() => {
|
||||
delete searchParams.search;
|
||||
searchParams.page = 1;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
>
|
||||
{t("general.actions.clear")}
|
||||
</Button>
|
||||
</>
|
||||
)}
|
||||
<Button disabled={hasNoAccess} onClick={handleNewPhonebook}>
|
||||
{t("phonebook.actions.new")}
|
||||
</Button>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={searchParams.search || t("general.labels.search")}
|
||||
onSearch={(value) => {
|
||||
searchParams.search = value;
|
||||
searchParams.page = 1;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
}}
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: data && data.search_phonebook_aggregate.aggregate.count
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_phonebook}
|
||||
//scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
onSelect: handleOnRowClick,
|
||||
type: "radio",
|
||||
selectedRowKeys: [phonebookentry]
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
return {
|
||||
onClick: (event) => {
|
||||
handleOnRowClick(record);
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
position: "top",
|
||||
pageSize: pageLimit,
|
||||
current: parseInt(page || 1),
|
||||
total: data && data.search_phonebook_aggregate.aggregate.count,
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={data && data.search_phonebook}
|
||||
//scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
rowSelection={{
|
||||
onSelect: handleOnRowClick,
|
||||
type: "radio",
|
||||
selectedRowKeys: [phonebookentry],
|
||||
}}
|
||||
onRow={(record, rowIndex) => {
|
||||
return {
|
||||
onClick: (event) => {
|
||||
handleOnRowClick(record);
|
||||
},
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, null)(PhonebookPageComponent);
|
||||
|
||||
@@ -1,70 +1,74 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import PhonebookPage from "./phonebook.page.component";
|
||||
import {Drawer, Grid} from "antd";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import { Drawer, Grid } from "antd";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import PhonebookFormContainer from "../../components/phonebook-form/phonebook-form.container";
|
||||
import queryString from "query-string";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function PhonebookContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.phonebook", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("phonebook");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/phonebook",
|
||||
label: t("titles.bc.phonebook"),
|
||||
},
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.phonebook", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("phonebook");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/phonebook",
|
||||
label: t("titles.bc.phonebook")
|
||||
}
|
||||
]);
|
||||
}, [setBreadcrumbs, t, setSelectedHeader]);
|
||||
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const {phonebookentry} = search;
|
||||
const search = queryString.parse(useLocation().search);
|
||||
const { phonebookentry } = search;
|
||||
|
||||
const navigate = useNavigate();
|
||||
const navigate = useNavigate();
|
||||
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
|
||||
const bpoints = {
|
||||
xs: "100%",
|
||||
sm: "100%",
|
||||
md: "100%",
|
||||
lg: "50%",
|
||||
xl: "50%",
|
||||
xxl: "45%",
|
||||
};
|
||||
const drawerPercentage = selectedBreakpoint
|
||||
? bpoints[selectedBreakpoint[0]]
|
||||
: "100%";
|
||||
const bpoints = {
|
||||
xs: "100%",
|
||||
sm: "100%",
|
||||
md: "100%",
|
||||
lg: "50%",
|
||||
xl: "50%",
|
||||
xxl: "45%"
|
||||
};
|
||||
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
|
||||
|
||||
return (
|
||||
(<RbacWrapper action="phonebook:view">
|
||||
<PhonebookPage/>
|
||||
<Drawer
|
||||
width={drawerPercentage}
|
||||
onClose={() => {
|
||||
delete search.phonebookentry;
|
||||
navigate({search: queryString.stringify(search)});
|
||||
}}
|
||||
open={phonebookentry}
|
||||
>
|
||||
<PhonebookFormContainer/>
|
||||
</Drawer>
|
||||
</RbacWrapper>)
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="phonebook:view">
|
||||
<PhonebookPage />
|
||||
<Drawer
|
||||
width={drawerPercentage}
|
||||
onClose={() => {
|
||||
delete search.phonebookentry;
|
||||
navigate({ search: queryString.stringify(search) });
|
||||
}}
|
||||
open={phonebookentry}
|
||||
>
|
||||
<PhonebookFormContainer />
|
||||
</Drawer>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(PhonebookContainer);
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from "react";
|
||||
import ProductionBoardKanbanContainer from "../../components/production-board-kanban/production-board-kanban.container";
|
||||
|
||||
export default function ProductionBoardComponent() {
|
||||
return <ProductionBoardKanbanContainer/>;
|
||||
return <ProductionBoardKanbanContainer />;
|
||||
}
|
||||
|
||||
@@ -1,51 +1,50 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ProductionBoardComponent from "./production-board.component";
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ProductionBoardContainer({
|
||||
setBreadcrumbs,
|
||||
bodyshop,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function ProductionBoardContainer({ setBreadcrumbs, bodyshop, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.productionboard",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("productionboard");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/production/board",
|
||||
label: t("titles.bc.productionboard"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.productionboard", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("productionboard");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/production/board",
|
||||
label: t("titles.bc.productionboard")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<FeatureWrapper featureName="visualboard">
|
||||
<RbacWrapper action="production:board">
|
||||
<ProductionBoardComponent/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
return (
|
||||
<FeatureWrapper featureName="visualboard">
|
||||
<RbacWrapper action="production:board">
|
||||
<ProductionBoardComponent />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ProductionBoardContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ProductionBoardContainer);
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from "react";
|
||||
import ProductionListTable from "../../components/production-list-table/production-list-table.container";
|
||||
|
||||
export default function ProductionListComponent() {
|
||||
return <ProductionListTable/>;
|
||||
return <ProductionListTable />;
|
||||
}
|
||||
|
||||
@@ -1,36 +1,40 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import ProductionListComponent from "./production-list.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ProductionListContainer({
|
||||
setBreadcrumbs,
|
||||
setBreadcrumbs,
|
||||
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
setSelectedHeader
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.productionlist",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("productionlist");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/production/list", label: t("titles.bc.productionlist")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.productionlist", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("productionlist");
|
||||
setBreadcrumbs([{ link: "/manage/production/list", label: t("titles.bc.productionlist") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="production:list">
|
||||
<ProductionListComponent/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="production:list">
|
||||
<ProductionListComponent />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ProductionListContainer);
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import ProfilePage from "./profile.page";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ProfileContainerPage({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
setSelectedHeader("profile");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/profile", label: t("titles.bc.profile")},
|
||||
]);
|
||||
document.title = t("titles.profile",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
export function ProfileContainerPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
setSelectedHeader("profile");
|
||||
setBreadcrumbs([{ link: "/manage/profile", label: t("titles.bc.profile") }]);
|
||||
document.title = t("titles.profile", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return <ProfilePage/>;
|
||||
return <ProfilePage />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(ProfileContainerPage);
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
import {Row} from "antd";
|
||||
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";
|
||||
|
||||
export default function ProfilePage() {
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<ProfileMyComponent/>
|
||||
<ProfileShopsContainer/>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<ProfileMyComponent />
|
||||
<ProfileShopsContainer />
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
import React from "react";
|
||||
import {useLocation} from "react-router-dom";
|
||||
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";
|
||||
import queryString from "query-string";
|
||||
|
||||
export default function ResetPassword() {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {mode, oobCode} = searchParams;
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { mode, oobCode } = searchParams;
|
||||
|
||||
if (mode === "resetPassword")
|
||||
return <UserValidatePwReset oobCode={oobCode}/>;
|
||||
return <UserRequestResetPw/>;
|
||||
}
|
||||
if (mode === "resetPassword") return <UserValidatePwReset oobCode={oobCode} />;
|
||||
return <UserRequestResetPw />;
|
||||
}
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from "react";
|
||||
import ScheduleCalendarContainer from "../../components/schedule-calendar/schedule-calendar.container";
|
||||
|
||||
export default function SchedulePageComponent() {
|
||||
return <ScheduleCalendarContainer/>;
|
||||
return <ScheduleCalendarContainer />;
|
||||
}
|
||||
|
||||
@@ -1,32 +1,36 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import SchedulePageComponent from "./schedule.page.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function SchedulePageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function SchedulePageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.schedule",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("schedule");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/schedule", label: t("titles.bc.schedule")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.schedule", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("schedule");
|
||||
setBreadcrumbs([{ link: "/manage/schedule", label: t("titles.bc.schedule") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="schedule:view">
|
||||
<SchedulePageComponent/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="schedule:view">
|
||||
<SchedulePageComponent />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(SchedulePageContainer);
|
||||
|
||||
@@ -1,34 +1,34 @@
|
||||
import Icon, {FieldTimeOutlined} from "@ant-design/icons";
|
||||
import {Tabs} from "antd";
|
||||
import Icon, { FieldTimeOutlined } from "@ant-design/icons";
|
||||
import { Tabs } from "antd";
|
||||
import queryString from "query-string";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {FaShieldAlt} from "react-icons/fa";
|
||||
import {connect} from "react-redux";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { FaShieldAlt } from "react-icons/fa";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
|
||||
import ScoreboardTimeTicketsStats from "../../components/scoreboard-timetickets-stats/scoreboard-timetickets.component";
|
||||
import ScoreboardTimeTickets from "../../components/scoreboard-timetickets/scoreboard-timetickets.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
/**
|
||||
* Mapping state to props
|
||||
*/
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
/**
|
||||
* Mapping dispatch to props
|
||||
*/
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -37,74 +37,77 @@ const mapDispatchToProps = (dispatch) => ({
|
||||
* @param {Function} props.setBreadcrumbs - Function to set breadcrumbs.
|
||||
* @param {Function} props.setSelectedHeader - Function to set selected header.
|
||||
*/
|
||||
export function ScoreboardContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {tab} = searchParams;
|
||||
const history = useNavigate();
|
||||
export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { tab } = searchParams;
|
||||
const history = useNavigate();
|
||||
|
||||
/**
|
||||
* useEffect hook to set document title, selected header and breadcrumbs
|
||||
*/
|
||||
useEffect(() => {
|
||||
document.title = t("titles.scoreboard",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("scoreboard");
|
||||
setBreadcrumbs([
|
||||
/**
|
||||
* useEffect hook to set document title, selected header and breadcrumbs
|
||||
*/
|
||||
useEffect(() => {
|
||||
document.title = t("titles.scoreboard", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("scoreboard");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/scoreboard",
|
||||
label: t("titles.bc.scoreboard")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
/**
|
||||
* Render the component
|
||||
*/
|
||||
return (
|
||||
<FeatureWrapper featureName="scoreboard">
|
||||
<RbacWrapper action="scoreboard:view">
|
||||
<Tabs
|
||||
activeKey={tab || "sb"}
|
||||
destroyInactiveTabPane
|
||||
onChange={(key) => {
|
||||
searchParams.tab = key;
|
||||
history({
|
||||
search: queryString.stringify(searchParams)
|
||||
});
|
||||
}}
|
||||
items={[
|
||||
{
|
||||
link: "/manage/scoreboard",
|
||||
label: t("titles.bc.scoreboard"),
|
||||
key: "sb",
|
||||
icon: <Icon component={FaShieldAlt} />,
|
||||
label: t("scoreboard.labels.jobs"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardDisplay />
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
/**
|
||||
* Render the component
|
||||
*/
|
||||
return (
|
||||
<FeatureWrapper featureName="scoreboard">
|
||||
<RbacWrapper action="scoreboard:view">
|
||||
<Tabs
|
||||
activeKey={tab || "sb"}
|
||||
destroyInactiveTabPane
|
||||
onChange={(key) => {
|
||||
searchParams.tab = key;
|
||||
history({
|
||||
search: queryString.stringify(searchParams),
|
||||
});
|
||||
}}
|
||||
items={[
|
||||
{
|
||||
key: "sb",
|
||||
icon: <Icon component={FaShieldAlt}/>,
|
||||
label: t("scoreboard.labels.jobs"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardDisplay/>,
|
||||
},
|
||||
{
|
||||
key: "tickets",
|
||||
icon: <FieldTimeOutlined/>,
|
||||
label: t("scoreboard.labels.timeticketsemployee"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardTimeTickets/>,
|
||||
},
|
||||
{
|
||||
key: "ticketsstats",
|
||||
icon: <FieldTimeOutlined/>,
|
||||
label: t("scoreboard.labels.allemployeetimetickets"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardTimeTicketsStats/>,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
{
|
||||
key: "tickets",
|
||||
icon: <FieldTimeOutlined />,
|
||||
label: t("scoreboard.labels.timeticketsemployee"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardTimeTickets />
|
||||
},
|
||||
{
|
||||
key: "ticketsstats",
|
||||
icon: <FieldTimeOutlined />,
|
||||
label: t("scoreboard.labels.allemployeetimetickets"),
|
||||
forceRender: true,
|
||||
children: <ScoreboardTimeTicketsStats />
|
||||
}
|
||||
]}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connecting the component to Redux store
|
||||
*/
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ScoreboardContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ScoreboardContainer);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
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';
|
||||
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";
|
||||
|
||||
export default function ShiftClock() {
|
||||
return (
|
||||
|
||||
@@ -1,74 +1,72 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Col, Row} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Col, Row } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import CsiResponseFormContainer from "../../components/csi-response-form/csi-response-form.container";
|
||||
import CsiResponseListPaginated
|
||||
from "../../components/csi-response-list-paginated/csi-response-list-paginated.component";
|
||||
import CsiResponseListPaginated from "../../components/csi-response-list-paginated/csi-response-list-paginated.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {QUERY_CSI_RESPONSE_PAGINATED} from "../../graphql/csi.queries";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ShopCsiContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
export function ShopCsiContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_CSI_RESPONSE_PAGINATED,
|
||||
{
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
}
|
||||
);
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_CSI_RESPONSE_PAGINATED, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop-csi",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("shop-csi");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", {shopname: bodyshop.shopname}),
|
||||
},
|
||||
{link: "/manage/shop/csi", label: t("titles.bc.shop-csi")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, bodyshop.shopname, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop-csi", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("shop-csi");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", { shopname: bodyshop.shopname })
|
||||
},
|
||||
{ link: "/manage/shop/csi", label: t("titles.bc.shop-csi") }
|
||||
]);
|
||||
}, [t, setBreadcrumbs, bodyshop.shopname, setSelectedHeader]);
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
return (
|
||||
<RbacWrapper action="csi:page">
|
||||
<Row gutter={16}>
|
||||
<Col span={10}>
|
||||
<CsiResponseListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
responses={data ? data.csi : []}
|
||||
total={data ? data.csi_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<CsiResponseFormContainer/>
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="csi:page">
|
||||
<Row gutter={16}>
|
||||
<Col span={10}>
|
||||
<CsiResponseListPaginated
|
||||
refetch={refetch}
|
||||
loading={loading}
|
||||
responses={data ? data.csi : []}
|
||||
total={data ? data.csi_aggregate.aggregate.count : 0}
|
||||
/>
|
||||
</Col>
|
||||
<Col span={14}>
|
||||
<CsiResponseFormContainer />
|
||||
</Col>
|
||||
</Row>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer);
|
||||
|
||||
@@ -1,43 +1,41 @@
|
||||
import {Drawer, Grid} from "antd";
|
||||
import { Drawer, Grid } from "antd";
|
||||
import React from "react";
|
||||
import {useNavigate, useSearchParams} from "react-router-dom";
|
||||
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";
|
||||
|
||||
export default function ShopVendorPageComponent() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const {selectedvendor} = Object.fromEntries(searchParams);
|
||||
const navigate = useNavigate();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { selectedvendor } = Object.fromEntries(searchParams);
|
||||
const navigate = useNavigate();
|
||||
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
|
||||
.filter((screen) => !!screen[1])
|
||||
.slice(-1)[0];
|
||||
|
||||
const bpoints = {
|
||||
xs: "100%",
|
||||
sm: "100%",
|
||||
md: "100%",
|
||||
lg: "50%",
|
||||
xl: "50%",
|
||||
xxl: "45%",
|
||||
};
|
||||
const drawerPercentage = selectedBreakpoint
|
||||
? bpoints[selectedBreakpoint[0]]
|
||||
: "100%";
|
||||
const bpoints = {
|
||||
xs: "100%",
|
||||
sm: "100%",
|
||||
md: "100%",
|
||||
lg: "50%",
|
||||
xl: "50%",
|
||||
xxl: "45%"
|
||||
};
|
||||
const drawerPercentage = selectedBreakpoint ? bpoints[selectedBreakpoint[0]] : "100%";
|
||||
|
||||
return (
|
||||
(<div>
|
||||
<VendorsListContainer/>
|
||||
<Drawer
|
||||
width={drawerPercentage}
|
||||
onClose={() => {
|
||||
searchParams.delete("selectedvendor");
|
||||
navigate({search: searchParams.toString()});
|
||||
}}
|
||||
open={selectedvendor}
|
||||
>
|
||||
<VendorsFormContainer/>
|
||||
</Drawer>
|
||||
</div>)
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
<VendorsListContainer />
|
||||
<Drawer
|
||||
width={drawerPercentage}
|
||||
onClose={() => {
|
||||
searchParams.delete("selectedvendor");
|
||||
navigate({ search: searchParams.toString() });
|
||||
}}
|
||||
open={selectedvendor}
|
||||
>
|
||||
<VendorsFormContainer />
|
||||
</Drawer>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,48 +1,47 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import ShopVendorPageComponent from "./shop-vendor.page.component";
|
||||
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function ShopVendorPageContainer({
|
||||
bodyshop,
|
||||
setBreadcrumbs,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {t} = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop_vendors", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("shop-vendors");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", {shopname: bodyshop.shopname}),
|
||||
},
|
||||
{link: "/manage/shop/vendors", label: t("titles.bc.shop-vendors")},
|
||||
]);
|
||||
}, [t, bodyshop.shopname, setBreadcrumbs, setSelectedHeader]);
|
||||
export function ShopVendorPageContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop_vendors", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("shop-vendors");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", { shopname: bodyshop.shopname })
|
||||
},
|
||||
{ link: "/manage/shop/vendors", label: t("titles.bc.shop-vendors") }
|
||||
]);
|
||||
}, [t, bodyshop.shopname, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="shop:vendors">
|
||||
<ShopVendorPageComponent/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="shop:vendors">
|
||||
<ShopVendorPageComponent />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(ShopVendorPageContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ShopVendorPageContainer);
|
||||
|
||||
@@ -1,93 +1,95 @@
|
||||
import {Tabs} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import { Tabs } from "antd";
|
||||
import React, { useEffect } from "react";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import queryString from "query-string";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container";
|
||||
import ShopInfoContainer from "../../components/shop-info/shop-info.container";
|
||||
import ShopCsiConfig from "../../components/shop-csi-config/shop-csi-config.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import ShopInfoUsersComponent from "../../components/shop-users/shop-users.component";
|
||||
|
||||
import ShopTeamsContainer from "../../components/shop-teams/shop-teams.container";
|
||||
import { HasFeatureAccess } from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs))
|
||||
});
|
||||
|
||||
export function ShopPage({bodyshop, setSelectedHeader, setBreadcrumbs}) {
|
||||
const {t} = useTranslation();
|
||||
const history = useNavigate();
|
||||
const search = queryString.parse(useLocation().search);
|
||||
export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
const search = queryString.parse(useLocation().search);
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("shop");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", {shopname: bodyshop.shopname}),
|
||||
},
|
||||
]);
|
||||
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!search.tab) history({search: "?tab=info"});
|
||||
}, [history, search]);
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: "info",
|
||||
label: t("bodyshop.labels.shopinfo"),
|
||||
children: <ShopInfoContainer/>,
|
||||
},
|
||||
{
|
||||
key: "employees",
|
||||
label: t("bodyshop.labels.employees"),
|
||||
children: <ShopEmployeesContainer/>,
|
||||
}];
|
||||
|
||||
if (bodyshop.md_tasks_presets.enable_tasks) {
|
||||
items.push({
|
||||
key: "teams",
|
||||
label: t("bodyshop.labels.employee_teams"),
|
||||
children: <ShopTeamsContainer/>
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
key: "licensing",
|
||||
label: t("bodyshop.labels.licensing"),
|
||||
children: <ShopInfoUsersComponent/>,
|
||||
},
|
||||
);
|
||||
|
||||
if(HasFeatureAccess({featureName:"csi", bodyshop})){
|
||||
items.push({
|
||||
key: "csiq",
|
||||
label: t("bodyshop.labels.csiq"),
|
||||
children: <ShopCsiConfig/>,
|
||||
useEffect(() => {
|
||||
document.title = t("titles.shop", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
}
|
||||
return (
|
||||
<RbacWrapper action="shop:config">
|
||||
<Tabs
|
||||
activeKey={search.tab}
|
||||
onChange={(key) => history({search: `?tab=${key}`})}
|
||||
items={items}
|
||||
/>
|
||||
</RbacWrapper>
|
||||
);
|
||||
});
|
||||
setSelectedHeader("shop");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/shop",
|
||||
label: t("titles.bc.shop", { shopname: bodyshop.shopname })
|
||||
}
|
||||
]);
|
||||
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!search.tab) history({ search: "?tab=info" });
|
||||
}, [history, search]);
|
||||
|
||||
const items = [
|
||||
{
|
||||
key: "info",
|
||||
label: t("bodyshop.labels.shopinfo"),
|
||||
children: <ShopInfoContainer />
|
||||
},
|
||||
{
|
||||
key: "employees",
|
||||
label: t("bodyshop.labels.employees"),
|
||||
children: <ShopEmployeesContainer />
|
||||
}
|
||||
];
|
||||
|
||||
if (bodyshop.md_tasks_presets.enable_tasks) {
|
||||
items.push({
|
||||
key: "teams",
|
||||
label: t("bodyshop.labels.employee_teams"),
|
||||
children: <ShopTeamsContainer />
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
key: "licensing",
|
||||
label: t("bodyshop.labels.licensing"),
|
||||
children: <ShopInfoUsersComponent />
|
||||
});
|
||||
|
||||
if (HasFeatureAccess({ featureName: "csi", bodyshop })) {
|
||||
items.push({
|
||||
key: "csiq",
|
||||
label: t("bodyshop.labels.csiq"),
|
||||
children: <ShopCsiConfig />
|
||||
});
|
||||
}
|
||||
return (
|
||||
<RbacWrapper action="shop:config">
|
||||
<Tabs activeKey={search.tab} onChange={(key) => history({ search: `?tab=${key}` })} items={items} />
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ShopPage);
|
||||
|
||||
@@ -2,9 +2,9 @@ import React from "react";
|
||||
import SignIn from "../../components/sign-in-form/sign-in-form.component";
|
||||
|
||||
export default function SignInPage() {
|
||||
return (
|
||||
<div>
|
||||
<SignIn/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<SignIn />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,261 +1,220 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useState} from "react";
|
||||
import {Button, Card, Input, Space, Table} from "antd";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM} from "../../graphql/jobs.queries";
|
||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {alphaSort} from "../../utils/sorters";
|
||||
import {SyncOutlined} from "@ant-design/icons";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useState } from "react";
|
||||
import { Button, Card, Input, Space, Table } from "antd";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM } from "../../graphql/jobs.queries";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { SyncOutlined } from "@ant-design/icons";
|
||||
import queryString from "query-string";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {useLocation, useNavigate} from "react-router-dom";
|
||||
import {onlyUnique} from "../../utils/arrayHelper";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { onlyUnique } from "../../utils/arrayHelper";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import OwnerNameDisplay from "../../components/owner-name-display/owner-name-display.component";
|
||||
import {setModalContext} from "../../redux/modals/modals.actions";
|
||||
import { setModalContext } from "../../redux/modals/modals.actions";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop,
|
||||
//currentUser: selectCurrentUser
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setTimeTicketTaskContext: (context) =>
|
||||
dispatch(setModalContext({context: context, modal: "timeTicketTask"})),
|
||||
setTimeTicketTaskContext: (context) => dispatch(setModalContext({ context: context, modal: "timeTicketTask" }))
|
||||
});
|
||||
|
||||
export function TechAssignedProdJobs({
|
||||
setTimeTicketTaskContext,
|
||||
technician,
|
||||
bodyshop,
|
||||
}) {
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM,
|
||||
{
|
||||
variables: {
|
||||
teamIds: bodyshop.employee_teams
|
||||
.filter((et) =>
|
||||
et.employee_team_members.find(
|
||||
(etm) => etm.employeeid === technician.id
|
||||
)
|
||||
)
|
||||
.map((et) => et.id),
|
||||
},
|
||||
}
|
||||
);
|
||||
export function TechAssignedProdJobs({ setTimeTicketTaskContext, technician, bodyshop }) {
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_JOBS_TECH_ASIGNED_TO_BY_TEAM, {
|
||||
variables: {
|
||||
teamIds: bodyshop.employee_teams
|
||||
.filter((et) => et.employee_team_members.find((etm) => etm.employeeid === technician.id))
|
||||
.map((et) => et.id)
|
||||
}
|
||||
});
|
||||
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {selected} = searchParams;
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { selected } = searchParams;
|
||||
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: {text: ""},
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
const history = useNavigate();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
const [state, setState] = useState({
|
||||
sortedInfo: {},
|
||||
filteredInfo: { text: "" }
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
const [searchText, setSearchText] = useState("");
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
const jobs = data
|
||||
? searchText === ""
|
||||
? data.jobs
|
||||
: data.jobs.filter(
|
||||
(j) =>
|
||||
(j.ro_number || "")
|
||||
.toString()
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_fn || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_ln || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_co_nm || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.plate_no || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.v_model_desc || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase()) ||
|
||||
(j.v_make_desc || "")
|
||||
.toLowerCase()
|
||||
.includes(searchText.toLowerCase())
|
||||
)
|
||||
: [];
|
||||
const columns = [
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
const jobs = data
|
||||
? searchText === ""
|
||||
? data.jobs
|
||||
: data.jobs.filter(
|
||||
(j) =>
|
||||
(j.ro_number || "").toString().toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_fn || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_ln || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.ownr_co_nm || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.clm_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.plate_no || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.v_model_desc || "").toLowerCase().includes(searchText.toLowerCase()) ||
|
||||
(j.v_make_desc || "").toLowerCase().includes(searchText.toLowerCase())
|
||||
)
|
||||
: [];
|
||||
const columns = [
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
sortOrder: state.sortedInfo.columnKey === "ro_number" && state.sortedInfo.order,
|
||||
|
||||
render: (text, record) => record.ro_number || t("general.labels.na"),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.owner"),
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record}/>
|
||||
render: (text, record) => record.ro_number || t("general.labels.na")
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.owner"),
|
||||
dataIndex: "owner",
|
||||
key: "owner",
|
||||
sorter: (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
|
||||
sortOrder: state.sortedInfo.columnKey === "owner" && state.sortedInfo.order,
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>
|
||||
<OwnerNameDisplay ownerObject={record} />
|
||||
</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
filters:
|
||||
(jobs &&
|
||||
jobs
|
||||
.map((j) => j.status)
|
||||
.filter(onlyUnique)
|
||||
.map((s) => {
|
||||
return {
|
||||
text: s || "No Status*",
|
||||
value: [s],
|
||||
};
|
||||
})) ||
|
||||
[],
|
||||
onFilter: (value, record) => value.includes(record.status),
|
||||
render: (text, record) => {
|
||||
return record.status || t("general.labels.na");
|
||||
},
|
||||
},
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
sortOrder: state.sortedInfo.columnKey === "status" && state.sortedInfo.order,
|
||||
filters:
|
||||
(jobs &&
|
||||
jobs
|
||||
.map((j) => j.status)
|
||||
.filter(onlyUnique)
|
||||
.map((s) => {
|
||||
return {
|
||||
text: s || "No Status*",
|
||||
value: [s]
|
||||
};
|
||||
})) ||
|
||||
[],
|
||||
onFilter: (value, record) => value.includes(record.status),
|
||||
render: (text, record) => {
|
||||
return record.status || t("general.labels.na");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${
|
||||
record.v_model_desc || ""
|
||||
}`}</span>
|
||||
),
|
||||
},
|
||||
{
|
||||
title: t("vehicles.fields.plate_no"),
|
||||
dataIndex: "plate_no",
|
||||
key: "plate_no",
|
||||
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.plate_no ? record.plate_no : "";
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.clm_no"),
|
||||
dataIndex: "clm_no",
|
||||
key: "clm_no",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||
sortOrder:
|
||||
state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.clm_no ? (
|
||||
<span>{record.clm_no}</span>
|
||||
) : (
|
||||
t("general.labels.unknown")
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTimeTicketTaskContext({
|
||||
actions: {refetch: refetch},
|
||||
context: {jobid: record.id},
|
||||
});
|
||||
}}
|
||||
>
|
||||
{t("timetickets.actions.claimtasks")}
|
||||
</Button>
|
||||
),
|
||||
},
|
||||
];
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({...state, filteredInfo: filters, sortedInfo: sorter});
|
||||
};
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
history({
|
||||
search: queryString.stringify({
|
||||
...searchParams,
|
||||
selected: record.id,
|
||||
}),
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined/>
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
setSearchText(e.target.value);
|
||||
}}
|
||||
value={searchText}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
{
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.v_model_yr || ""} ${record.v_make_desc || ""} ${record.v_model_desc || ""}`}</span>
|
||||
)
|
||||
},
|
||||
{
|
||||
title: t("vehicles.fields.plate_no"),
|
||||
dataIndex: "plate_no",
|
||||
key: "plate_no",
|
||||
sorter: (a, b) => alphaSort(a.plate_no, b.plate_no),
|
||||
sortOrder: state.sortedInfo.columnKey === "plate_no" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.plate_no ? record.plate_no : "";
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.clm_no"),
|
||||
dataIndex: "clm_no",
|
||||
key: "clm_no",
|
||||
ellipsis: true,
|
||||
sorter: (a, b) => alphaSort(a.clm_no, b.clm_no),
|
||||
sortOrder: state.sortedInfo.columnKey === "clm_no" && state.sortedInfo.order,
|
||||
render: (text, record) => {
|
||||
return record.clm_no ? <span>{record.clm_no}</span> : t("general.labels.unknown");
|
||||
}
|
||||
},
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Button
|
||||
onClick={() => {
|
||||
setTimeTicketTaskContext({
|
||||
actions: { refetch: refetch },
|
||||
context: { jobid: record.id }
|
||||
});
|
||||
}}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={jobs}
|
||||
scroll={{x: true}}
|
||||
rowSelection={{
|
||||
onSelect: (record) => {
|
||||
handleOnRowClick(record);
|
||||
},
|
||||
selectedRowKeys: [selected],
|
||||
type: "radio",
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
// onRow={(record, rowIndex) => {
|
||||
// return {
|
||||
// onClick: (event) => {
|
||||
// handleOnRowClick(record);
|
||||
// },
|
||||
// };
|
||||
// }}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
{t("timetickets.actions.claimtasks")}
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
];
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
setState({ ...state, filteredInfo: filters, sortedInfo: sorter });
|
||||
};
|
||||
|
||||
const handleOnRowClick = (record) => {
|
||||
if (record) {
|
||||
if (record.id) {
|
||||
history({
|
||||
search: queryString.stringify({
|
||||
...searchParams,
|
||||
selected: record.id
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
<Input.Search
|
||||
placeholder={t("general.labels.search")}
|
||||
onChange={(e) => {
|
||||
setSearchText(e.target.value);
|
||||
}}
|
||||
value={searchText}
|
||||
enterButton
|
||||
/>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={false}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={jobs}
|
||||
scroll={{ x: true }}
|
||||
rowSelection={{
|
||||
onSelect: (record) => {
|
||||
handleOnRowClick(record);
|
||||
},
|
||||
selectedRowKeys: [selected],
|
||||
type: "radio"
|
||||
}}
|
||||
onChange={handleTableChange}
|
||||
// onRow={(record, rowIndex) => {
|
||||
// return {
|
||||
// onClick: (event) => {
|
||||
// handleOnRowClick(record);
|
||||
// },
|
||||
// };
|
||||
// }}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TechAssignedProdJobs);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechAssignedProdJobs);
|
||||
|
||||
@@ -1,146 +1,135 @@
|
||||
import {MinusCircleTwoTone, PlusCircleTwoTone, SyncOutlined,} from "@ant-design/icons";
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {Button, Card, Space, Table} from "antd";
|
||||
import { MinusCircleTwoTone, PlusCircleTwoTone, SyncOutlined } from "@ant-design/icons";
|
||||
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";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import PartsDispatchExpander from "../../components/parts-dispatch-expander/parts-dispatch-expander.component";
|
||||
import {GET_UNACCEPTED_PARTS_DISPATCH} from "../../graphql/parts-dispatch.queries";
|
||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {alphaSort} from "../../utils/sorters";
|
||||
import { GET_UNACCEPTED_PARTS_DISPATCH } from "../../graphql/parts-dispatch.queries";
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { alphaSort } from "../../utils/sorters";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
//currentUser: selectCurrentUser
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop,
|
||||
//currentUser: selectCurrentUser
|
||||
technician: selectTechnician,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({});
|
||||
|
||||
export function TechDispatchedParts({technician, bodyshop}) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const {page} = searchParams;
|
||||
export function TechDispatchedParts({ technician, bodyshop }) {
|
||||
const searchParams = queryString.parse(useLocation().search);
|
||||
const { page } = searchParams;
|
||||
|
||||
const {treatments: {Enhanced_Payroll}} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Enhanced_Payroll"],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
const {
|
||||
treatments: { Enhanced_Payroll }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ["Enhanced_Payroll"],
|
||||
splitKey: bodyshop.imexshopid
|
||||
});
|
||||
|
||||
const {loading, error, data, refetch} = useQuery(
|
||||
GET_UNACCEPTED_PARTS_DISPATCH,
|
||||
{
|
||||
variables: {
|
||||
techId: technician.id,
|
||||
offset: page ? (page - 1) * 25 : 0,
|
||||
limit: 25,
|
||||
},
|
||||
}
|
||||
);
|
||||
const { loading, error, data, refetch } = useQuery(GET_UNACCEPTED_PARTS_DISPATCH, {
|
||||
variables: {
|
||||
techId: technician.id,
|
||||
offset: page ? (page - 1) * 25 : 0,
|
||||
limit: 25
|
||||
}
|
||||
});
|
||||
|
||||
const {t} = useTranslation();
|
||||
const history = useNavigate();
|
||||
const { t } = useTranslation();
|
||||
const history = useNavigate();
|
||||
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
const parts_dispatch = data?.parts_dispatch;
|
||||
const parts_dispatch = data?.parts_dispatch;
|
||||
|
||||
const columns = [
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "job.ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
const columns = [
|
||||
{
|
||||
title: t("jobs.fields.ro_number"),
|
||||
dataIndex: "job.ro_number",
|
||||
key: "ro_number",
|
||||
sorter: (a, b) => alphaSort(a.ro_number, b.ro_number),
|
||||
|
||||
render: (text, record) => record.job.ro_number || t("general.labels.na"),
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
render: (text, record) => {
|
||||
return record.job.status || t("general.labels.na");
|
||||
},
|
||||
},
|
||||
render: (text, record) => record.job.ro_number || t("general.labels.na")
|
||||
},
|
||||
{
|
||||
title: t("jobs.fields.status"),
|
||||
dataIndex: "status",
|
||||
key: "status",
|
||||
sorter: (a, b) => alphaSort(a.status, b.status),
|
||||
render: (text, record) => {
|
||||
return record.job.status || t("general.labels.na");
|
||||
}
|
||||
},
|
||||
|
||||
{
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.job.v_model_yr || ""} ${
|
||||
record.job.v_make_desc || ""
|
||||
} ${record.job.v_model_desc || ""}`}</span>
|
||||
),
|
||||
},
|
||||
...Enhanced_Payroll.treatment=== 'on' ? [ {
|
||||
{
|
||||
title: t("jobs.fields.vehicle"),
|
||||
dataIndex: "vehicle",
|
||||
key: "vehicle",
|
||||
ellipsis: true,
|
||||
render: (text, record) => (
|
||||
<span>{`${record.job.v_model_yr || ""} ${record.job.v_make_desc || ""} ${record.job.v_model_desc || ""}`}</span>
|
||||
)
|
||||
},
|
||||
...(Enhanced_Payroll.treatment === "on"
|
||||
? [
|
||||
{
|
||||
title: t("general.labels.actions"),
|
||||
dataIndex: "actions",
|
||||
key: "actions",
|
||||
render: (text, record) => (
|
||||
<Button onClick={() => {
|
||||
}}>
|
||||
{t("timetickets.actions.claimtasks")}
|
||||
</Button>
|
||||
),
|
||||
},] : []
|
||||
render: (text, record) => <Button onClick={() => {}}>{t("timetickets.actions.claimtasks")}</Button>
|
||||
}
|
||||
]
|
||||
: [])
|
||||
];
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
history({ search: queryString.stringify(searchParams) });
|
||||
};
|
||||
|
||||
|
||||
];
|
||||
const handleTableChange = (pagination, filters, sorter) => {
|
||||
searchParams.page = pagination.current;
|
||||
history({search: queryString.stringify(searchParams)});
|
||||
};
|
||||
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined/>
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: data ? data.parts_dispatch_aggregate.aggregate.count : 0,
|
||||
showSizeChanger: false,
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={parts_dispatch}
|
||||
scroll={{x: true}}
|
||||
onChange={handleTableChange}
|
||||
expandable={{
|
||||
expandedRowRender: (record) => (
|
||||
<PartsDispatchExpander dispatch={record}/>
|
||||
),
|
||||
rowExpandable: (record) => true,
|
||||
//expandRowByClick: true,
|
||||
expandIcon: ({expanded, onExpand, record}) =>
|
||||
expanded ? (
|
||||
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)}/>
|
||||
) : (
|
||||
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)}/>
|
||||
),
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
return (
|
||||
<Card
|
||||
extra={
|
||||
<Space wrap>
|
||||
<Button onClick={() => refetch()}>
|
||||
<SyncOutlined />
|
||||
</Button>
|
||||
</Space>
|
||||
}
|
||||
>
|
||||
<Table
|
||||
loading={loading}
|
||||
pagination={{
|
||||
pageSize: 25,
|
||||
current: parseInt(page || 1),
|
||||
total: data ? data.parts_dispatch_aggregate.aggregate.count : 0,
|
||||
showSizeChanger: false
|
||||
}}
|
||||
columns={columns}
|
||||
rowKey="id"
|
||||
dataSource={parts_dispatch}
|
||||
scroll={{ x: true }}
|
||||
onChange={handleTableChange}
|
||||
expandable={{
|
||||
expandedRowRender: (record) => <PartsDispatchExpander dispatch={record} />,
|
||||
rowExpandable: (record) => true,
|
||||
//expandRowByClick: true,
|
||||
expandIcon: ({ expanded, onExpand, record }) =>
|
||||
expanded ? (
|
||||
<MinusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
) : (
|
||||
<PlusCircleTwoTone onClick={(e) => onExpand(record, e)} />
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TechDispatchedParts);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechDispatchedParts);
|
||||
|
||||
@@ -1,24 +1,30 @@
|
||||
import {Divider} from "antd";
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import { Divider } from "antd";
|
||||
import React, { 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";
|
||||
import TechJobStatistics from "../../components/tech-job-statistics/tech-job-statistics.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
export default function TechClockComponent() {
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techjobclock", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
}, [t]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techjobclock", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TechJobStatistics/>
|
||||
<TechClockInFormContainer/>
|
||||
<Divider/>
|
||||
<TechClockedInList/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<TechJobStatistics />
|
||||
<TechClockInFormContainer />
|
||||
<Divider />
|
||||
<TechClockedInList />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,27 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import React, { 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";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
export default function TechLookupContainer() {
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techjoblookup", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
}, [t]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techjoblookup", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<RbacWrapperComponent action="jobs:list-active">
|
||||
<TechLookupJobsList/>
|
||||
</RbacWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<RbacWrapperComponent action="jobs:list-active">
|
||||
<TechLookupJobsList />
|
||||
</RbacWrapperComponent>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,18 +1,24 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import TimeTicketShift from "../../components/time-ticket-shift/time-ticket-shift.container";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
export default function TechShiftClock() {
|
||||
const {t} = useTranslation();
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techshiftclock",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
}, [t]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.techshiftclock", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<TimeTicketShift isTechConsole/>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
<TimeTicketShift isTechConsole />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import {FloatButton, Layout} from "antd";
|
||||
import React, {lazy, Suspense, useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {Route, Routes, useNavigate} from "react-router-dom";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { FloatButton, Layout } from "antd";
|
||||
import React, { lazy, Suspense, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { Route, Routes, useNavigate } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
|
||||
|
||||
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
@@ -12,108 +12,99 @@ import TechHeader from "../../components/tech-header/tech-header.component";
|
||||
import TechLookupJobsDrawer from "../../components/tech-lookup-jobs-drawer/tech-lookup-jobs-drawer.component";
|
||||
import TechSider from "../../components/tech-sider/tech-sider.component";
|
||||
import UpdateAlert from "../../components/update-alert/update-alert.component";
|
||||
import {selectTechnician} from "../../redux/tech/tech.selectors";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { selectTechnician } from "../../redux/tech/tech.selectors";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import "./tech.page.styles.scss";
|
||||
|
||||
const TimeTicketModalContainer = lazy(() =>
|
||||
import("../../components/time-ticket-modal/time-ticket-modal.container")
|
||||
);
|
||||
const EmailOverlayContainer = lazy(() =>
|
||||
import("../../components/email-overlay/email-overlay.container.jsx")
|
||||
);
|
||||
const PrintCenterModalContainer = lazy(() =>
|
||||
import("../../components/print-center-modal/print-center-modal.container")
|
||||
);
|
||||
const TechLogin = lazy(() =>
|
||||
import("../../components/tech-login/tech-login.component")
|
||||
const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
|
||||
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx"));
|
||||
const PrintCenterModalContainer = lazy(
|
||||
() => import("../../components/print-center-modal/print-center-modal.container")
|
||||
);
|
||||
const TechLogin = lazy(() => import("../../components/tech-login/tech-login.component"));
|
||||
const TechLookup = lazy(() => import("../tech-lookup/tech-lookup.container"));
|
||||
const ProductionListPage = lazy(() =>
|
||||
import("../production-list/production-list.container")
|
||||
);
|
||||
const ProductionBoardPage = lazy(() =>
|
||||
import("../production-board/production-board.container")
|
||||
);
|
||||
const TechJobClock = lazy(() =>
|
||||
import("../tech-job-clock/tech-job-clock.component")
|
||||
);
|
||||
const TechShiftClock = lazy(() =>
|
||||
import("../tech-shift-clock/tech-shift-clock.component")
|
||||
);
|
||||
const TimeTicketModalTask = lazy(() =>
|
||||
import(
|
||||
"../../components/time-ticket-task-modal/time-ticket-task-modal.container"
|
||||
)
|
||||
);
|
||||
const TechAssignedProdJobs = lazy(() =>
|
||||
import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component")
|
||||
);
|
||||
const TechDispatchedParts = lazy(() =>
|
||||
import("../tech-dispatched-parts/tech-dispatched-parts.page")
|
||||
const ProductionListPage = lazy(() => import("../production-list/production-list.container"));
|
||||
const ProductionBoardPage = lazy(() => import("../production-board/production-board.container"));
|
||||
const TechJobClock = lazy(() => import("../tech-job-clock/tech-job-clock.component"));
|
||||
const TechShiftClock = lazy(() => import("../tech-shift-clock/tech-shift-clock.component"));
|
||||
const TimeTicketModalTask = lazy(
|
||||
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
|
||||
);
|
||||
const TechAssignedProdJobs = lazy(() => import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component"));
|
||||
const TechDispatchedParts = lazy(() => import("../tech-dispatched-parts/tech-dispatched-parts.page"));
|
||||
|
||||
const {Content} = Layout;
|
||||
const { Content } = Layout;
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
technician: selectTechnician,
|
||||
technician: selectTechnician
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
|
||||
export function TechPage({technician}) {
|
||||
const {t} = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
export function TechPage({ technician }) {
|
||||
const { t } = useTranslation();
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = InstanceRenderManager({imex: t("titles.imexonline"), rome: t("titles.romeonline"), promanager:t("titles.promanager")});
|
||||
}, [t]);
|
||||
useEffect(() => {
|
||||
document.title = InstanceRenderManager({
|
||||
imex: t("titles.imexonline"),
|
||||
rome: t("titles.romeonline"),
|
||||
promanager: t("titles.promanager")
|
||||
});
|
||||
}, [t]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!technician) {
|
||||
navigate(`/tech/login`);
|
||||
}
|
||||
}, [technician, navigate]);
|
||||
useEffect(() => {
|
||||
if (!technician) {
|
||||
navigate(`/tech/login`);
|
||||
}
|
||||
}, [technician, navigate]);
|
||||
|
||||
return (
|
||||
<Layout className="tech-layout-container">
|
||||
<TechSider/>
|
||||
<Layout>
|
||||
<UpdateAlert/>
|
||||
<TechHeader/>
|
||||
<TechLookupJobsDrawer/>
|
||||
<Content className="tech-content-container">
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<LoadingSpinner message={t("general.labels.loadingapp", {app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})})}/>
|
||||
}
|
||||
>
|
||||
<FeatureWrapper featureName="tech-console">
|
||||
<TimeTicketModalContainer/>
|
||||
<EmailOverlayContainer/>
|
||||
<PrintCenterModalContainer/>
|
||||
<TimeTicketModalTask/>
|
||||
<Routes>
|
||||
<Route path='/login' element={<TechLogin/>}/>
|
||||
<Route path='/joblookup' element={<TechLookup/>}/>
|
||||
<Route path='/list' element={<ProductionListPage/>}/>
|
||||
<Route path='/jobclock' element={<TechJobClock/>}/>
|
||||
<Route path='/shiftclock' element={<TechShiftClock/>}/>
|
||||
<Route path='/board' element={<ProductionBoardPage/>}/>
|
||||
<Route path='/assigned' element={<TechAssignedProdJobs/>}/>
|
||||
<Route path='/dispatchedparts' element={<TechDispatchedParts/>}/>
|
||||
|
||||
</Routes>
|
||||
</FeatureWrapper>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
<FloatButton.BackTop/>
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
return (
|
||||
<Layout className="tech-layout-container">
|
||||
<TechSider />
|
||||
<Layout>
|
||||
<UpdateAlert />
|
||||
<TechHeader />
|
||||
<TechLookupJobsDrawer />
|
||||
<Content className="tech-content-container">
|
||||
<ErrorBoundary>
|
||||
<Suspense
|
||||
fallback={
|
||||
<LoadingSpinner
|
||||
message={t("general.labels.loadingapp", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
})}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<FeatureWrapper featureName="tech-console">
|
||||
<TimeTicketModalContainer />
|
||||
<EmailOverlayContainer />
|
||||
<PrintCenterModalContainer />
|
||||
<TimeTicketModalTask />
|
||||
<Routes>
|
||||
<Route path="/login" element={<TechLogin />} />
|
||||
<Route path="/joblookup" element={<TechLookup />} />
|
||||
<Route path="/list" element={<ProductionListPage />} />
|
||||
<Route path="/jobclock" element={<TechJobClock />} />
|
||||
<Route path="/shiftclock" element={<TechShiftClock />} />
|
||||
<Route path="/board" element={<ProductionBoardPage />} />
|
||||
<Route path="/assigned" element={<TechAssignedProdJobs />} />
|
||||
<Route path="/dispatchedparts" element={<TechDispatchedParts />} />
|
||||
</Routes>
|
||||
</FeatureWrapper>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
<FloatButton.BackTop />
|
||||
</Content>
|
||||
</Layout>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechPage);
|
||||
|
||||
@@ -1,39 +1,37 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import React, {useEffect} from "react";
|
||||
import {connect} from "react-redux";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React, { useEffect } from "react";
|
||||
import { connect } from "react-redux";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {QUERY_BODYSHOP} from "../../graphql/bodyshop.queries";
|
||||
import {setBodyshop} from "../../redux/user/user.actions";
|
||||
import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries";
|
||||
import { setBodyshop } from "../../redux/user/user.actions";
|
||||
import TechPage from "./tech.page.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs)),
|
||||
setBodyshop: (bs) => dispatch(setBodyshop(bs))
|
||||
});
|
||||
|
||||
export function TechPageContainer({bodyshop, setBodyshop}) {
|
||||
const {loading, error, data} = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
});
|
||||
const {t} = useTranslation();
|
||||
export function TechPageContainer({ bodyshop, setBodyshop }) {
|
||||
const { loading, error, data } = useQuery(QUERY_BODYSHOP, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (data) setBodyshop(data.bodyshops[0]);
|
||||
}, [data, setBodyshop]);
|
||||
useEffect(() => {
|
||||
if (data) setBodyshop(data.bodyshops[0]);
|
||||
}, [data, setBodyshop]);
|
||||
|
||||
|
||||
if (loading || !bodyshop)
|
||||
return <LoadingSpinner message={t("general.labels.loadingshop")}/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
return <TechPage/>;
|
||||
if (loading || !bodyshop) return <LoadingSpinner message={t("general.labels.loadingshop")} />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
return <TechPage />;
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TechPageContainer);
|
||||
|
||||
@@ -1,47 +1,43 @@
|
||||
import {useQuery} from "@apollo/client";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import React from "react";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import JobsDocumentsComponent from "../../components/jobs-documents-gallery/jobs-documents-gallery.component";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import {QUERY_TEMPORARY_DOCS} from "../../graphql/documents.queries";
|
||||
import { QUERY_TEMPORARY_DOCS } from "../../graphql/documents.queries";
|
||||
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import JobsDocumentsLocalGallery
|
||||
from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import JobsDocumentsLocalGallery from "../../components/jobs-documents-local-gallery/jobs-documents-local-gallery.container";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
//setUserLanguage: language => dispatch(setUserLanguage(language))
|
||||
});
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TemporaryDocsComponent);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TemporaryDocsComponent);
|
||||
|
||||
export function TemporaryDocsComponent({bodyshop}) {
|
||||
const {loading, error, data, refetch} = useQuery(QUERY_TEMPORARY_DOCS, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
skip: bodyshop.uselocalmediaserver,
|
||||
});
|
||||
export function TemporaryDocsComponent({ bodyshop }) {
|
||||
const { loading, error, data, refetch } = useQuery(QUERY_TEMPORARY_DOCS, {
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
skip: bodyshop.uselocalmediaserver
|
||||
});
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
|
||||
if (bodyshop.uselocalmediaserver) {
|
||||
return <JobsDocumentsLocalGallery job={{id: "temporary"}}/>;
|
||||
}
|
||||
return (
|
||||
<JobsDocumentsComponent
|
||||
data={data ? data.documents : []}
|
||||
jobId={null}
|
||||
billId={null}
|
||||
refetch={refetch}
|
||||
ignoreSizeLimit
|
||||
/>
|
||||
);
|
||||
if (bodyshop.uselocalmediaserver) {
|
||||
return <JobsDocumentsLocalGallery job={{ id: "temporary" }} />;
|
||||
}
|
||||
return (
|
||||
<JobsDocumentsComponent
|
||||
data={data ? data.documents : []}
|
||||
jobId={null}
|
||||
billId={null}
|
||||
refetch={refetch}
|
||||
ignoreSizeLimit
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,47 +1,50 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import TemporaryDocsComponent from "./temporary-docs.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function TempDocumentsContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function TempDocumentsContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.temporarydocs",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("temporarydocs");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/temporarydocs",
|
||||
label: t("titles.bc.temporarydocs"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.temporarydocs", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("temporarydocs");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/temporarydocs",
|
||||
label: t("titles.bc.temporarydocs")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<RbacWrapper action="temporarydocs:view">
|
||||
<FeatureWrapperComponent featureName="media">
|
||||
<TemporaryDocsComponent />
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
return (
|
||||
<RbacWrapper action="temporarydocs:view">
|
||||
<FeatureWrapperComponent featureName="media">
|
||||
<TemporaryDocsComponent />
|
||||
</FeatureWrapperComponent>
|
||||
</RbacWrapper>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(
|
||||
mapStateToProps,
|
||||
mapDispatchToProps
|
||||
)(TempDocumentsContainer);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TempDocumentsContainer);
|
||||
|
||||
@@ -1,73 +1,73 @@
|
||||
import { useQuery } from '@apollo/client';
|
||||
import { Col, Row, Space } from 'antd';
|
||||
import dayjs from '../../utils/day';
|
||||
import React, { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { connect } from 'react-redux';
|
||||
import { useSearchParams } from 'react-router-dom';
|
||||
import { createStructuredSelector } from 'reselect';
|
||||
import AlertComponent from '../../components/alert/alert.component';
|
||||
import RbacWrapper from '../../components/rbac-wrapper/rbac-wrapper.component';
|
||||
import TimeTicketsDatesSelector from '../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component';
|
||||
import TimeTicketList from '../../components/time-ticket-list/time-ticket-list.component';
|
||||
import TimeTicketsPayrollTable from '../../components/time-tickets-payroll-table/time-tickets-payroll-table.component';
|
||||
import TimeTicketsSummaryEmployees from '../../components/time-tickets-summary-employees/time-tickets-summary-employees.component';
|
||||
import { QUERY_TIME_TICKETS_IN_RANGE } from '../../graphql/timetickets.queries';
|
||||
import TimeTicketsAttendanceTable from '../../components/time-tickets-attendance-table/time-tickets-attendance-table.component';
|
||||
import { setBreadcrumbs, setSelectedHeader } from '../../redux/application/application.actions';
|
||||
import TimeTicketsCommit from '../../components/time-tickets-commit/time-tickets-commit.component';
|
||||
import FeatureWrapperComponent from '../../components/feature-wrapper/feature-wrapper.component';
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import { useSplitTreatments } from '@splitsoftware/splitio-react';
|
||||
import { selectBodyshop } from '../../redux/user/user.selectors';
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { Col, Row, Space } from "antd";
|
||||
import dayjs from "../../utils/day";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TimeTicketsDatesSelector from "../../components/ticket-tickets-dates-selector/time-tickets-dates-selector.component";
|
||||
import TimeTicketList from "../../components/time-ticket-list/time-ticket-list.component";
|
||||
import TimeTicketsPayrollTable from "../../components/time-tickets-payroll-table/time-tickets-payroll-table.component";
|
||||
import TimeTicketsSummaryEmployees from "../../components/time-tickets-summary-employees/time-tickets-summary-employees.component";
|
||||
import { QUERY_TIME_TICKETS_IN_RANGE } from "../../graphql/timetickets.queries";
|
||||
import TimeTicketsAttendanceTable from "../../components/time-tickets-attendance-table/time-tickets-attendance-table.component";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import TimeTicketsCommit from "../../components/time-tickets-commit/time-tickets-commit.component";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
import { useSplitTreatments } from "@splitsoftware/splitio-react";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop:selectBodyshop
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function TimeTicketsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
|
||||
const {
|
||||
treatments: { Enhanced_Payroll },
|
||||
treatments: { Enhanced_Payroll }
|
||||
} = useSplitTreatments({
|
||||
attributes: {},
|
||||
names: ['Enhanced_Payroll'],
|
||||
splitKey: bodyshop.imexshopid,
|
||||
names: ["Enhanced_Payroll"],
|
||||
splitKey: bodyshop.imexshopid
|
||||
});
|
||||
const { t } = useTranslation();
|
||||
const [searchParams] = useSearchParams();
|
||||
const { start, end } = Object.fromEntries(searchParams);
|
||||
|
||||
const startDate = start ? dayjs(start) : dayjs().startOf('week').subtract(7, 'day');
|
||||
const endDate = end ? dayjs(end) : dayjs().endOf('week');
|
||||
const startDate = start ? dayjs(start) : dayjs().startOf("week").subtract(7, "day");
|
||||
const endDate = end ? dayjs(end) : dayjs().endOf("week");
|
||||
|
||||
const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
|
||||
variables: {
|
||||
start: startDate,
|
||||
end: endDate,
|
||||
end: endDate
|
||||
},
|
||||
fetchPolicy: 'network-only',
|
||||
nextFetchPolicy: 'network-only',
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t('titles.timetickets', {
|
||||
document.title = t("titles.timetickets", {
|
||||
app: InstanceRenderManager({
|
||||
imex: '$t(titles.imexonline)',
|
||||
rome: '$t(titles.romeonline)',
|
||||
promanager: '$t(titles.promanager)',
|
||||
}),
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader('timetickets');
|
||||
setSelectedHeader("timetickets");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: '/manage/timetickets',
|
||||
label: t('titles.bc.timetickets'),
|
||||
},
|
||||
link: "/manage/timetickets",
|
||||
label: t("titles.bc.timetickets")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
@@ -85,7 +85,7 @@ export function TimeTicketsContainer({ bodyshop, setBreadcrumbs, setSelectedHead
|
||||
<Space wrap>
|
||||
<TimeTicketsAttendanceTable />
|
||||
<TimeTicketsPayrollTable />
|
||||
{Enhanced_Payroll.treatment === 'on' && (
|
||||
{Enhanced_Payroll.treatment === "on" && (
|
||||
<TimeTicketsCommit timetickets={data ? data.timetickets : []} />
|
||||
)}
|
||||
<TimeTicketsDatesSelector />
|
||||
|
||||
@@ -1,44 +1,50 @@
|
||||
import React, {useEffect} from "react";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {connect} from "react-redux";
|
||||
import {createStructuredSelector} from "reselect";
|
||||
import React, { useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
|
||||
import TtApprovalsList from "../../components/tt-approvals-list/tt-approvals-list.container";
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {selectBodyshop} from "../../redux/user/user.selectors";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
import { selectBodyshop } from "../../redux/user/user.selectors";
|
||||
import FeatureWrapperComponent from "../../components/feature-wrapper/feature-wrapper.component";
|
||||
import InstanceRenderManager from '../../utils/instanceRenderMgr';
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
bodyshop: selectBodyshop
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function TtApprovalsPage({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function TtApprovalsPage({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.ttapprovals",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("ttapprovals");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/ttapprovals",
|
||||
label: t("titles.bc.ttapprovals"),
|
||||
},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.ttapprovals", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("ttapprovals");
|
||||
setBreadcrumbs([
|
||||
{
|
||||
link: "/manage/ttapprovals",
|
||||
label: t("titles.bc.ttapprovals")
|
||||
}
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return (
|
||||
<FeatureWrapperComponent featureName='timetickets'>
|
||||
<RbacWrapper action="ttapprovals:view">
|
||||
<TtApprovalsList/>
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
return (
|
||||
<FeatureWrapperComponent featureName="timetickets">
|
||||
<RbacWrapper action="ttapprovals:view">
|
||||
<TtApprovalsList />
|
||||
</RbacWrapper>
|
||||
</FeatureWrapperComponent>
|
||||
);
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TtApprovalsPage);
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
import {Col, Divider, Row} from "antd";
|
||||
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";
|
||||
|
||||
export default function VehicleDetailComponent({vehicle, refetch}) {
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<VehicleDetailFormContainer vehicle={vehicle} refetch={refetch}/>
|
||||
</Col>
|
||||
<Divider type="horizontal"/>
|
||||
<Col span={24}>
|
||||
<VehicleDetailJobsComponent vehicle={vehicle}/>
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
export default function VehicleDetailComponent({ vehicle, refetch }) {
|
||||
return (
|
||||
<div>
|
||||
<Row gutter={[16, 16]}>
|
||||
<Col span={24}>
|
||||
<VehicleDetailFormContainer vehicle={vehicle} refetch={refetch} />
|
||||
</Col>
|
||||
<Divider type="horizontal" />
|
||||
<Col span={24}>
|
||||
<VehicleDetailJobsComponent vehicle={vehicle} />
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,92 +1,81 @@
|
||||
import React, {useEffect} from "react";
|
||||
import React, { useEffect } from "react";
|
||||
import VehicleDetailComponent from "./vehicles-detail.page.component";
|
||||
import {useQuery} from "@apollo/client";
|
||||
import {useParams} from 'react-router-dom';
|
||||
import {QUERY_VEHICLE_BY_ID} from "../../graphql/vehicles.queries";
|
||||
import { useQuery } from "@apollo/client";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { QUERY_VEHICLE_BY_ID } from "../../graphql/vehicles.queries";
|
||||
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
|
||||
import AlertComponent from "../../components/alert/alert.component";
|
||||
import {useTranslation} from "react-i18next";
|
||||
import {addRecentItem, setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import {connect} from "react-redux";
|
||||
import {CreateRecentItem} from "../../utils/create-recent-item";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { addRecentItem, setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
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 InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
addRecentItem: (item) => dispatch(addRecentItem(item)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function VehicleDetailContainer({
|
||||
setBreadcrumbs,
|
||||
addRecentItem,
|
||||
setSelectedHeader,
|
||||
}) {
|
||||
const {vehId} = useParams();
|
||||
const {t} = useTranslation();
|
||||
export function VehicleDetailContainer({ setBreadcrumbs, addRecentItem, setSelectedHeader }) {
|
||||
const { vehId } = useParams();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const {loading, data, error, refetch} = useQuery(QUERY_VEHICLE_BY_ID, {
|
||||
variables: {id: vehId},
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only",
|
||||
const { loading, data, error, refetch } = useQuery(QUERY_VEHICLE_BY_ID, {
|
||||
variables: { id: vehId },
|
||||
fetchPolicy: "network-only",
|
||||
nextFetchPolicy: "network-only"
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.vehicledetail", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
}),
|
||||
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) || ""}`
|
||||
: ""
|
||||
});
|
||||
setSelectedHeader("vehicles");
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.vehicledetail", {
|
||||
app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'}),
|
||||
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) || ""
|
||||
}`
|
||||
: "",
|
||||
});
|
||||
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) || ""}`
|
||||
: ""
|
||||
})
|
||||
}
|
||||
]);
|
||||
|
||||
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) ||
|
||||
""
|
||||
}`
|
||||
: "",
|
||||
}),
|
||||
},
|
||||
]);
|
||||
if (data && data.vehicles_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
vehId,
|
||||
"vehicle",
|
||||
`${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}`
|
||||
)
|
||||
);
|
||||
}, [t, data, setBreadcrumbs, vehId, addRecentItem, setSelectedHeader]);
|
||||
|
||||
if (data && data.vehicles_by_pk)
|
||||
addRecentItem(
|
||||
CreateRecentItem(
|
||||
vehId,
|
||||
"vehicle",
|
||||
`${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}`
|
||||
)
|
||||
);
|
||||
}, [t, data, setBreadcrumbs, vehId, addRecentItem, setSelectedHeader]);
|
||||
|
||||
if (loading) return <LoadingSpinner/>;
|
||||
if (error) return <AlertComponent message={error.message} type="error"/>;
|
||||
if (!data.vehicles_by_pk) return <NotFound/>;
|
||||
return (
|
||||
<VehicleDetailComponent vehicle={data.vehicles_by_pk} refetch={refetch}/>
|
||||
);
|
||||
if (loading) return <LoadingSpinner />;
|
||||
if (error) return <AlertComponent message={error.message} type="error" />;
|
||||
if (!data.vehicles_by_pk) return <NotFound />;
|
||||
return <VehicleDetailComponent vehicle={data.vehicles_by_pk} refetch={refetch} />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(VehicleDetailContainer);
|
||||
|
||||
@@ -2,5 +2,5 @@ import React from "react";
|
||||
import VehiclesListContainer from "../../components/vehicles-list/vehicles-list.container";
|
||||
|
||||
export default function VehiclesPageComponent() {
|
||||
return <VehiclesListContainer/>;
|
||||
return <VehiclesListContainer />;
|
||||
}
|
||||
|
||||
@@ -1,28 +1,32 @@
|
||||
import React, {useEffect} from "react";
|
||||
import React, { 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 { useTranslation } from "react-i18next";
|
||||
import { connect } from "react-redux";
|
||||
import InstanceRenderManager from "../../utils/instanceRenderMgr";
|
||||
|
||||
import {setBreadcrumbs, setSelectedHeader,} from "../../redux/application/application.actions";
|
||||
import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
|
||||
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
|
||||
setSelectedHeader: (key) => dispatch(setSelectedHeader(key))
|
||||
});
|
||||
|
||||
export function VehiclesPageContainer({setBreadcrumbs, setSelectedHeader}) {
|
||||
const {t} = useTranslation();
|
||||
export function VehiclesPageContainer({ setBreadcrumbs, setSelectedHeader }) {
|
||||
const { t } = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
document.title = t("titles.vehicles",{app: InstanceRenderManager({imex:'$t(titles.imexonline)', rome: '$t(titles.romeonline)', promanager: '$t(titles.promanager)'})} );
|
||||
setSelectedHeader("vehicles");
|
||||
setBreadcrumbs([
|
||||
{link: "/manage/vehicles", label: t("titles.bc.vehicles")},
|
||||
]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
useEffect(() => {
|
||||
document.title = t("titles.vehicles", {
|
||||
app: InstanceRenderManager({
|
||||
imex: "$t(titles.imexonline)",
|
||||
rome: "$t(titles.romeonline)",
|
||||
promanager: "$t(titles.promanager)"
|
||||
})
|
||||
});
|
||||
setSelectedHeader("vehicles");
|
||||
setBreadcrumbs([{ link: "/manage/vehicles", label: t("titles.bc.vehicles") }]);
|
||||
}, [t, setBreadcrumbs, setSelectedHeader]);
|
||||
|
||||
return <VehiclesPageComponent/>;
|
||||
return <VehiclesPageComponent />;
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(VehiclesPageContainer);
|
||||
|
||||
Reference in New Issue
Block a user