This commit is contained in:
Dave Richer
2023-12-11 17:34:05 -05:00
parent 5c164f807d
commit ad79344709
87 changed files with 1100 additions and 1113 deletions

View File

@@ -4,7 +4,7 @@ import LogRocket from "logrocket";
import React, { lazy, Suspense, useEffect } from "react"; import React, { lazy, Suspense, useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Route } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import DocumentEditorContainer from "../components/document-editor/document-editor.container"; import DocumentEditorContainer from "../components/document-editor/document-editor.container";
import ErrorBoundary from "../components/error-boundary/error-boundary.component"; import ErrorBoundary from "../components/error-boundary/error-boundary.component";
@@ -73,6 +73,7 @@ export function App({
window.addEventListener("online", function (e) { window.addEventListener("online", function (e) {
setOnline(true); setOnline(true);
}); });
useEffect(() => { useEffect(() => {
if (currentUser.authorized && bodyshop) { if (currentUser.authorized && bodyshop) {
client.setAttribute("imexshopid", bodyshop.imexshopid); client.setAttribute("imexshopid", bodyshop.imexshopid);
@@ -107,54 +108,77 @@ export function App({
/> />
); );
// <Switch>
// <Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
// <ErrorBoundary>
// <Route exact path="/" component={LandingPage} />
// </ErrorBoundary>
// <ErrorBoundary>
// <Route exact path="/signin" component={SignInPage} />
// </ErrorBoundary>
// <ErrorBoundary>
// <Route exact path="/resetpassword" component={ResetPassword} />
// </ErrorBoundary>
// <ErrorBoundary>
// <Route exact path="/csi/:surveyId" component={CsiPage} />
// </ErrorBoundary>
// <ErrorBoundary>
// <Route exact path="/disclaimer" component={DisclaimerPage} />
// </ErrorBoundary>
// <ErrorBoundary>
// <Route
// exact
// path="/mp/:paymentIs"
// component={MobilePaymentContainer}
// />
// </ErrorBoundary>
// <ErrorBoundary>
// <PrivateRoute
// isAuthorized={currentUser.authorized}
// path="/manage"
// component={ManagePage}
// />
// </ErrorBoundary>
// <ErrorBoundary>
// <PrivateRoute
// isAuthorized={currentUser.authorized}
// path="/tech"
// component={TechPageContainer}
// />
// </ErrorBoundary>
// <ErrorBoundary>
// <PrivateRoute
// isAuthorized={currentUser.authorized}
// path="/edit"
// component={DocumentEditorContainer}
// />
// </ErrorBoundary>
// </Suspense>
// </Switch>
return ( return (
<Switch> <Suspense fallback={<LoadingSpinner message="ImEX Online" />}>
<Suspense fallback={<LoadingSpinner message="ImEX Online" />}> <ErrorBoundary>
<ErrorBoundary> <Routes>
<Route exact path="/" component={LandingPage} /> <Route path="/" element={<LandingPage />} />
</ErrorBoundary> <Route path="/signin" element={<SignInPage />} />
<ErrorBoundary> <Route path="/resetpassword" element={<ResetPassword />} />
<Route exact path="/signin" component={SignInPage} /> <Route path="/csi/:surveyId" element={<CsiPage />} />
</ErrorBoundary> <Route path="/disclaimer" element={<DisclaimerPage />} />
<ErrorBoundary> <Route path="/mp/:paymentIs" element={<MobilePaymentContainer />} />
<Route exact path="/resetpassword" component={ResetPassword} /> <Route path="/manage" element={<PrivateRoute isAuthorized={currentUser.authorized} />}>
</ErrorBoundary> <Route path="/manage" element={<ManagePage />} />
<ErrorBoundary> </Route>
<Route exact path="/csi/:surveyId" component={CsiPage} /> <Route path="/tech" element={<PrivateRoute isAuthorized={currentUser.authorized} />}>
</ErrorBoundary> <Route path="/tech" element={<TechPageContainer />} />
<ErrorBoundary> </Route>
<Route exact path="/disclaimer" component={DisclaimerPage} /> <Route path="/edit" element={<PrivateRoute isAuthorized={currentUser.authorized} />}>
</ErrorBoundary> <Route path="/edit" element={<DocumentEditorContainer />} />
<ErrorBoundary> </Route>
<Route </Routes>
exact </ErrorBoundary>
path="/mp/:paymentIs" </Suspense>
component={MobilePaymentContainer}
/>
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/manage"
component={ManagePage}
/>
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/tech"
component={TechPageContainer}
/>
</ErrorBoundary>
<ErrorBoundary>
<PrivateRoute
isAuthorized={currentUser.authorized}
path="/edit"
component={DocumentEditorContainer}
/>
</ErrorBoundary>
</Suspense>
</Switch>
); );
} }

View File

@@ -1,21 +1,17 @@
import { useMutation, useQuery } from "@apollo/client"; import {useMutation, useQuery} from "@apollo/client";
import { Button, Form, PageHeader, Popconfirm, Space } from "antd"; import {Button, Form, PageHeader, Popconfirm, Space} from "antd";
import moment from "moment"; import moment from "moment";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, {useState} from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { useLocation } from "react-router-dom"; import {useSearchParams} from "react-router-dom";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { import {DELETE_BILL_LINE, INSERT_NEW_BILL_LINES, UPDATE_BILL_LINE} from "../../graphql/bill-lines.queries";
DELETE_BILL_LINE, import {QUERY_BILL_BY_PK, UPDATE_BILL} from "../../graphql/bills.queries";
INSERT_NEW_BILL_LINES, import {insertAuditTrail} from "../../redux/application/application.actions";
UPDATE_BILL_LINE import {setModalContext} from "../../redux/modals/modals.actions";
} from "../../graphql/bill-lines.queries"; import {selectBodyshop} from "../../redux/user/user.selectors";
import { QUERY_BILL_BY_PK, UPDATE_BILL } from "../../graphql/bills.queries";
import { insertAuditTrail } from "../../redux/application/application.actions";
import { setModalContext } from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors";
import AuditTrailMapping from "../../utils/AuditTrailMappings"; import AuditTrailMapping from "../../utils/AuditTrailMappings";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import BillFormContainer from "../bill-form/bill-form.container"; import BillFormContainer from "../bill-form/bill-form.container";
@@ -27,225 +23,223 @@ import LoadingSkeleton from "../loading-skeleton/loading-skeleton.component";
import BillDetailEditReturn from "./bill-detail-edit-return.component"; import BillDetailEditReturn from "./bill-detail-edit-return.component";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setPartsOrderContext: (context) => setPartsOrderContext: (context) =>
dispatch(setModalContext({ context: context, modal: "partsOrder" })), dispatch(setModalContext({context: context, modal: "partsOrder"})),
insertAuditTrail: ({ jobid, operation }) => insertAuditTrail: ({jobid, operation}) =>
dispatch(insertAuditTrail({ jobid, operation })), dispatch(insertAuditTrail({jobid, operation})),
}); });
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(BillDetailEditcontainer); )(BillDetailEditcontainer);
export function BillDetailEditcontainer({ export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail, bodyshop,}) {
setPartsOrderContext, const search = queryString.parse(useSearchParams().toString());
insertAuditTrail,
bodyshop,
}) {
const search = queryString.parse(useLocation().search);
const { t } = useTranslation(); const {t} = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const [updateLoading, setUpdateLoading] = useState(false); const [updateLoading, setUpdateLoading] = useState(false);
const [update_bill] = useMutation(UPDATE_BILL); const [update_bill] = useMutation(UPDATE_BILL);
const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES); const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES);
const [updateBillLine] = useMutation(UPDATE_BILL_LINE); const [updateBillLine] = useMutation(UPDATE_BILL_LINE);
const [deleteBillLine] = useMutation(DELETE_BILL_LINE); const [deleteBillLine] = useMutation(DELETE_BILL_LINE);
const { loading, error, data, refetch } = useQuery(QUERY_BILL_BY_PK, { const {loading, error, data, refetch} = useQuery(QUERY_BILL_BY_PK, {
variables: { billid: search.billid }, variables: {billid: search.billid},
skip: !!!search.billid, skip: !!!search.billid,
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
});
const handleSave = () => {
//It's got a previously deducted bill line!
if (
data.bills_by_pk.billlines.filter((b) => b.deductedfromlbr).length > 0 ||
form.getFieldValue("billlines").filter((b) => b.deductedfromlbr).length >
0
)
setVisible(true);
else {
form.submit();
}
};
const handleFinish = async (values) => {
setUpdateLoading(true);
//let adjustmentsToInsert = {};
const { billlines, upload, ...bill } = values;
const updates = [];
updates.push(
update_bill({
variables: { billId: search.billid, bill: bill },
})
);
billlines.forEach((l) => {
delete l.selected;
}); });
//Find bill lines that were deleted. // ... rest of the code remains the same
const deletedJobLines = [];
data.bills_by_pk.billlines.forEach((a) => { const handleSave = () => {
const matchingRecord = billlines.find((b) => b.id === a.id); //It's got a previously deducted bill line!
if (!matchingRecord) { if (
deletedJobLines.push(a); data.bills_by_pk.billlines.filter((b) => b.deductedfromlbr).length > 0 ||
} form.getFieldValue("billlines").filter((b) => b.deductedfromlbr).length >
}); 0
)
setVisible(true);
else {
form.submit();
}
};
deletedJobLines.forEach((d) => { const handleFinish = async (values) => {
updates.push(deleteBillLine({ variables: { id: d.id } })); setUpdateLoading(true);
}); //let adjustmentsToInsert = {};
billlines.forEach((billline) => { const {billlines, upload, ...bill} = values;
const { deductedfromlbr, inventories, jobline, ...il } = billline; const updates = [];
delete il.__typename;
if (il.id) {
updates.push( updates.push(
updateBillLine({ update_bill({
variables: { variables: {billId: search.billid, bill: bill},
billLineId: il.id, })
billLine: {
...il,
deductedfromlbr: deductedfromlbr,
joblineid: il.joblineid === "noline" ? null : il.joblineid,
},
},
})
); );
} else {
//It's a new line, have to insert it.
updates.push(
insertBillLine({
variables: {
billLines: [
{
...il,
deductedfromlbr: deductedfromlbr,
billid: search.billid,
joblineid: il.joblineid === "noline" ? null : il.joblineid,
},
],
},
})
);
}
});
await Promise.all(updates); billlines.forEach((l) => {
delete l.selected;
});
insertAuditTrail({ //Find bill lines that were deleted.
jobid: bill.jobid, const deletedJobLines = [];
billid: search.billid,
operation: AuditTrailMapping.billupdated(bill.invoice_number),
});
await refetch(); data.bills_by_pk.billlines.forEach((a) => {
form.setFieldsValue(transformData(data)); const matchingRecord = billlines.find((b) => b.id === a.id);
form.resetFields(); if (!matchingRecord) {
setVisible(false); deletedJobLines.push(a);
setUpdateLoading(false); }
}; });
if (error) return <AlertComponent message={error.message} type="error" />; deletedJobLines.forEach((d) => {
if (!search.billid) return <></>; //<div>{t("bills.labels.noneselected")}</div>; updates.push(deleteBillLine({variables: {id: d.id}}));
});
const exported = data && data.bills_by_pk && data.bills_by_pk.exported; billlines.forEach((billline) => {
const {deductedfromlbr, inventories, jobline, ...il} = billline;
delete il.__typename;
return ( if (il.id) {
<> updates.push(
{loading && <LoadingSkeleton />} updateBillLine({
{data && ( variables: {
billLineId: il.id,
billLine: {
...il,
deductedfromlbr: deductedfromlbr,
joblineid: il.joblineid === "noline" ? null : il.joblineid,
},
},
})
);
} else {
//It's a new line, have to insert it.
updates.push(
insertBillLine({
variables: {
billLines: [
{
...il,
deductedfromlbr: deductedfromlbr,
billid: search.billid,
joblineid: il.joblineid === "noline" ? null : il.joblineid,
},
],
},
})
);
}
});
await Promise.all(updates);
insertAuditTrail({
jobid: bill.jobid,
billid: search.billid,
operation: AuditTrailMapping.billupdated(bill.invoice_number),
});
await refetch();
form.setFieldsValue(transformData(data));
form.resetFields();
setVisible(false);
setUpdateLoading(false);
};
if (error) return <AlertComponent message={error.message} type="error"/>;
if (!search.billid) return <></>; //<div>{t("bills.labels.noneselected")}</div>;
const exported = data && data.bills_by_pk && data.bills_by_pk.exported;
return (
<> <>
<PageHeader {loading && <LoadingSkeleton/>}
title={ {data && (
data && <>
`${data.bills_by_pk.invoice_number} - ${data.bills_by_pk.vendor.name}` <PageHeader
} title={
extra={ data &&
<Space> `${data.bills_by_pk.invoice_number} - ${data.bills_by_pk.vendor.name}`
<BillDetailEditReturn data={data} /> }
extra={
<Space>
<BillDetailEditReturn data={data}/>
<Popconfirm <Popconfirm
open={visible} open={visible}
onConfirm={() => form.submit()} onConfirm={() => form.submit()}
onCancel={() => setVisible(false)} onCancel={() => setVisible(false)}
okButtonProps={{ loading: updateLoading }} okButtonProps={{loading: updateLoading}}
title={t("bills.labels.editadjwarning")} title={t("bills.labels.editadjwarning")}
> >
<Button <Button
htmlType="submit" htmlType="submit"
disabled={exported} disabled={exported}
onClick={handleSave} onClick={handleSave}
loading={updateLoading} loading={updateLoading}
type="primary" type="primary"
> >
{t("general.actions.save")} {t("general.actions.save")}
</Button> </Button>
</Popconfirm> </Popconfirm>
<BillReeportButtonComponent bill={data && data.bills_by_pk} /> <BillReeportButtonComponent bill={data && data.bills_by_pk}/>
<BillMarkExportedButton bill={data && data.bills_by_pk} /> <BillMarkExportedButton bill={data && data.bills_by_pk}/>
</Space> </Space>
} }
/> />
<Form <Form
form={form} form={form}
onFinish={handleFinish} onFinish={handleFinish}
initialValues={transformData(data)} initialValues={transformData(data)}
layout="vertical" layout="vertical"
> >
<BillFormContainer form={form} billEdit disabled={exported} /> <BillFormContainer form={form} billEdit disabled={exported}/>
{bodyshop.uselocalmediaserver ? ( {bodyshop.uselocalmediaserver ? (
<JobsDocumentsLocalGallery <JobsDocumentsLocalGallery
job={{ id: data ? data.bills_by_pk.jobid : null }} job={{id: data ? data.bills_by_pk.jobid : null}}
invoice_number={data ? data.bills_by_pk.invoice_number : null} invoice_number={data ? data.bills_by_pk.invoice_number : null}
vendorid={data ? data.bills_by_pk.vendorid : null} vendorid={data ? data.bills_by_pk.vendorid : null}
/> />
) : ( ) : (
<JobDocumentsGallery <JobDocumentsGallery
jobId={data ? data.bills_by_pk.jobid : null} jobId={data ? data.bills_by_pk.jobid : null}
billId={search.billid} billId={search.billid}
documentsList={data ? data.bills_by_pk.documents : []} documentsList={data ? data.bills_by_pk.documents : []}
billsCallback={refetch} billsCallback={refetch}
/> />
)}
</Form>
</>
)} )}
</Form>
</> </>
)} );
</>
);
} }
const transformData = (data) => { const transformData = (data) => {
return data return data
? { ? {
...data.bills_by_pk, ...data.bills_by_pk,
billlines: data.bills_by_pk.billlines.map((i) => { billlines: data.bills_by_pk.billlines.map((i) => {
return { return {
...i, ...i,
joblineid: !!i.joblineid ? i.joblineid : "noline", joblineid: !!i.joblineid ? i.joblineid : "noline",
applicable_taxes: { applicable_taxes: {
federal: federal:
(i.applicable_taxes && i.applicable_taxes.federal) || false, (i.applicable_taxes && i.applicable_taxes.federal) || false,
state: (i.applicable_taxes && i.applicable_taxes.state) || false, state: (i.applicable_taxes && i.applicable_taxes.state) || false,
local: (i.applicable_taxes && i.applicable_taxes.local) || false, local: (i.applicable_taxes && i.applicable_taxes.local) || false,
}, },
}; };
}), }),
date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null, date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null,
} }
: {}; : {};
}; };

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useSearchParams, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { insertAuditTrail } from "../../redux/application/application.actions"; import { insertAuditTrail } from "../../redux/application/application.actions";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
@@ -32,7 +32,7 @@ export function BillDetailEditReturn({
data, data,
disabled, disabled,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -67,7 +67,7 @@ export function BillDetailEditReturn({
}); });
delete search.billid; delete search.billid;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
setVisible(false); setVisible(false);
}; };
useEffect(() => { useEffect(() => {

View File

@@ -1,11 +1,11 @@
import { Drawer, Grid } from "antd"; import { Drawer, Grid } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useSearchParams, useNavigate } from "react-router-dom";
import BillDetailEditComponent from "./bill-detail-edit-component"; import BillDetailEditComponent from "./bill-detail-edit-component";
export default function BillDetailEditcontainer() { export default function BillDetailEditcontainer() {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
@@ -29,7 +29,7 @@ export default function BillDetailEditcontainer() {
width={drawerPercentage} width={drawerPercentage}
onClose={() => { onClose={() => {
delete search.billid; delete search.billid;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
destroyOnClose destroyOnClose
open={search.billid} open={search.billid}

View File

@@ -13,7 +13,7 @@ import {
} from "../../redux/user/user.selectors"; } from "../../redux/user/user.selectors";
import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility"; import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility";
import queryString from "query-string"; import queryString from "query-string";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -35,7 +35,7 @@ export function BilllineAddInventory({
jobid, jobid,
}) { }) {
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const { billid } = queryString.parse(useLocation().search); const { billid } = queryString.parse(useSearchParams().toString());
const [insertInventoryLine] = useMutation(INSERT_INVENTORY_AND_CREDIT); const [insertInventoryLine] = useMutation(INSERT_INVENTORY_AND_CREDIT);

View File

@@ -2,14 +2,14 @@ import React, { useState } from "react";
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries"; import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string"; import queryString from "query-string";
import { useNavigate, useLocation } from "react-router-dom"; import { useSearchParams, useNavigate } from "react-router-dom";
import { Table, Input } from "antd"; import { Table, Input } from "antd";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
export default function BillsVendorsList() { export default function BillsVendorsList() {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const { loading, error, data } = useQuery(QUERY_ALL_VENDORS, { const { loading, error, data } = useQuery(QUERY_ALL_VENDORS, {

View File

@@ -3,7 +3,7 @@ import { Button, Card, Input, Space, Table, Typography } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
import { DateTimeFormatter } from "../../utils/DateFormatter"; import { DateTimeFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
@@ -40,7 +40,7 @@ export function ContractsList({
filteredInfo: { text: "" }, filteredInfo: { text: "" },
}); });
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { page } = search; const { page } = search;
const { t } = useTranslation(); const { t } = useTranslation();
@@ -164,7 +164,7 @@ export function ContractsList({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
return ( return (
@@ -179,7 +179,7 @@ export function ContractsList({
<Button <Button
onClick={() => { onClick={() => {
delete search.search; delete search.search;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -196,7 +196,7 @@ export function ContractsList({
placeholder={search.searh || t("general.labels.search")} placeholder={search.searh || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
search.search = value; search.search = value;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
/> />
</Space> </Space>

View File

@@ -2,7 +2,7 @@ import { Card, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useSearchParams, useNavigate } from "react-router-dom";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
@@ -11,7 +11,7 @@ export default function CourtesyCarContractListComponent({
contracts, contracts,
totalContracts, totalContracts,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder } = search; const { page, sortcolumn, sortorder } = search;
const history = useNavigate(); const history = useNavigate();
@@ -81,7 +81,7 @@ export default function CourtesyCarContractListComponent({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
return ( return (

View File

@@ -1,9 +1,8 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Card, Form, Result } from "antd"; import { Card, Form, Result } from "antd";
import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useSearchParams } from "react-router-dom";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom";
import { QUERY_CSI_RESPONSE_BY_PK } from "../../graphql/csi.queries"; import { QUERY_CSI_RESPONSE_BY_PK } from "../../graphql/csi.queries";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import ConfigFormComponents from "../config-form-components/config-form-components.component"; import ConfigFormComponents from "../config-form-components/config-form-components.component";
@@ -12,7 +11,7 @@ import LoadingSpinner from "../loading-spinner/loading-spinner.component";
export default function CsiResponseFormContainer() { export default function CsiResponseFormContainer() {
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = Form.useForm(); const [form] = Form.useForm();
const searchParams = queryString.parse(useLocation().search); const searchParams = Object.fromEntries(useSearchParams());
const { responseid } = searchParams; const { responseid } = searchParams;
const { loading, error, data } = useQuery(QUERY_CSI_RESPONSE_BY_PK, { const { loading, error, data } = useQuery(QUERY_CSI_RESPONSE_BY_PK, {
variables: { variables: {

View File

@@ -3,7 +3,7 @@ import { Button, Card, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useSearchParams, useNavigate } from "react-router-dom";
import { DateFormatter } from "../../utils/DateFormatter"; import { DateFormatter } from "../../utils/DateFormatter";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
@@ -15,7 +15,7 @@ export default function CsiResponseListPaginated({
responses, responses,
total, total,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { responseid, page, sortcolumn, sortorder } = search; const { responseid, page, sortcolumn, sortorder } = search;
const history = useNavigate(); const history = useNavigate();
const [state, setState] = useState({ const [state, setState] = useState({
@@ -80,18 +80,18 @@ export default function CsiResponseListPaginated({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
search.responseid = record.id; search.responseid = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
} else { } else {
delete search.responseid; delete search.responseid;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };
@@ -128,7 +128,7 @@ export default function CsiResponseListPaginated({
handleOnRowClick(record); handleOnRowClick(record);
}, // click row }, // click row
}; };
}} }}q
/> />
</Card> </Card>
); );

View File

@@ -2,7 +2,7 @@ import React from "react";
import { Form, Space } from "antd"; import { Form, Space } from "antd";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import {useLocation } from "react-router-dom"; import {useSearchParams } from "react-router-dom";
import "./form-fields-changed.styles.scss"; import "./form-fields-changed.styles.scss";
import Prompt from "../../utils/prompt"; import Prompt from "../../utils/prompt";
@@ -12,7 +12,7 @@ export default function FormsFieldChanged({ form, skipPrompt }) {
const handleReset = () => { const handleReset = () => {
form.resetFields(); form.resetFields();
}; };
const loc = useLocation(); const loc = useSearchParams();
//if (!form.isFieldsTouched()) return <></>; //if (!form.isFieldsTouched()) return <></>;
return ( return (
<Form.Item <Form.Item
@@ -26,7 +26,7 @@ export default function FormsFieldChanged({ form, skipPrompt }) {
return ( return (
<Space direction="vertical" style={{ width: "100%" }}> <Space direction="vertical" style={{ width: "100%" }}>
<Prompt <Prompt
when={skipPrompt ? false : true} when={!skipPrompt}
message={(location) => { message={(location) => {
if (loc.pathname === location.pathname) return false; if (loc.pathname === location.pathname) return false;
return t("general.messages.unsavedchangespopup"); return t("general.messages.unsavedchangespopup");

View File

@@ -201,7 +201,7 @@ export default function GlobalSearchOs() {
onSearch={handleSearch} onSearch={handleSearch}
defaultActiveFirstOption defaultActiveFirstOption
onSelect={(val, opt) => { onSelect={(val, opt) => {
history.push(opt.label.props.to); history(opt.label.props.to);
}} }}
onClear={() => setData([])} onClear={() => setData([])}
> >

View File

@@ -186,7 +186,7 @@ export default function GlobalSearch() {
onSearch={handleSearch} onSearch={handleSearch}
defaultActiveFirstOption defaultActiveFirstOption
onSelect={(val, opt) => { onSelect={(val, opt) => {
history.push(opt.label.props.to); history(opt.label.props.to);
}} }}
> >
<Input.Search <Input.Search

View File

@@ -1,229 +1,224 @@
import { EditFilled, SyncOutlined, FileAddFilled } from "@ant-design/icons"; import {EditFilled, FileAddFilled, SyncOutlined} from "@ant-design/icons";
import { Button, Card, Input, Space, Table, Typography } from "antd"; import {Button, Card, Input, Space, Table, Typography} from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import {useTranslation} from "react-i18next";
import { connect } from "react-redux"; import {connect} from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import {Link, useNavigate, useSearchParams} from "react-router-dom";
import { createStructuredSelector } from "reselect"; import {createStructuredSelector} from "reselect";
import { setModalContext } from "../../redux/modals/modals.actions"; import {setModalContext} from "../../redux/modals/modals.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import {selectBodyshop} from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
import InventoryBillRo from "../inventory-bill-ro/inventory-bill-ro.component"; import InventoryBillRo from "../inventory-bill-ro/inventory-bill-ro.component";
import InventoryLineDelete from "../inventory-line-delete/inventory-line-delete.component"; import InventoryLineDelete from "../inventory-line-delete/inventory-line-delete.component";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
//currentUser: selectCurrentUser //currentUser: selectCurrentUser
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setInventoryUpsertContext: (context) => setInventoryUpsertContext: (context) =>
dispatch(setModalContext({ context: context, modal: "inventoryUpsert" })), dispatch(setModalContext({context: context, modal: "inventoryUpsert"})),
}); });
export function JobsList({ export function JobsList({bodyshop, refetch, loading, jobs, total, setInventoryUpsertContext,}) {
bodyshop, const search = queryString.parse(useSearchParams().toString());
refetch, const {page, sortcolumn, sortorder} = search;
loading, const history = useNavigate();
jobs,
total,
setInventoryUpsertContext,
}) {
const search = queryString.parse(useLocation().search);
const { page, sortcolumn, sortorder } = search;
const history = useNavigate();
const { t } = useTranslation(); const {t} = useTranslation();
const columns = [ const columns = [
{ {
title: t("billlines.fields.line_desc"), title: t("billlines.fields.line_desc"),
dataIndex: "line_desc", dataIndex: "line_desc",
key: "line_desc", key: "line_desc",
sorter: true, //(a, b) => alphaSort(a.line_desc, b.line_desc), sorter: true, //(a, b) => alphaSort(a.line_desc, b.line_desc),
sortOrder: sortcolumn === "line_desc" && sortorder, sortOrder: sortcolumn === "line_desc" && sortorder,
render: (text, record) => render: (text, record) =>
record.billline?.bill?.job ? ( record.billline?.bill?.job ? (
<div> <div>
<div>{text}</div> <div>{text}</div>
<strong>{`(${record.billline?.bill?.job?.v_model_yr} ${record.billline?.bill?.job?.v_make_desc} ${record.billline?.bill?.job?.v_model_desc})`}</strong> <strong>{`(${record.billline?.bill?.job?.v_model_yr} ${record.billline?.bill?.job?.v_make_desc} ${record.billline?.bill?.job?.v_model_desc})`}</strong>
</div> </div>
) : ( ) : (
text text
), ),
}, },
{ {
title: t("inventory.labels.frombillinvoicenumber"), title: t("inventory.labels.frombillinvoicenumber"),
dataIndex: "vendorname", dataIndex: "vendorname",
key: "vendorname", key: "vendorname",
ellipsis: true, ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder, //sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => render: (text, record) =>
( (
(record.billline?.bill?.invoice_number || "") + (record.billline?.bill?.invoice_number || "") +
" " + " " +
(record.manualinvoicenumber || "") (record.manualinvoicenumber || "")
).trim(), ).trim(),
}, },
{ {
title: t("inventory.labels.fromvendor"), title: t("inventory.labels.fromvendor"),
dataIndex: "vendorname", dataIndex: "vendorname",
key: "vendorname", key: "vendorname",
ellipsis: true, ellipsis: true,
//sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln), //sorter: true, // (a, b) => alphaSort(a.ownr_ln, b.ownr_ln),
//sortOrder: sortcolumn === "ownr_ln" && sortorder, //sortOrder: sortcolumn === "ownr_ln" && sortorder,
render: (text, record) => render: (text, record) =>
( (
(record.billline?.bill?.vendor?.name || "") + (record.billline?.bill?.vendor?.name || "") +
" " + " " +
(record.manualvendor || "") (record.manualvendor || "")
).trim(), ).trim(),
}, },
{ {
title: t("billlines.fields.actual_price"), title: t("billlines.fields.actual_price"),
dataIndex: "actual_price", dataIndex: "actual_price",
key: "actual_price", key: "actual_price",
render: (text, record) => ( render: (text, record) => (
<CurrencyFormatter>{record.actual_price}</CurrencyFormatter> <CurrencyFormatter>{record.actual_price}</CurrencyFormatter>
), ),
}, },
{ {
title: t("billlines.fields.actual_cost"), title: t("billlines.fields.actual_cost"),
dataIndex: "actual_cost", dataIndex: "actual_cost",
key: "actual_cost", key: "actual_cost",
render: (text, record) => ( render: (text, record) => (
<CurrencyFormatter>{record.actual_cost}</CurrencyFormatter> <CurrencyFormatter>{record.actual_cost}</CurrencyFormatter>
), ),
}, },
{ {
title: t("inventory.fields.comment"), title: t("inventory.fields.comment"),
dataIndex: "comment", dataIndex: "comment",
key: "comment", key: "comment",
}, },
{ {
title: t("inventory.labels.consumedbyjob"), title: t("inventory.labels.consumedbyjob"),
dataIndex: "consumedbyjob", dataIndex: "consumedbyjob",
key: "consumedbyjob", key: "consumedbyjob",
ellipsis: true, ellipsis: true,
render: (text, record) => render: (text, record) =>
record.bill?.job?.ro_number ? ( record.bill?.job?.ro_number ? (
<Link to={`/manage/jobs/${record.bill?.job?.id}`}> <Link to={`/manage/jobs/${record.bill?.job?.id}`}>
{record.bill?.job?.ro_number} {record.bill?.job?.ro_number}
</Link> </Link>
) : ( ) : (
<InventoryBillRo inventoryline={record} /> <InventoryBillRo inventoryline={record}/>
), ),
}, },
{ {
title: t("general.labels.actions"), title: t("general.labels.actions"),
dataIndex: "actions", dataIndex: "actions",
key: "actions", key: "actions",
ellipsis: true, ellipsis: true,
render: (text, record) => ( render: (text, record) => (
<Space wrap> <Space wrap>
<Button <Button
onClick={() => { onClick={() => {
setInventoryUpsertContext({ setInventoryUpsertContext({
actions: { refetch: refetch }, actions: {refetch: refetch},
context: { context: {
existingInventory: record, existingInventory: record,
}, },
}); });
}} }}
> >
<EditFilled /> <EditFilled/>
</Button> </Button>
<InventoryLineDelete inventoryline={record} refetch={refetch} /> <InventoryLineDelete inventoryline={record} refetch={refetch}/>
</Space> </Space>
), ),
}, },
]; ];
const handleTableChange = (pagination, filters, sorter) => { const handleTableChange = (pagination, filters, sorter) => {
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.column && sorter.column.key; search.sortcolumn = sorter.column && sorter.column.key;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({search: queryString.stringify(search)});
}; };
return ( return (
<Card <Card
extra={ extra={
<Space wrap> <Space wrap>
{search.search && ( {search.search && (
<> <>
<Typography.Title level={4}> <Typography.Title level={4}>
{t("general.labels.searchresults", { search: search.search })} {t("general.labels.searchresults", {search: search.search})}
</Typography.Title> </Typography.Title>
<Button <Button
onClick={() => { onClick={() => {
delete search.search; delete search.search;
history.push({ search: queryString.stringify(search) }); history({search: queryString.stringify(search)});
}}
>
{t("general.actions.clear")}
</Button>
</>
)}
<Button
onClick={() => {
setInventoryUpsertContext({
actions: {refetch: refetch},
context: {},
});
}}
>
<FileAddFilled/>
</Button>
<Button
onClick={() => {
if (search.showall) delete search.showall;
else {
search.showall = true;
}
history({search: queryString.stringify(search)});
}}
>
{search.showall
? t("inventory.labels.showavailable")
: t("inventory.labels.showall")}
</Button>
<Button onClick={() => refetch()}>
<SyncOutlined/>
</Button>
<Input.Search
placeholder={search.search || t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history({search: queryString.stringify(search)});
}}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: pageLimit,
current: parseInt(page || 1),
total: total,
}} }}
> columns={columns}
{t("general.actions.clear")} rowKey="id"
</Button> dataSource={jobs}
</> onChange={handleTableChange}
)} />
<Button </Card>
onClick={() => { );
setInventoryUpsertContext({
actions: { refetch: refetch },
context: {},
});
}}
>
<FileAddFilled />
</Button>
<Button
onClick={() => {
if (search.showall) delete search.showall;
else {
search.showall = true;
}
history.push({ search: queryString.stringify(search) });
}}
>
{search.showall
? t("inventory.labels.showavailable")
: t("inventory.labels.showall")}
</Button>
<Button onClick={() => refetch()}>
<SyncOutlined />
</Button>
<Input.Search
placeholder={search.search || t("general.labels.search")}
onSearch={(value) => {
search.search = value;
history.push({ search: queryString.stringify(search) });
}}
enterButton
/>
</Space>
}
>
<Table
loading={loading}
pagination={{
position: "top",
pageSize: pageLimit,
current: parseInt(page || 1),
total: total,
}}
columns={columns}
rowKey="id"
dataSource={jobs}
onChange={handleTableChange}
/>
</Card>
);
} }
export default connect(mapStateToProps, mapDispatchToProps)(JobsList); export default connect(mapStateToProps, mapDispatchToProps)(JobsList);

View File

@@ -2,7 +2,7 @@ import { useQuery } from "@apollo/client";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_INVENTORY_PAGINATED } from "../../graphql/inventory.queries"; import { QUERY_INVENTORY_PAGINATED } from "../../graphql/inventory.queries";
import { import {
@@ -23,7 +23,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function InventoryList({ setBreadcrumbs, setSelectedHeader }) { export function InventoryList({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search, showall } = searchParams; const { page, sortcolumn, sortorder, search, showall } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(

View File

@@ -17,7 +17,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { import {
openChatByPhone, openChatByPhone,
@@ -60,7 +60,7 @@ export function ScheduleEventComponent({
const { t } = useTranslation(); const { t } = useTranslation();
const [visible, setVisible] = useState(false); const [visible, setVisible] = useState(false);
const history = useNavigate(); const history = useNavigate();
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const [updateAppointment] = useMutation(UPDATE_APPOINTMENT); const [updateAppointment] = useMutation(UPDATE_APPOINTMENT);
const [title, setTitle] = useState(event.title); const [title, setTitle] = useState(event.title);
const blockContent = ( const blockContent = (
@@ -172,7 +172,7 @@ export function ScheduleEventComponent({
{event.job ? ( {event.job ? (
<Button <Button
onClick={() => { onClick={() => {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
selected: event.job.id, selected: event.job.id,

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation, useParams } from "react-router-dom"; import { useSearchParams, useNavigate, useParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../../../firebase/firebase.utils"; import { logImEXEvent } from "../../../../firebase/firebase.utils";
import { import {
@@ -50,7 +50,7 @@ export function JobChecklistForm({
const { jobId } = useParams(); const { jobId } = useParams();
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const [form] = Form.useForm(); const [form] = Form.useForm();
const handleFinish = async (values) => { const handleFinish = async (values) => {
@@ -172,7 +172,7 @@ export function JobChecklistForm({
if (!!!result.errors) { if (!!!result.errors) {
notification["success"]({ message: t("checklist.successes.completed") }); notification["success"]({ message: t("checklist.successes.completed") });
history.push(`/manage/jobs/${jobId}`); history(`/manage/jobs/${jobId}`);
insertAuditTrail({ insertAuditTrail({
jobid: jobId, jobid: jobId,

View File

@@ -50,7 +50,7 @@ export function JobCreateIOU({ bodyshop, currentUser, job, selectedJobLines }) {
notification.open({ notification.open({
type: "success", type: "success",
message: t("jobs.successes.ioucreated"), message: t("jobs.successes.ioucreated"),
onClick: () => history.push(`/manage/jobs/${iouId}`), onClick: () => history(`/manage/jobs/${iouId}`),
}); });
const selectedJobLinesIds = selectedJobLines.map((l) => l.id); const selectedJobLinesIds = selectedJobLines.map((l) => l.id);
await client.mutate({ await client.mutate({

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries"; import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
@@ -54,7 +54,7 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
? bpoints[selectedBreakpoint[0]] ? bpoints[selectedBreakpoint[0]]
: "100%"; : "100%";
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { selected } = searchParams; const { selected } = searchParams;
const history = useNavigate(); const history = useNavigate();
const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, { const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, {
@@ -67,7 +67,7 @@ export function JobDetailCards({ bodyshop, setPrintCenterContext }) {
const { t } = useTranslation(); const { t } = useTranslation();
const handleDrawerClose = () => { const handleDrawerClose = () => {
delete searchParams.selected; delete searchParams.selected;
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
}), }),

View File

@@ -8,7 +8,7 @@ export default function JobSyncButton({ job }) {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useNavigate(); const history = useNavigate();
const handleClick = () => { const handleClick = () => {
history.push( history(
`/manage/available?availableJobId=${job.available_jobs[0].id}&clm_no=${job.clm_no}` `/manage/available?availableJobId=${job.available_jobs[0].id}&clm_no=${job.clm_no}`
); );
}; };

View File

@@ -14,7 +14,7 @@ import queryString from "query-string";
import React, { useCallback, useEffect, useState } from "react"; import React, { useCallback, useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { import {
@@ -64,7 +64,7 @@ export function JobsAvailableContainer({
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const { clm_no, availableJobId } = queryString.parse(useLocation().search); const { clm_no, availableJobId } = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
@@ -174,7 +174,7 @@ export function JobsAvailableContainer({
notification["success"]({ notification["success"]({
message: t("jobs.successes.created"), message: t("jobs.successes.created"),
onClick: () => { onClick: () => {
history.push(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`); history(`/manage/jobs/${r.data.insert_jobs.returning[0].id}`);
}, },
}); });
//Job has been inserted. Clean up the available jobs record. //Job has been inserted. Clean up the available jobs record.
@@ -292,7 +292,7 @@ export function JobsAvailableContainer({
notification["success"]({ notification["success"]({
message: t("jobs.successes.supplemented"), message: t("jobs.successes.supplemented"),
onClick: () => { onClick: () => {
history.push( history(
`/manage/jobs/${updateResult.data.update_jobs.returning[0].id}` `/manage/jobs/${updateResult.data.update_jobs.returning[0].id}`
); );
}, },

View File

@@ -50,7 +50,7 @@ export function JobsCloseExportButton({
const handleQbxml = async () => { const handleQbxml = async () => {
//Check if it's a CDK setup. //Check if it's a CDK setup.
if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) { if (bodyshop.cdk_dealerid || bodyshop.pbs_serialnumber) {
history.push(`/manage/dms?jobId=${jobId}`); history(`/manage/dms?jobId=${jobId}`);
return; return;
} }
logImEXEvent("jobs_close_export"); logImEXEvent("jobs_close_export");

View File

@@ -344,7 +344,7 @@ export function JobsDetailHeaderActions({
job.id, job.id,
{ defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported },
(newJobId) => { (newJobId) => {
history.push(`/manage/jobs/${newJobId}`); history(`/manage/jobs/${newJobId}`);
notification["success"]({ notification["success"]({
message: t("jobs.successes.duplicated"), message: t("jobs.successes.duplicated"),
}); });
@@ -369,7 +369,7 @@ export function JobsDetailHeaderActions({
job.id, job.id,
{ defaultOpenStatus: bodyshop.md_ro_statuses.default_imported }, { defaultOpenStatus: bodyshop.md_ro_statuses.default_imported },
(newJobId) => { (newJobId) => {
history.push(`/manage/jobs/${newJobId}`); history(`/manage/jobs/${newJobId}`);
notification["success"]({ notification["success"]({
message: t("jobs.successes.duplicated"), message: t("jobs.successes.duplicated"),
}); });
@@ -480,7 +480,7 @@ export function JobsDetailHeaderActions({
message: t("jobs.successes.delete"), message: t("jobs.successes.delete"),
}); });
//go back to jobs list. //go back to jobs list.
history.push(`/manage/`); history(`/manage/`);
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.deleted", { message: t("jobs.errors.deleted", {
@@ -533,7 +533,7 @@ export function JobsDetailHeaderActions({
message: t("jobs.successes.voided"), message: t("jobs.successes.voided"),
}); });
//go back to jobs list. //go back to jobs list.
history.push(`/manage/`); history(`/manage/`);
} else { } else {
notification["error"]({ notification["error"]({
message: t("jobs.errors.voiding", { message: t("jobs.errors.voiding", {

View File

@@ -1,7 +1,7 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries"; import { QUERY_BILLS_BY_JOBID } from "../../graphql/bills.queries";
import JobsDetailPliComponent from "./jobs-detail-pli.component"; import JobsDetailPliComponent from "./jobs-detail-pli.component";
@@ -12,18 +12,18 @@ export default function JobsDetailPliContainer({ job }) {
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const handleBillOnRowClick = (record) => { const handleBillOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
search.billid = record.id; search.billid = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
} else { } else {
delete search.billid; delete search.billid;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };
@@ -31,11 +31,11 @@ export default function JobsDetailPliContainer({ job }) {
if (record) { if (record) {
if (record.id) { if (record.id) {
search.partsorderid = record.id; search.partsorderid = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
} else { } else {
delete search.partsorderid; delete search.partsorderid;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import CurrencyFormatter from "../../utils/CurrencyFormatter"; import CurrencyFormatter from "../../utils/CurrencyFormatter";
@@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function JobsList({ bodyshop, refetch, loading, jobs, total }) { export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const [openSearchResults, setOpenSearchResults] = useState([]); const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const { page, sortcolumn, sortorder } = search; const { page, sortcolumn, sortorder } = search;
@@ -189,7 +189,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
} else { } else {
delete search.statusFilters; delete search.statusFilters;
} }
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
useEffect(() => { useEffect(() => {
@@ -227,7 +227,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
onClick={() => { onClick={() => {
delete search.search; delete search.search;
delete search.page; delete search.page;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -241,7 +241,7 @@ export function JobsList({ bodyshop, refetch, loading, jobs, total }) {
placeholder={search.search || t("general.labels.search")} placeholder={search.search || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
search.search = value; search.search = value;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
searchJobs(value); searchJobs(value);
}} }}
loading={loading || searchLoading} loading={loading || searchLoading}

View File

@@ -10,7 +10,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -26,7 +26,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function JobsList({ bodyshop }) { export function JobsList({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { selected } = searchParams; const { selected } = searchParams;
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
@@ -97,7 +97,7 @@ export function JobsList({ bodyshop }) {
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
selected: record.id, selected: record.id,

View File

@@ -10,7 +10,7 @@ import queryString from "query-string";
import React, { useMemo, useState } from "react"; import React, { useMemo, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -27,7 +27,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function JobsReadyList({ bodyshop }) { export function JobsReadyList({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { selected } = searchParams; const { selected } = searchParams;
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
@@ -111,7 +111,7 @@ export function JobsReadyList({ bodyshop }) {
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
selected: record.id, selected: record.id,

View File

@@ -32,7 +32,7 @@ function OwnerDetailFormContainer({ owner, refetch }) {
message: t("owners.successes.delete"), message: t("owners.successes.delete"),
}); });
setLoading(false); setLoading(false);
history.push(`/manage/owners`); history(`/manage/owners`);
} }
}; };

View File

@@ -3,7 +3,7 @@ import { Button, Card, Input, Space, Table, Typography } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import PhoneFormatter from "../../utils/PhoneFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter";
import OwnerNameDisplay from "../owner-name-display/owner-name-display.component"; import OwnerNameDisplay from "../owner-name-display/owner-name-display.component";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
@@ -14,7 +14,7 @@ export default function OwnersListComponent({
total, total,
refetch, refetch,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { const {
page, page,
// sortcolumn, sortorder // sortcolumn, sortorder
@@ -79,7 +79,7 @@ export default function OwnersListComponent({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
return ( return (
<Card <Card
@@ -94,7 +94,7 @@ export default function OwnersListComponent({
<Button <Button
onClick={() => { onClick={() => {
delete search.search; delete search.search;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -112,7 +112,7 @@ export default function OwnersListComponent({
} else { } else {
delete search.search; delete search.search;
} }
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
enterButton enterButton
/> />

View File

@@ -4,11 +4,11 @@ import { QUERY_ALL_OWNERS_PAGINATED } from "../../graphql/owners.queries";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import OwnersListComponent from "./owners-list.component"; import OwnersListComponent from "./owners-list.component";
import queryString from "query-string"; import queryString from "query-string";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
export default function OwnersListContainer() { export default function OwnersListContainer() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search } = searchParams; const { page, sortcolumn, sortorder, search } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(
QUERY_ALL_OWNERS_PAGINATED, QUERY_ALL_OWNERS_PAGINATED,

View File

@@ -16,7 +16,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries"; import { DELETE_PARTS_ORDER } from "../../graphql/parts-orders.queries";
@@ -78,7 +78,7 @@ export function PartsOrderListTableComponent({
const [state, setState] = useState({ const [state, setState] = useState({
sortedInfo: {}, sortedInfo: {},
}); });
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const selectedpartsorder = search.partsorderid; const selectedpartsorder = search.partsorderid;
const [searchText, setSearchText] = useState(""); const [searchText, setSearchText] = useState("");

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_PAYMENT_BY_ID } from "../../graphql/payments.queries"; import { QUERY_PAYMENT_BY_ID } from "../../graphql/payments.queries";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
@@ -42,7 +42,7 @@ export function PaymentsListPaginated({
total, total,
bodyshop, bodyshop,
}) { }) {
const search = queryString.parse(useLocation().search); const search =queryString.parse(useSearchParams().toString());
const [openSearchResults, setOpenSearchResults] = useState([]); const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const { page, sortcolumn, sortorder } = search; const { page, sortcolumn, sortorder } = search;
@@ -208,7 +208,7 @@ export function PaymentsListPaginated({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
useEffect(() => { useEffect(() => {
@@ -246,7 +246,7 @@ export function PaymentsListPaginated({
onClick={() => { onClick={() => {
delete search.search; delete search.search;
delete search.page; delete search.page;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -268,7 +268,7 @@ export function PaymentsListPaginated({
placeholder={search.search || t("general.labels.search")} placeholder={search.search || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
search.search = value; search.search = value;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
searchPayments(value); searchPayments(value);
}} }}
loading={loading || searchLoading} loading={loading || searchLoading}

View File

@@ -4,7 +4,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { import {
DELETE_PHONEBOOK, DELETE_PHONEBOOK,
@@ -23,7 +23,7 @@ const mapStateToProps = createStructuredSelector({
function PhonebookFormContainer({ refetch, bodyshop }) { function PhonebookFormContainer({ refetch, bodyshop }) {
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { phonebookentry } = search; const { phonebookentry } = search;
const [formLoading, setFormLoading] = useState(false); const [formLoading, setFormLoading] = useState(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -51,7 +51,7 @@ function PhonebookFormContainer({ refetch, bodyshop }) {
message: t("phonebook.successes.deleted"), message: t("phonebook.successes.deleted"),
}); });
delete search.phonebookentry; delete search.phonebookentry;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
if (refetch) if (refetch)
refetch().then((r) => { refetch().then((r) => {
form.resetFields(); form.resetFields();
@@ -113,7 +113,7 @@ function PhonebookFormContainer({ refetch, bodyshop }) {
form.resetFields(); form.resetFields();
form.resetFields(); form.resetFields();
delete search.phonebookentry; delete search.phonebookentry;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
setFormLoading(false); setFormLoading(false);
} else { } else {
notification["error"]({ notification["error"]({

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries"; import { QUERY_JOB_CARD_DETAILS } from "../../graphql/jobs.queries";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
@@ -44,7 +44,7 @@ export function ProductionListDetail({
setPrintCenterContext, setPrintCenterContext,
technician, technician,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const { selected } = search; const { selected } = search;
@@ -53,7 +53,7 @@ export function ProductionListDetail({
const handleClose = () => { const handleClose = () => {
delete search.selected; delete search.selected;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, { const { loading, error, data, refetch } = useQuery(QUERY_JOB_CARD_DETAILS, {
variables: { id: selected }, variables: { id: selected },

View File

@@ -5,13 +5,13 @@ import { useTranslation } from "react-i18next";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { UPDATE_JOB } from "../../graphql/jobs.queries"; import { UPDATE_JOB } from "../../graphql/jobs.queries";
import queryString from "query-string"; import queryString from "query-string";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
export default function ProductionRemoveButton({ jobId }) { export default function ProductionRemoveButton({ jobId }) {
const [removeJobFromProduction] = useMutation(UPDATE_JOB); const [removeJobFromProduction] = useMutation(UPDATE_JOB);
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const handleRemoveFromProd = async () => { const handleRemoveFromProd = async () => {
@@ -24,7 +24,7 @@ export default function ProductionRemoveButton({ jobId }) {
if (!!!result.errors) { if (!!!result.errors) {
notification["success"]({ message: t("production.successes.removed") }); notification["success"]({ message: t("production.successes.removed") });
delete search.selected; delete search.selected;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} else { } else {
notification["error"]({ notification["error"]({
message: t("production.errors.removing", { message: t("production.errors.removing", {

View File

@@ -3,19 +3,19 @@ import Axios from "axios";
import queryString from "query-string"; import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useCookies } from "react-cookie"; import { useCookies } from "react-cookie";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import QboSignIn from "../../assets/qbo/C2QB_green_btn_med_default.svg"; import QboSignIn from "../../assets/qbo/C2QB_green_btn_med_default.svg";
export default function QboAuthorizeComponent() { export default function QboAuthorizeComponent() {
const location = useLocation(); const location = useSearchParams();
const history = useNavigate(); const history = useNavigate();
const [, setCookie] = useCookies(["access_token", "refresh_token"]); const [setCookie] = useCookies(["access_token", "refresh_token"]);
const handleQbSignIn = async () => { const handleQbSignIn = async () => {
const result = await Axios.post("/qbo/authorize"); const result = await Axios.post("/qbo/authorize");
window.location.href = result.data; window.location.href = result.data;
}; };
const qs = queryString.parse(location.search); const qs = queryString.parse(location.toString());
const { error } = qs; const { error } = qs;
@@ -39,7 +39,7 @@ export default function QboAuthorizeComponent() {
// : {}), // : {}),
// }); // });
history.push({ pathname: `/manage/accounting/receivables` }); history({ pathname: `/manage/accounting/receivables` });
} }
// eslint-disable-next-line react-hooks/exhaustive-deps // eslint-disable-next-line react-hooks/exhaustive-deps
}, [qs, location, setCookie]); }, [qs, location, setCookie]);

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { Calendar, momentLocalizer } from "react-big-calendar"; import { Calendar, momentLocalizer } from "react-big-calendar";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import Event from "../job-at-change/schedule-event.container"; import Event from "../job-at-change/schedule-event.container";
@@ -30,7 +30,7 @@ export function ScheduleCalendarWrapperComponent({
date, date,
...otherProps ...otherProps
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const handleEventPropStyles = (event, start, end, isSelected) => { const handleEventPropStyles = (event, start, end, isSelected) => {
@@ -113,14 +113,14 @@ export function ScheduleCalendarWrapperComponent({
date={selectedDate} date={selectedDate}
onNavigate={(date, view, action) => { onNavigate={(date, view, action) => {
search.date = date.toISOString().substr(0, 10); search.date = date.toISOString().substr(0, 10);
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
onRangeChange={(start, end) => { onRangeChange={(start, end) => {
if (setDateRangeCallback) setDateRangeCallback({ start, end }); if (setDateRangeCallback) setDateRangeCallback({ start, end });
}} }}
onView={(view) => { onView={(view) => {
search.view = view; search.view = view;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
step={15} step={15}
// timeslots={1} // timeslots={1}

View File

@@ -1,7 +1,7 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string"; import queryString from "query-string";
import React, { useMemo, useEffect } from "react"; import React, { useMemo, useEffect } from "react";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { QUERY_ALL_ACTIVE_APPOINTMENTS } from "../../graphql/appointments.queries"; import { QUERY_ALL_ACTIVE_APPOINTMENTS } from "../../graphql/appointments.queries";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
@@ -19,7 +19,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function ScheduleCalendarContainer({ calculateScheduleLoad }) { export function ScheduleCalendarContainer({ calculateScheduleLoad }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { date, view } = search; const { date, view } = search;
const range = useMemo(() => getRange(date, view), [date, view]); const range = useMemo(() => getRange(date, view), [date, view]);

View File

@@ -4,7 +4,7 @@ import _ from "lodash";
import moment from "moment"; import moment from "moment";
import queryString from "query-string"; import queryString from "query-string";
import React, { useMemo } from "react"; import React, { useMemo } from "react";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries"; import { QUERY_TIME_TICKETS_IN_RANGE_SB } from "../../graphql/timetickets.queries";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import LoadingSpinner from "../loading-spinner/loading-spinner.component"; import LoadingSpinner from "../loading-spinner/loading-spinner.component";
@@ -13,7 +13,7 @@ import ScoreboardTicketsBar from "./scoreboard-timetickets.bar.component";
import ScoreboardTicketsStats from "./scoreboard-timetickets.stats.component"; import ScoreboardTicketsStats from "./scoreboard-timetickets.stats.component";
export default function ScoreboardTimeTickets() { export default function ScoreboardTimeTickets() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { start, end } = searchParams; const { start, end } = searchParams;
const startDate = start const startDate = start
? moment(start) ? moment(start)

View File

@@ -13,11 +13,10 @@ import {
} from "antd"; } from "antd";
import { useForm } from "antd/es/form/Form"; import { useForm } from "antd/es/form/Form";
import moment from "moment"; import moment from "moment";
import querystring from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { import {
@@ -36,6 +35,7 @@ import FormDatePicker from "../form-date-picker/form-date-picker.component";
import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component"; import FormListMoveArrows from "../form-list-move-arrows/form-list-move-arrows.component";
import LayoutFormRow from "../layout-form-row/layout-form-row.component"; import LayoutFormRow from "../layout-form-row/layout-form-row.component";
import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component"; import ShopEmployeeAddVacation from "./shop-employees-add-vacation.component";
import queryString from "query-string";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -48,7 +48,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
const { t } = useTranslation(); const { t } = useTranslation();
const [form] = useForm(); const [form] = useForm();
const history = useNavigate(); const history = useNavigate();
const search = querystring.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const [deleteVacation] = useMutation(DELETE_VACATION); const [deleteVacation] = useMutation(DELETE_VACATION);
const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, { const { error, data } = useQuery(QUERY_EMPLOYEE_BY_ID, {
variables: { id: search.employeeId }, variables: { id: search.employeeId },
@@ -103,7 +103,7 @@ export function ShopEmployeesFormComponent({ bodyshop }) {
refetchQueries: ["QUERY_EMPLOYEES"], refetchQueries: ["QUERY_EMPLOYEES"],
}).then((r) => { }).then((r) => {
search.employeeId = r.data.insert_employees.returning[0].id; search.employeeId = r.data.insert_employees.returning[0].id;
history.push({ search: querystring.stringify(search) }); history({ search: queryString.stringify(search) });
notification["success"]({ notification["success"]({
message: t("employees.successes.save"), message: t("employees.successes.save"),
}); });

View File

@@ -2,20 +2,20 @@ import { Button, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
export default function ShopEmployeesListComponent({ loading, employees }) { export default function ShopEmployeesListComponent({ loading, employees }) {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
search.employeeId = record.id; search.employeeId = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} else { } else {
delete search.employeeId; delete search.employeeId;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };
const columns = [ const columns = [
@@ -54,7 +54,7 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
type="primary" type="primary"
onClick={() => { onClick={() => {
search.employeeId = "new"; search.employeeId = "new";
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("employees.actions.new")} {t("employees.actions.new")}
@@ -69,7 +69,7 @@ export default function ShopEmployeesListComponent({ loading, employees }) {
rowSelection={{ rowSelection={{
onSelect: (props) => { onSelect: (props) => {
search.employeeId = props.id; search.employeeId = props.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}, },
type: "radio", type: "radio",
selectedRowKeys: [search.employeeId], selectedRowKeys: [search.employeeId],

View File

@@ -15,7 +15,7 @@ import ShopInfoResponsibilityCenterComponent from "./shop-info.responsibilitycen
import ShopInfoROStatusComponent from "./shop-info.rostatus.component"; import ShopInfoROStatusComponent from "./shop-info.rostatus.component";
import ShopInfoSchedulingComponent from "./shop-info.scheduling.component"; import ShopInfoSchedulingComponent from "./shop-info.scheduling.component";
import ShopInfoSpeedPrint from "./shop-info.speedprint.component"; import ShopInfoSpeedPrint from "./shop-info.speedprint.component";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import queryString from "query-string"; import queryString from "query-string";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
@@ -34,8 +34,8 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
); );
const { t } = useTranslation(); const { t } = useTranslation();
const history = useNavigate(); const history = useNavigate();
const location = useLocation(); const location = useSearchParams();
const search = queryString.parse(location.search); const search = queryString.parse(location.toString());
return ( return (
<Card <Card
@@ -52,7 +52,7 @@ export function ShopInfoComponent({ bodyshop, form, saveLoading }) {
<Tabs <Tabs
defaultActiveKey={search.subtab} defaultActiveKey={search.subtab}
onChange={(key) => onChange={(key) =>
history.push({ history({
search: `?tab=${search.tab}&subtab=${key}`, search: `?tab=${search.tab}&subtab=${key}`,
}) })
} }

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
import { import {
@@ -29,7 +29,7 @@ export function ShopTemplateAddComponent({
refetch, refetch,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const [insertTemplate] = useMutation(INSERT_TEMPLATE); const [insertTemplate] = useMutation(INSERT_TEMPLATE);
@@ -64,7 +64,7 @@ export function ShopTemplateAddComponent({
const returningId = result.data.insert_templates.returning[0].id; const returningId = result.data.insert_templates.returning[0].id;
search.customTemplateId = returningId; search.customTemplateId = returningId;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
if (!!refetch) refetch(); if (!!refetch) refetch();
}; };
const TemplateListGenerated = TemplateList(); const TemplateListGenerated = TemplateList();

View File

@@ -3,13 +3,13 @@ import { Button, notification, Popconfirm } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { DELETE_TEMPLATE } from "../../graphql/templates.queries"; import { DELETE_TEMPLATE } from "../../graphql/templates.queries";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
export default function ShopTemplateDeleteComponent({ templateId, refetch }) { export default function ShopTemplateDeleteComponent({ templateId, refetch }) {
const { t } = useTranslation(); const { t } = useTranslation();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const [deleteTemplate] = useMutation(DELETE_TEMPLATE); const [deleteTemplate] = useMutation(DELETE_TEMPLATE);
@@ -30,7 +30,7 @@ export default function ShopTemplateDeleteComponent({ templateId, refetch }) {
}); });
} else { } else {
delete search.customTemplateId; delete search.customTemplateId;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
if (!!refetch) refetch(); if (!!refetch) refetch();
} }
}; };

View File

@@ -5,7 +5,7 @@ import { QUERY_CUSTOM_TEMPLATES } from "../../graphql/templates.queries";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import Skeleton from "../loading-skeleton/loading-skeleton.component"; import Skeleton from "../loading-skeleton/loading-skeleton.component";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import queryString from "query-string"; import queryString from "query-string";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import ShopTemplateAdd from "../shop-template-add/shop-template-add.component"; import ShopTemplateAdd from "../shop-template-add/shop-template-add.component";
@@ -18,7 +18,7 @@ export default function ShopTemplatesListContainer({ visibleState }) {
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const { t } = useTranslation(); const { t } = useTranslation();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
@@ -26,11 +26,11 @@ export default function ShopTemplatesListContainer({ visibleState }) {
if (record) { if (record) {
if (record.id) { if (record.id) {
search.customTemplateId = record.id; search.customTemplateId = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
} else { } else {
delete search.customTemplateId; delete search.customTemplateId;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };

View File

@@ -1,10 +1,10 @@
import { LockOutlined, UserOutlined } from "@ant-design/icons"; import { LockOutlined, UserOutlined } from "@ant-design/icons";
import { Button, Form, Input, Typography } from "antd"; import { Button, Form, Input, Typography } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React, {useEffect} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import ImEXOnlineLogo from "../../assets/logo192.png"; import ImEXOnlineLogo from "../../assets/logo192.png";
import { import {
@@ -38,8 +38,10 @@ export function SignInComponent({
sendPasswordReset, sendPasswordReset,
loginLoading, loginLoading,
}) { }) {
const { redirect } = queryString.parse(useLocation().search); const [searchParams] = useSearchParams();
const redirect = searchParams.get("redirect");
const navigate = useNavigate(); const navigate = useNavigate();
const { t } = useTranslation(); const { t } = useTranslation();
const handleFinish = (values) => { const handleFinish = (values) => {
const { email, password } = values; const { email, password } = values;
@@ -47,8 +49,13 @@ export function SignInComponent({
}; };
const [form] = Form.useForm(); const [form] = Form.useForm();
if (currentUser.authorized === true) useEffect(() => {
return navigate("/manage"); console.log('navigating to ' + redirect || "/manage");
if (currentUser.authorized === true) {
navigate(redirect || "/manage");
}
}, [currentUser, redirect, navigate]);
return ( return (
<div className="login-container"> <div className="login-container">

View File

@@ -1,5 +1,5 @@
import { Button, Form, Input } from "antd"; import { Button, Form, Input } from "antd";
import React from "react"; import React, {useEffect} from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -36,7 +36,9 @@ export function TechLogin({
techLoginStart(values); techLoginStart(values);
}; };
if (technician) return navigate("/tech/joblookup"); useEffect(() => {
if (technician) return navigate("/tech/joblookup");
}, [technician, navigate]);
return ( return (
<div className="tech-login-container"> <div className="tech-login-container">

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
import { setModalContext } from "../../redux/modals/modals.actions"; import { setModalContext } from "../../redux/modals/modals.actions";
@@ -51,7 +51,7 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
? bpoints[selectedBreakpoint[0]] ? bpoints[selectedBreakpoint[0]]
: "100%"; : "100%";
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { selected } = searchParams; const { selected } = searchParams;
const history = useNavigate(); const history = useNavigate();
const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, { const { loading, error, data, refetch } = useQuery(GET_JOB_BY_PK, {
@@ -64,7 +64,7 @@ export function TechLookupJobsDrawer({ bodyshop, setPrintCenterContext }) {
const { t } = useTranslation(); const { t } = useTranslation();
const handleDrawerClose = () => { const handleDrawerClose = () => {
delete searchParams.selected; delete searchParams.selected;
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
}), }),

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
@@ -19,7 +19,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function TechLookupJobsList({ bodyshop }) { export function TechLookupJobsList({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { selected } = searchParams; const { selected } = searchParams;
const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, { const { loading, error, data, refetch } = useQuery(QUERY_ALL_ACTIVE_JOBS, {
@@ -80,7 +80,7 @@ export function TechLookupJobsList({ bodyshop }) {
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
if (record.id) { if (record.id) {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
selected: record.id, selected: record.id,

View File

@@ -3,10 +3,10 @@ import { DatePicker } from "antd";
import moment from "moment"; import moment from "moment";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
export default function TimeTicketsDatesSelector() { export default function TimeTicketsDatesSelector() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { start, end } = searchParams; const { start, end } = searchParams;
const history = useNavigate(); const history = useNavigate();
@@ -15,7 +15,7 @@ export default function TimeTicketsDatesSelector() {
const [start, end] = dates; const [start, end] = dates;
if (!!start && !!end) { if (!!start && !!end) {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
start: start.format("YYYY-MM-DD"), start: start.format("YYYY-MM-DD"),
@@ -24,7 +24,7 @@ export default function TimeTicketsDatesSelector() {
}); });
} }
} else { } else {
history.push({ history({
search: queryString.stringify({ search: queryString.stringify({
...searchParams, ...searchParams,
start: null, start: null,

View File

@@ -1,7 +1,7 @@
import { Button } from "antd"; import { Button } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { GenerateDocument } from "../../utils/RenderTemplate"; import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
@@ -9,7 +9,7 @@ import moment from "moment";
const AttendanceCsv = TemplateList("special").attendance_detail_csv; const AttendanceCsv = TemplateList("special").attendance_detail_csv;
export default function TimeTicketsAttendanceTable() { export default function TimeTicketsAttendanceTable() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { start, end } = searchParams; const { start, end } = searchParams;
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);

View File

@@ -1,14 +1,14 @@
import { Button } from "antd"; import { Button } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { GenerateDocument } from "../../utils/RenderTemplate"; import { GenerateDocument } from "../../utils/RenderTemplate";
import { TemplateList } from "../../utils/TemplateConstants"; import { TemplateList } from "../../utils/TemplateConstants";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import moment from "moment"; import moment from "moment";
const PayrollTemplate = TemplateList("special").exported_payroll; const PayrollTemplate = TemplateList("special").exported_payroll;
export default function TimeTicketsPayrollTable() { export default function TimeTicketsPayrollTable() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { start, end } = searchParams; const { start, end } = searchParams;
const { t } = useTranslation(); const { t } = useTranslation();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);

View File

@@ -33,7 +33,7 @@ function VehicleDetailFormContainer({ vehicle, refetch }) {
message: t("vehicles.successes.delete"), message: t("vehicles.successes.delete"),
}); });
setLoading(false); setLoading(false);
history.push(`/manage/vehicles`); history(`/manage/vehicles`);
} }
}; };

View File

@@ -3,7 +3,7 @@ import { Button, Card, Input, Space, Table, Typography } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component"; import VehicleVinDisplay from "../vehicle-vin-display/vehicle-vin-display.component";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
export default function VehiclesListComponent({ export default function VehiclesListComponent({
@@ -12,7 +12,7 @@ export default function VehiclesListComponent({
total, total,
refetch, refetch,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { const {
page, page,
//sortcolumn, sortorder, //sortcolumn, sortorder,
@@ -66,7 +66,7 @@ export default function VehiclesListComponent({
search.page = pagination.current; search.page = pagination.current;
search.sortcolumn = sorter.columnKey; search.sortcolumn = sorter.columnKey;
search.sortorder = sorter.order; search.sortorder = sorter.order;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
return ( return (
@@ -82,7 +82,7 @@ export default function VehiclesListComponent({
<Button <Button
onClick={() => { onClick={() => {
delete search.search; delete search.search;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -96,7 +96,7 @@ export default function VehiclesListComponent({
placeholder={search.search || t("general.labels.search")} placeholder={search.search || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
search.search = value; search.search = value;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
enterButton enterButton
/> />

View File

@@ -4,11 +4,11 @@ import { useQuery } from "@apollo/client";
import AlertComponent from "../alert/alert.component"; import AlertComponent from "../alert/alert.component";
import { QUERY_ALL_VEHICLES_PAGINATED } from "../../graphql/vehicles.queries"; import { QUERY_ALL_VEHICLES_PAGINATED } from "../../graphql/vehicles.queries";
import queryString from "query-string"; import queryString from "query-string";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
export default function VehiclesListContainer() { export default function VehiclesListContainer() {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search } = searchParams; const { page, sortcolumn, sortorder, search } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(

View File

@@ -4,7 +4,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { import {
DELETE_VENDOR, DELETE_VENDOR,
@@ -23,7 +23,7 @@ const mapStateToProps = createStructuredSelector({
function VendorsFormContainer({ refetch, bodyshop }) { function VendorsFormContainer({ refetch, bodyshop }) {
const history = useNavigate(); const history = useNavigate();
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { selectedvendor } = search; const { selectedvendor } = search;
const [formLoading, setFormLoading] = useState(false); const [formLoading, setFormLoading] = useState(false);
const [form] = Form.useForm(); const [form] = Form.useForm();
@@ -55,7 +55,7 @@ function VendorsFormContainer({ refetch, bodyshop }) {
message: t("vendors.successes.deleted"), message: t("vendors.successes.deleted"),
}); });
delete search.selectedvendor; delete search.selectedvendor;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
if (refetch) if (refetch)
refetch().then((r) => { refetch().then((r) => {
form.resetFields(); form.resetFields();
@@ -107,7 +107,7 @@ function VendorsFormContainer({ refetch, bodyshop }) {
form.resetFields(); form.resetFields();
form.resetFields(); form.resetFields();
delete search.selectedvendor; delete search.selectedvendor;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
setFormLoading(false); setFormLoading(false);
} else { } else {
notification["error"]({ notification["error"]({

View File

@@ -3,7 +3,7 @@ import { Button, Card, Input, Space, Table } from "antd";
import queryString from "query-string"; import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { alphaSort } from "../../utils/sorters"; import { alphaSort } from "../../utils/sorters";
export default function VendorsListComponent({ export default function VendorsListComponent({
@@ -13,7 +13,7 @@ export default function VendorsListComponent({
vendors, vendors,
refetch, refetch,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { selectedvendor } = search; const { selectedvendor } = search;
const [state, setState] = useState({ const [state, setState] = useState({

View File

@@ -1,7 +1,7 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string"; import queryString from "query-string";
import React from "react"; import React from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries"; import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries";
import VendorsListComponent from "./vendors-list.component"; import VendorsListComponent from "./vendors-list.component";
@@ -11,21 +11,21 @@ export default function VendorsListContainer() {
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const history = useNavigate(); const history = useNavigate();
const handleNewVendor = () => { const handleNewVendor = () => {
search.selectedvendor = "new"; search.selectedvendor = "new";
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
search.selectedvendor = record.id; search.selectedvendor = record.id;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} else { } else {
delete search.selectedvendor; delete search.selectedvendor;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
} }
}; };

View File

@@ -3,9 +3,9 @@ import * as Sentry from "@sentry/react";
import "antd/dist/antd.less"; import "antd/dist/antd.less";
import Dinero from "dinero.js"; import Dinero from "dinero.js";
import React from "react"; import React from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom/client";
import { Provider } from "react-redux"; import { Provider } from "react-redux";
import { BrowserRouter } from "react-router-dom"; import { BrowserRouter as Router } from "react-router-dom";
import { PersistGate } from "redux-persist/integration/react"; import { PersistGate } from "redux-persist/integration/react";
import AppContainer from "./App/App.container"; import AppContainer from "./App/App.container";
import LoadingSpinner from "./components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "./components/loading-spinner/loading-spinner.component";
@@ -47,18 +47,20 @@ if (process.env.NODE_ENV !== "development") {
}); });
} }
ReactDOM.render( const root = ReactDOM.createRoot(document.getElementById("root"));
<Provider store={store}> root.render(
<BrowserRouter> <React.StrictMode>
<PersistGate <Provider store={store}>
loading={<LoadingSpinner message="Restoring your settings..." />} <Router>
persistor={persistor} <PersistGate
> loading={<LoadingSpinner message="Restoring your settings..." />}
<AppContainer /> persistor={persistor}
</PersistGate> >
</BrowserRouter> <AppContainer />
</Provider>, </PersistGate>
document.getElementById("root") </Router>
</Provider>
</React.StrictMode>
); );
// const onServiceWorkerUpdate = (registration) => { // const onServiceWorkerUpdate = (registration) => {

View File

@@ -5,7 +5,7 @@ import queryString from "query-string";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import BillDeleteButton from "../../components/bill-delete-button/bill-delete-button.component"; import BillDeleteButton from "../../components/bill-delete-button/bill-delete-button.component";
import PartsOrderModalContainer from "../../components/parts-order-modal/parts-order-modal.container"; import PartsOrderModalContainer from "../../components/parts-order-modal/parts-order-modal.container";
import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.component"; import PrintWrapperComponent from "../../components/print-wrapper/print-wrapper.component";
@@ -31,7 +31,7 @@ export function BillsListPage({
setPartsOrderContext, setPartsOrderContext,
setBillEnterContext, setBillEnterContext,
}) { }) {
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const [openSearchResults, setOpenSearchResults] = useState([]); const [openSearchResults, setOpenSearchResults] = useState([]);
const [searchLoading, setSearchLoading] = useState(false); const [searchLoading, setSearchLoading] = useState(false);
const { page } = search; const { page } = search;
@@ -212,7 +212,7 @@ export function BillsListPage({
search.sortorder = sorter.order; search.sortorder = sorter.order;
} }
search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order }); search.sort = JSON.stringify({ [sorter.columnKey]: sorter.order });
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}; };
useEffect(() => { useEffect(() => {
@@ -251,7 +251,7 @@ export function BillsListPage({
onClick={() => { onClick={() => {
delete search.search; delete search.search;
delete search.page; delete search.page;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -276,7 +276,7 @@ export function BillsListPage({
placeholder={search.search || t("general.labels.search")} placeholder={search.search || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
search.search = value; search.search = value;
history.push({ search: queryString.stringify(search) }); history({ search: queryString.stringify(search) });
searchBills(value); searchBills(value);
}} }}
loading={loading || searchLoading} loading={loading || searchLoading}

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import BillDetailEditContainer from "../../components/bill-detail-edit/bill-detail-edit.container"; import BillDetailEditContainer from "../../components/bill-detail-edit/bill-detail-edit.container";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
@@ -22,7 +22,7 @@ const mapDispatchToProps = (dispatch) => ({
export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) { export function BillsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation(); const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, searchObj } = searchParams; const { page, sortcolumn, sortorder, searchObj } = searchParams;
useEffect(() => { useEffect(() => {

View File

@@ -3,7 +3,7 @@ import { Form, notification } from "antd";
import React, { useEffect, useState } from "react"; import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useSearchParams, useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries"; import { INSERT_NEW_CONTRACT } from "../../graphql/cccontracts.queries";
@@ -31,11 +31,11 @@ export function ContractCreatePageContainer({
const [form] = Form.useForm(); const [form] = Form.useForm();
const { t } = useTranslation(); const { t } = useTranslation();
const history = useNavigate(); const history = useNavigate();
const location = useLocation(); const searchParams = useSearchParams();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const selectedCarState = useState(null); const selectedCarState = useState(null);
const selectedJobState = useState( const selectedJobState = useState(
(location.state && location.state.jobId) || null (searchParams.get('state') && searchParams.get('state').jobId) || null
); );
const [insertContract] = useMutation(INSERT_NEW_CONTRACT); const [insertContract] = useMutation(INSERT_NEW_CONTRACT);
const [intakeJob] = useMutation(UPDATE_JOB); const [intakeJob] = useMutation(UPDATE_JOB);
@@ -87,7 +87,7 @@ export function ContractCreatePageContainer({
form.resetFields(); form.resetFields();
form.resetFields(); form.resetFields();
history.push( history(
`/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}` `/manage/courtesycars/contracts/${result.data.insert_cccontracts.returning[0].id}`
); );
} else { } else {

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import { QUERY_ACTIVE_CONTRACTS_PAGINATED } from "../../graphql/cccontracts.queries"; import { QUERY_ACTIVE_CONTRACTS_PAGINATED } from "../../graphql/cccontracts.queries";
@@ -20,7 +20,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function ContractsPageContainer({ setBreadcrumbs, setSelectedHeader }) { export function ContractsPageContainer({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { search, page, sortcolumn, sortorder } = searchParams; const { search, page, sortcolumn, sortorder } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(

View File

@@ -50,7 +50,7 @@ export function CourtesyCarCreateContainer({
form.resetFields(); form.resetFields();
form.resetFields(); form.resetFields();
notification["success"]({ message: t("courtesycars.successes.saved") }); notification["success"]({ message: t("courtesycars.successes.saved") });
history.push( history(
`/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}` `/manage/courtesycars/${result.data.insert_courtesycars.returning[0].id}`
); );
} }

View File

@@ -18,7 +18,7 @@ import CourtesyCarDetailPageComponent from "./courtesy-car-detail.page.component
import NotFound from "../../components/not-found/not-found.component"; import NotFound from "../../components/not-found/not-found.component";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import queryString from "query-string"; import queryString from "query-string";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import {pageLimit} from "../../utils/config"; import {pageLimit} from "../../utils/config";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
@@ -31,7 +31,7 @@ export function CourtesyCarDetailPageContainer({
addRecentItem, addRecentItem,
setSelectedHeader, setSelectedHeader,
}) { }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder } = searchParams; const { page, sortcolumn, sortorder } = searchParams;
const { t } = useTranslation(); const { t } = useTranslation();

View File

@@ -2,7 +2,7 @@ import { Button, Card, Col, notification, Row, Select, Space } from "antd";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import SocketIO from "socket.io-client"; 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";
@@ -45,9 +45,9 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const history = useNavigate(); const history = useNavigate();
const [logs, setLogs] = useState([]); const [logs, setLogs] = useState([]);
const { state } = useLocation(); const searchParams = useSearchParams();
const state = Object.fromEntries(searchParams);
const logsRef = useRef(null); const logsRef = useRef(null);
useEffect(() => { useEffect(() => {
document.title = t("titles.dms"); document.title = t("titles.dms");
@@ -101,7 +101,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
}, []); }, []);
if (!state?.billids) { if (!state?.billids) {
history.push(`/manage/accounting/payables`); history(`/manage/accounting/payables`);
} }
return ( return (

View File

@@ -13,7 +13,7 @@ import queryString from "query-string";
import React, { useEffect, useRef, useState } from "react"; import React, { useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import SocketIO from "socket.io-client"; import SocketIO from "socket.io-client";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
@@ -62,7 +62,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const [logLevel, setLogLevel] = useState("DEBUG"); const [logLevel, setLogLevel] = useState("DEBUG");
const history = useNavigate(); const history = useNavigate();
const [logs, setLogs] = useState([]); const [logs, setLogs] = useState([]);
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const { jobId } = search; const { jobId } = search;
const { loading, error, data } = useQuery(QUERY_JOB_EXPORT_DMS, { const { loading, error, data } = useQuery(QUERY_JOB_EXPORT_DMS, {
@@ -115,7 +115,7 @@ export function DmsContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
notification.success({ notification.success({
message: t("jobs.successes.exported"), message: t("jobs.successes.exported"),
}); });
history.push("/manage/accounting/receivables"); history("/manage/accounting/receivables");
}); });
if (socket.disconnected) socket.connect(); if (socket.disconnected) socket.connect();

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries"; import { QUERY_EXPORT_LOG_PAGINATED } from "../../graphql/accounting.queries";
@@ -19,7 +19,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function ExportLogsPageComponent({ bodyshop }) { export function ExportLogsPageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search } = searchParams; const { page, sortcolumn, sortorder, search } = searchParams;
const history = useNavigate(); const history = useNavigate();
@@ -60,7 +60,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
} else { } else {
delete searchParams.statusFilters; delete searchParams.statusFilters;
} }
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}; };
const columns = [ const columns = [
@@ -155,7 +155,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
<Button <Button
onClick={() => { onClick={() => {
delete searchParams.search; delete searchParams.search;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -169,7 +169,7 @@ export function ExportLogsPageComponent({ bodyshop }) {
placeholder={searchParams.search || t("general.labels.search")} placeholder={searchParams.search || t("general.labels.search")}
onSearch={(value) => { onSearch={(value) => {
searchParams.search = value; searchParams.search = value;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}} }}
/> />
</Space> </Space>

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import JobsListPaginated from "../../components/jobs-list-paginated/jobs-list-paginated.component"; import JobsListPaginated from "../../components/jobs-list-paginated/jobs-list-paginated.component";
@@ -25,7 +25,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function AllJobs({ setBreadcrumbs, setSelectedHeader }) { export function AllJobs({ setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, statusFilters } = searchParams; const { page, sortcolumn, sortorder, statusFilters } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(

View File

@@ -21,7 +21,7 @@ import {
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
//import { useHistory } from "react-router-dom"; // import { useNavigate } from 'react-router-dom';
import { useTreatments } from "@splitsoftware/splitio-react"; import { useTreatments } from "@splitsoftware/splitio-react";
import Dinero from "dinero.js"; import Dinero from "dinero.js";
import moment from "moment"; import moment from "moment";
@@ -110,7 +110,9 @@ export function JobsCloseComponent({ job, bodyshop, jobRO }) {
notification["success"]({ notification["success"]({
message: t("jobs.successes.closed"), message: t("jobs.successes.closed"),
}); });
// history.push(`/manage/jobs/${job.id}`);
// const navigate = useNavigate();
// navigate(`/manage/jobs/${job.id}`);
} else { } else {
setLoading(false); setLoading(false);
notification["error"]({ notification["error"]({

View File

@@ -24,7 +24,7 @@ import React, { useEffect, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa"; import { FaHardHat, FaRegStickyNote, FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux"; import { connect } from "react-redux";
import {useNavigate, useLocation} from "react-router-dom"; import {useNavigate, useSearchParams} from "react-router-dom";
import { createStructuredSelector } from "reselect"; 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 JobAuditTrail from "../../components/job-audit-trail/job-audit-trail.component";
@@ -79,8 +79,7 @@ export function JobsDetailPage({
const [form] = Form.useForm(); const [form] = Form.useForm();
const history = useNavigate(); const history = useNavigate();
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const search = queryString.parse(useLocation().search); const search = queryString.parse(useSearchParams().toString());
const formItemLayout = { const formItemLayout = {
layout: "vertical", layout: "vertical",
}; };
@@ -256,7 +255,7 @@ export function JobsDetailPage({
<FormFieldsChanged form={form} /> <FormFieldsChanged form={form} />
<Tabs <Tabs
defaultActiveKey={search.tab} defaultActiveKey={search.tab}
onChange={(key) => history.push({ search: `?tab=${key}` })} onChange={(key) => history({ search: `?tab=${key}` })}
tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }} tabBarStyle={{ fontWeight: "bold", borderBottom: "10px" }}
> >
<Tabs.TabPane <Tabs.TabPane

View File

@@ -1,4 +1,4 @@
import React from "react"; import React, {useEffect} from "react";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -13,8 +13,12 @@ export default connect(mapStateToProps, null)(LandingPage);
export function LandingPage({ currentUser }) { export function LandingPage({ currentUser }) {
const navigate = useNavigate(); const navigate = useNavigate();
if (currentUser.authorized) return navigate("/manage");
return <LandingPageStatic />; useEffect(() => {
//return <Redirect to={"/signin"} />; if (!currentUser.authorized) {
navigate('/manage');
}
}, [currentUser, navigate]);
return currentUser.authorized ? <LandingPageStatic /> : <div />;
} }

View File

@@ -1,14 +1,19 @@
import React from "react"; import React, {useEffect} from "react";
//import DashboardGridComponent from "../../components/dashboard-grid/dashboard-grid.component"; //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() { export default function ManageRootPageComponent() {
//const client = useApolloClient(); //const client = useApolloClient();
const navigate = useNavigate(); const navigate = useNavigate();
return navigate("/manage/jobs");
useEffect(() => {
navigate('/manage/jobs');
}, [navigate]);
return <div />;
// return ( // return (
// <div> // <div>
// <DashboardGridComponent /> // <DashboardGridComponent />
// </div> // </div>
// ); // );
} }

View File

@@ -179,7 +179,13 @@ const mapStateToProps = createStructuredSelector({
}); });
export function Manage({ match, conflict, bodyshop }) { export function Manage({ match, conflict, bodyshop }) {
// TODO: Remove after client upgrade
console.log('Manage Page :');
console.dir({ match, conflict, bodyshop });
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => { useEffect(() => {
const widgetId = "IABVNO4scRKY11XBQkNr"; const widgetId = "IABVNO4scRKY11XBQkNr";
window.noticeable.render("widget", widgetId); window.noticeable.render("widget", widgetId);
@@ -209,184 +215,152 @@ export function Manage({ match, conflict, bodyshop }) {
<EmailOverlayContainer /> <EmailOverlayContainer />
<TimeTicketModalContainer /> <TimeTicketModalContainer />
<PrintCenterModalContainer /> <PrintCenterModalContainer />
<Route exact path={`${match.path}/_test`} component={TestComponent} /> <Route path={`${match.path}/_test`} element={<TestComponent />} />
<Route exact path={`${match.path}`} component={ManageRootPage} /> <Route path={`${match.path}`} element={<ManageRootPage />} />
<Route exact path={`${match.path}/jobs`} component={JobsPage} /> <Route path={`${match.path}/jobs`} element={<JobsPage />} />
<Routes> <Routes>
<Route <Route
exact
path={`${match.path}/jobs/:jobId/intake`} path={`${match.path}/jobs/:jobId/intake`}
component={JobIntake} element={<JobIntake />}
/> />
<Route <Route
exact
path={`${match.path}/jobs/:jobId/deliver`} path={`${match.path}/jobs/:jobId/deliver`}
component={JobDeliver} element={<JobDeliver />}
/> />
<Route <Route
exact
path={`${match.path}/jobs/:jobId/checklist`} path={`${match.path}/jobs/:jobId/checklist`}
component={JobChecklistView} element={<JobChecklistView />}
/> />
<Route <Route
exact
path={`${match.path}/jobs/:jobId/close`} path={`${match.path}/jobs/:jobId/close`}
component={JobsClose} element={<JobsClose />}
/> />
<Route <Route
exact
path={`${match.path}/jobs/:jobId/admin`} path={`${match.path}/jobs/:jobId/admin`}
component={JobsAdmin} element={<JobsAdmin />}
/> />
<Route exact path={`${match.path}/jobs/all`} component={AllJobs} /> <Route path={`${match.path}/jobs/all`} element={<AllJobs />} />
<Route exact path={`${match.path}/jobs/ready`} component={ReadyJobs} /> <Route path={`${match.path}/jobs/ready`} element={<ReadyJobs />} />
<Route <Route
exact
path={`${match.path}/jobs/new`} path={`${match.path}/jobs/new`}
component={JobsCreateContainerPage} element={<JobsCreateContainerPage />}
/> />
<Route path={`${match.path}/jobs/:jobId`} component={JobsDetailPage} /> <Route path={`${match.path}/jobs/:jobId`} element={<JobsDetailPage />} />
</Routes> </Routes>
<Route exact path={`${match.path}/temporarydocs/`} component={TempDocs} /> <Route path={`${match.path}/temporarydocs/`} element={<TempDocs />} />
<Route <Route
exact
path={`${match.path}/inventory/`} path={`${match.path}/inventory/`}
component={InventoryListPage} element={<InventoryListPage />}
/> />
<Route <Route
exact
path={`${match.path}/courtesycars/`} path={`${match.path}/courtesycars/`}
component={CourtesyCarsPage} element={<CourtesyCarsPage />}
/> />
<Routes> <Routes>
<Route <Route
exact
path={`${match.path}/courtesycars/new`} path={`${match.path}/courtesycars/new`}
component={CourtesyCarCreateContainer} element={<CourtesyCarCreateContainer />}
/> />
<Route <Route
exact
path={`${match.path}/courtesycars/contracts`} path={`${match.path}/courtesycars/contracts`}
component={ContractsList} element={<ContractsList />}
/> />
<Route <Route
exact
path={`${match.path}/courtesycars/contracts/new`} path={`${match.path}/courtesycars/contracts/new`}
component={ContractCreatePage} element={<ContractCreatePage />}
/> />
<Route <Route
exact
path={`${match.path}/courtesycars/contracts/:contractId`} path={`${match.path}/courtesycars/contracts/:contractId`}
component={ContractDetailPage} element={<ContractDetailPage />}
/> />
<Route <Route
exact
path={`${match.path}/courtesycars/:ccId`} path={`${match.path}/courtesycars/:ccId`}
component={CourtesyCarDetailContainer} element={<CourtesyCarDetailContainer />}
/> />
</Routes> </Routes>
<Route exact path={`${match.path}/profile`} component={ProfilePage} /> <Route path={`${match.path}/profile`} element={<ProfilePage />} />
<Route <Route
exact
path={`${match.path}/vehicles`} path={`${match.path}/vehicles`}
component={VehiclesContainer} element={<VehiclesContainer />}
/> />
<Route <Route
exact
path={`${match.path}/production/list`} path={`${match.path}/production/list`}
component={ProductionListPage} element={<ProductionListPage />}
/> />
<Route <Route
exact
path={`${match.path}/production/board`} path={`${match.path}/production/board`}
component={ProductionBoardPage} element={<ProductionBoardPage />}
/> />
<Route <Route
exact
path={`${match.path}/vehicles/:vehId`} path={`${match.path}/vehicles/:vehId`}
component={VehiclesDetailContainer} element={<VehiclesDetailContainer />}
/> />
<Route exact path={`${match.path}/bills`} component={BillsListPage} /> <Route path={`${match.path}/bills`} element={<BillsListPage />} />
<Route exact path={`${match.path}/owners`} component={OwnersContainer} /> <Route path={`${match.path}/owners`} element={<OwnersContainer />} />
<Route <Route
exact
path={`${match.path}/owners/:ownerId`} path={`${match.path}/owners/:ownerId`}
component={OwnersDetailContainer} element={<OwnersDetailContainer />}
/> />
<Route <Route
exact
path={`${match.path}/schedule`} path={`${match.path}/schedule`}
component={ScheduleContainer} element={<ScheduleContainer />}
/> />
<Route <Route
exact
path={`${match.path}/available`} path={`${match.path}/available`}
component={JobsAvailablePage} element={<JobsAvailablePage />}
/> />
<Route exact path={`${match.path}/shop/`} component={ShopPage} /> <Route path={`${match.path}/shop/`} element={<ShopPage />} />
{ {
// <Route // <Route
// exact
// path={`${match.path}/shop/templates`} // path={`${match.path}/shop/templates`}
// component={ShopTemplates} // element={<ShopTemplates />}
// /> // />
} }
<Route <Route
exact
path={`${match.path}/shop/vendors`} path={`${match.path}/shop/vendors`}
component={ShopVendorPageContainer} element={<ShopVendorPageContainer />}
/> />
<Route <Route
exact
path={`${match.path}/shop/csi`} path={`${match.path}/shop/csi`}
component={ShopCsiPageContainer} element={<ShopCsiPageContainer />}
/> />
<Route <Route
exact
path={`${match.path}/accounting/qbo`} path={`${match.path}/accounting/qbo`}
component={AccountingQboCallback} element={<AccountingQboCallback />}
/> />
<Route <Route
exact
path={`${match.path}/accounting/receivables`} path={`${match.path}/accounting/receivables`}
component={AccountingReceivables} element={<AccountingReceivables />}
/> />
<Route <Route
exact
path={`${match.path}/accounting/payables`} path={`${match.path}/accounting/payables`}
component={AccountingPayables} element={<AccountingPayables />}
/> />
<Route <Route
exact
path={`${match.path}/accounting/payments`} path={`${match.path}/accounting/payments`}
component={AccountingPayments} element={<AccountingPayments />}
/> />
<Route <Route
exact
path={`${match.path}/accounting/exportlogs`} path={`${match.path}/accounting/exportlogs`}
component={ExportLogs} element={<ExportLogs />}
/> />
<Route exact path={`${match.path}/partsqueue`} component={PartsQueue} /> <Route path={`${match.path}/partsqueue`} element={<PartsQueue />} />
<Route exact path={`${match.path}/phonebook`} component={Phonebook} /> <Route path={`${match.path}/phonebook`} element={<Phonebook />} />
<Route exact path={`${match.path}/payments`} component={PaymentsAll} /> <Route path={`${match.path}/payments`} element={<PaymentsAll />} />
<Route exact path={`${match.path}/shiftclock`} component={ShiftClock} /> <Route path={`${match.path}/shiftclock`} element={<ShiftClock />} />
<Route exact path={`${match.path}/scoreboard`} component={Scoreboard} /> <Route path={`${match.path}/scoreboard`} element={<Scoreboard />} />
<Route <Route
exact
path={`${match.path}/timetickets`} path={`${match.path}/timetickets`}
component={TimeTicketsAll} element={<TimeTicketsAll />}
/> />
<Route exact path={`${match.path}/help`} component={Help} /> <Route path={`${match.path}/help`} element={<Help />} />
<Route exact path={`${match.path}/emailtest`} component={EmailTest} /> <Route path={`${match.path}/emailtest`} element={<EmailTest />} />
<Route exact path={`${match.path}/dashboard`} component={Dashboard} /> <Route path={`${match.path}/dashboard`} element={<Dashboard />} />
<Route exact path={`${match.path}/dms`} component={Dms} /> <Route path={`${match.path}/dms`} element={<Dms />} />
<Route exact path={`${match.path}/dmsap`} component={DmsPayables} /> <Route path={`${match.path}/dmsap`} element={<DmsPayables />} />
</Suspense> </Suspense>
); );

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React, { useState } from "react"; import React, { useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { Link, useNavigate, useLocation } from "react-router-dom"; import { Link, useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component"; import JobPartsQueueCount from "../../components/job-parts-queue-count/job-parts-queue-count.component";
@@ -25,7 +25,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function PartsQueuePageComponent({ bodyshop }) { export function PartsQueuePageComponent({ bodyshop }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { const {
//page, //page,
sortcolumn, sortcolumn,
@@ -104,7 +104,7 @@ export function PartsQueuePageComponent({ bodyshop }) {
delete searchParams.statusFilters; delete searchParams.statusFilters;
} }
setFilter(filters); setFilter(filters);
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}; };
const columns = [ const columns = [

View File

@@ -3,7 +3,7 @@ import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import PaymentsListPaginated from "../../components/payments-list-paginated/payment-list-paginated.component"; import PaymentsListPaginated from "../../components/payments-list-paginated/payment-list-paginated.component";
@@ -26,7 +26,7 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) { export function AllJobs({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, searchObj } = searchParams; const { page, sortcolumn, sortorder, searchObj } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(

View File

@@ -6,7 +6,7 @@ import queryString from "query-string";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import { QUERY_PHONEBOOK_PAGINATED } from "../../graphql/phonebook.queries"; import { QUERY_PHONEBOOK_PAGINATED } from "../../graphql/phonebook.queries";
@@ -25,7 +25,7 @@ const mapStateToProps = createStructuredSelector({
}); });
export function PhonebookPageComponent({ bodyshop, authLevel }) { export function PhonebookPageComponent({ bodyshop, authLevel }) {
const searchParams = queryString.parse(useLocation().search); const searchParams = queryString.parse(useSearchParams().toString());
const { page, sortcolumn, sortorder, search, phonebookentry } = searchParams; const { page, sortcolumn, sortorder, search, phonebookentry } = searchParams;
const history = useNavigate(); const history = useNavigate();
@@ -66,7 +66,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
} else { } else {
delete searchParams.statusFilters; delete searchParams.statusFilters;
} }
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}; };
const columns = [ const columns = [
@@ -129,16 +129,16 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
const handleNewPhonebook = () => { const handleNewPhonebook = () => {
searchParams.phonebookentry = "new"; searchParams.phonebookentry = "new";
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}; };
const handleOnRowClick = (record) => { const handleOnRowClick = (record) => {
if (record) { if (record) {
searchParams.phonebookentry = record.id; searchParams.phonebookentry = record.id;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
} else { } else {
delete searchParams.phonebookentry; delete searchParams.phonebookentry;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
} }
}; };
const hasNoAccess = !HasRbacAccess({ const hasNoAccess = !HasRbacAccess({
@@ -162,7 +162,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
onClick={() => { onClick={() => {
delete searchParams.search; delete searchParams.search;
searchParams.page = 1; searchParams.page = 1;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}} }}
> >
{t("general.actions.clear")} {t("general.actions.clear")}
@@ -180,7 +180,7 @@ export function PhonebookPageComponent({ bodyshop, authLevel }) {
onSearch={(value) => { onSearch={(value) => {
searchParams.search = value; searchParams.search = value;
searchParams.page = 1; searchParams.page = 1;
history.push({ search: queryString.stringify(searchParams) }); history({ search: queryString.stringify(searchParams) });
}} }}
/> />
</Space> </Space>

View File

@@ -8,9 +8,9 @@ import {
} from "../../redux/application/application.actions"; } from "../../redux/application/application.actions";
import PhonebookPage from "./phonebook.page.component"; import PhonebookPage from "./phonebook.page.component";
import { Drawer, Grid } from "antd"; import { Drawer, Grid } from "antd";
import queryString from "query-string"; import { useSearchParams, useNavigate } from "react-router-dom";
import { useNavigate, useLocation } from "react-router-dom";
import PhonebookFormContainer from "../../components/phonebook-form/phonebook-form.container"; import PhonebookFormContainer from "../../components/phonebook-form/phonebook-form.container";
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({
setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)), setBreadcrumbs: (breadcrumbs) => dispatch(setBreadcrumbs(breadcrumbs)),
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)), setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
@@ -29,13 +29,16 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
}, },
]); ]);
}, [setBreadcrumbs, t, setSelectedHeader]); }, [setBreadcrumbs, t, setSelectedHeader]);
const search = queryString.parse(useLocation().search);
const { phonebookentry } = search; const [searchParams] = useSearchParams();
const history = useNavigate(); const search = Object.fromEntries(searchParams);
const { phonebookentry } = search;
const navigate = useNavigate();
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
.slice(-1)[0]; .slice(-1)[0];
const bpoints = { const bpoints = {
xs: "100%", xs: "100%",
@@ -46,23 +49,23 @@ export function PhonebookContainer({ setBreadcrumbs, setSelectedHeader }) {
xxl: "45%", xxl: "45%",
}; };
const drawerPercentage = selectedBreakpoint const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]] ? bpoints[selectedBreakpoint[0]]
: "100%"; : "100%";
return ( return (
<RbacWrapper action="phonebook:view"> <RbacWrapper action="phonebook:view">
<PhonebookPage /> <PhonebookPage />
<Drawer <Drawer
width={drawerPercentage} width={drawerPercentage}
onClose={() => { onClose={() => {
delete search.phonebookentry; searchParams.delete("phonebookentry");
history.push({ search: queryString.stringify(search) }); navigate({ search: searchParams.toString() });
}} }}
visible={phonebookentry} visible={phonebookentry}
> >
<PhonebookFormContainer /> <PhonebookFormContainer />
</Drawer> </Drawer>
</RbacWrapper> </RbacWrapper>
); );
} }
export default connect(null, mapDispatchToProps)(PhonebookContainer); export default connect(null, mapDispatchToProps)(PhonebookContainer);

View File

@@ -1,14 +1,13 @@
import queryString from "query-string";
import React from "react"; import React from "react";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import UserRequestResetPw from "../../components/user-request-pw-reset/user-request-reset-pw.component"; 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 UserValidatePwReset from "../../components/user-validate-pw-reset/user-validate-pw-reset.component";
export default function ResetPassword() { export default function ResetPassword() {
const searchParams = queryString.parse(useLocation().search); const [searchParams] = useSearchParams();
const { mode, oobCode } = searchParams; const { mode, oobCode } = Object.fromEntries(searchParams);
if (mode === "resetPassword") if (mode === "resetPassword")
return <UserValidatePwReset oobCode={oobCode} />; return <UserValidatePwReset oobCode={oobCode} />;
return <UserRequestResetPw />; return <UserRequestResetPw />;
} }

View File

@@ -1,12 +1,9 @@
import Icon, { FieldTimeOutlined } from "@ant-design/icons"; import Icon, { FieldTimeOutlined } from "@ant-design/icons";
import { Tabs } from "antd"; import { Tabs } from "antd";
import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FaShieldAlt } from "react-icons/fa"; import { FaShieldAlt } from "react-icons/fa";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useNavigate, useLocation } from "react-router-dom";
import { createStructuredSelector } from "reselect";
import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component"; import FeatureWrapper from "../../components/feature-wrapper/feature-wrapper.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component"; import ScoreboardDisplay from "../../components/scoreboard-display/scoreboard-display.component";
@@ -17,6 +14,8 @@ import {
setSelectedHeader, setSelectedHeader,
} from "../../redux/application/application.actions"; } from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import { useNavigate, useSearchParams } from "react-router-dom";
import {createStructuredSelector} from "reselect";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
@@ -29,9 +28,9 @@ const mapDispatchToProps = (dispatch) => ({
export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) { export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
const { t } = useTranslation(); const { t } = useTranslation();
const searchParams = queryString.parse(useLocation().search); const [searchParams] = useSearchParams();
const { tab } = searchParams; const { tab } = Object.fromEntries(searchParams);
const history = useNavigate(); const navigate = useNavigate();
useEffect(() => { useEffect(() => {
document.title = t("titles.scoreboard"); document.title = t("titles.scoreboard");
setSelectedHeader("scoreboard"); setSelectedHeader("scoreboard");
@@ -44,60 +43,58 @@ export function ScoreboardContainer({ setBreadcrumbs, setSelectedHeader }) {
}, [t, setBreadcrumbs, setSelectedHeader]); }, [t, setBreadcrumbs, setSelectedHeader]);
return ( return (
<FeatureWrapper featureName="scoreboard"> <FeatureWrapper featureName="scoreboard">
<RbacWrapper action="scoreboard:view"> <RbacWrapper action="scoreboard:view">
<Tabs <Tabs
activeKey={tab || "sb"} activeKey={tab || "sb"}
destroyInactiveTabPane destroyInactiveTabPane
onChange={(key) => { onChange={(key) => {
searchParams.tab = key; searchParams.set("tab", key);
history.push({ navigate({ search: searchParams.toString() });
search: queryString.stringify(searchParams), }}
}); >
}} <Tabs.TabPane
> tab={
<Tabs.TabPane <span>
tab={
<span>
<Icon component={FaShieldAlt} /> <Icon component={FaShieldAlt} />
{t("scoreboard.labels.jobs")} {t("scoreboard.labels.jobs")}
</span> </span>
} }
destroyInactiveTabPane destroyInactiveTabPane
key="sb" key="sb"
> >
<ScoreboardDisplay /> <ScoreboardDisplay />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane <Tabs.TabPane
tab={ tab={
<span> <span>
<FieldTimeOutlined /> <FieldTimeOutlined />
{t("scoreboard.labels.timeticketsemployee")} {t("scoreboard.labels.timeticketsemployee")}
</span> </span>
} }
destroyInactiveTabPane destroyInactiveTabPane
key="tickets" key="tickets"
> >
<ScoreboardTimeTickets /> <ScoreboardTimeTickets />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane <Tabs.TabPane
tab={ tab={
<span> <span>
<FieldTimeOutlined /> <FieldTimeOutlined />
{t("scoreboard.labels.allemployeetimetickets")} {t("scoreboard.labels.allemployeetimetickets")}
</span> </span>
} }
destroyInactiveTabPane destroyInactiveTabPane
key="ticketsstats" key="ticketsstats"
> >
<ScoreboardTimeTicketsStats /> <ScoreboardTimeTicketsStats />
</Tabs.TabPane> </Tabs.TabPane>
</Tabs> </Tabs>
</RbacWrapper> </RbacWrapper>
</FeatureWrapper> </FeatureWrapper>
); );
} }
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(ScoreboardContainer); )(ScoreboardContainer);

View File

@@ -1,22 +1,19 @@
import { Row, Col } from "antd"; import { Row, Col } from "antd";
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import CsiResponseFormContainer from "../../components/csi-response-form/csi-response-form.container"; 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 { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries"; import { QUERY_CSI_RESPONSE_PAGINATED } from "../../graphql/csi.queries";
import { import { setBreadcrumbs, setSelectedHeader } from "../../redux/application/application.actions";
setBreadcrumbs,
setSelectedHeader,
} from "../../redux/application/application.actions";
import { selectBodyshop } from "../../redux/user/user.selectors"; import { selectBodyshop } from "../../redux/user/user.selectors";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
import {pageLimit} from "../../utils/config"; import { pageLimit } from "../../utils/config";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
}); });
@@ -26,36 +23,30 @@ const mapDispatchToProps = (dispatch) => ({
setSelectedHeader: (key) => dispatch(setSelectedHeader(key)), setSelectedHeader: (key) => dispatch(setSelectedHeader(key)),
}); });
export function ShopCsiContainer({ export function ShopCsiContainer({ bodyshop, setBreadcrumbs, setSelectedHeader }) {
bodyshop,
setBreadcrumbs,
setSelectedHeader,
}) {
const { t } = useTranslation(); const { t } = useTranslation();
const [searchParams] = useSearchParams();
const searchParams = queryString.parse(useLocation().search); const { page, sortcolumn, sortorder } = Object.fromEntries(searchParams);
const { page, sortcolumn, sortorder } = searchParams;
const { loading, error, data, refetch } = useQuery( const { loading, error, data, refetch } = useQuery(
QUERY_CSI_RESPONSE_PAGINATED, QUERY_CSI_RESPONSE_PAGINATED,
{ {
fetchPolicy: "network-only", fetchPolicy: "network-only",
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
variables: { variables: {
//search: search || "", offset: page ? (page - 1) * pageLimit : 0,
offset: page ? (page - 1) * pageLimit : 0, limit: pageLimit,
limit: pageLimit, order: [
order: [ {
{ [sortcolumn || "completedon"]: sortorder
[sortcolumn || "completedon"]: sortorder ? sortorder === "descend"
? sortorder === "descend" ? "desc_nulls_last"
? "desc_nulls_last" : "asc"
: "asc" : "desc_nulls_last",
: "desc_nulls_last", },
}, ],
], },
}, }
}
); );
useEffect(() => { useEffect(() => {
@@ -73,26 +64,21 @@ export function ShopCsiContainer({
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
return ( return (
<RbacWrapper <RbacWrapper action="csi:page">
action="csi:page" <Row gutter={16}>
// noauth={ <Col span={10}>
// <AlertComponent message="You don't have acess to see this screen." /> <CsiResponseListPaginated
// } refetch={refetch}
> loading={loading}
<Row gutter={16}> responses={data ? data.csi : []}
<Col span={10}> total={data ? data.csi_aggregate.aggregate.count : 0}
<CsiResponseListPaginated />
refetch={refetch} </Col>
loading={loading} <Col span={14}>
responses={data ? data.csi : []} <CsiResponseFormContainer />
total={data ? data.csi_aggregate.aggregate.count : 0} </Col>
/> </Row>
</Col> </RbacWrapper>
<Col span={14}>
<CsiResponseFormContainer />
</Col>
</Row>
</RbacWrapper>
); );
} }
export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer); export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer);

View File

@@ -1,45 +1,44 @@
import { Drawer, Grid } from "antd"; import { Drawer, Grid } from "antd";
import queryString from "query-string";
import React from "react"; import React from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } from "react-router-dom";
import VendorsFormContainer from "../../components/vendors-form/vendors-form.container"; import VendorsFormContainer from "../../components/vendors-form/vendors-form.container";
import VendorsListContainer from "../../components/vendors-list/vendors-list.container"; import VendorsListContainer from "../../components/vendors-list/vendors-list.container";
export default function ShopVendorPageComponent() { export default function ShopVendorPageComponent() {
const search = queryString.parse(useLocation().search); const [searchParams] = useSearchParams();
const { selectedvendor } = search; const { selectedvendor } = Object.fromEntries(searchParams);
const history = useNavigate(); const navigate = useNavigate();
const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) const selectedBreakpoint = Object.entries(Grid.useBreakpoint())
.filter((screen) => !!screen[1]) .filter((screen) => !!screen[1])
.slice(-1)[0]; .slice(-1)[0];
const bpoints = { const bpoints = {
xs: "100%", xs: "100%",
sm: "100%", sm: "100%",
md: "100%", md: "100%",
lg: "50%", lg: "50%",
xl: "50%", xl: "50%",
xxl: "45%", xxl: "45%",
}; };
const drawerPercentage = selectedBreakpoint const drawerPercentage = selectedBreakpoint
? bpoints[selectedBreakpoint[0]] ? bpoints[selectedBreakpoint[0]]
: "100%"; : "100%";
return ( return (
<div> <div>
<VendorsListContainer /> <VendorsListContainer />
<Drawer <Drawer
width={drawerPercentage} width={drawerPercentage}
onClose={() => { onClose={() => {
delete search.selectedvendor; searchParams.delete("selectedvendor");
history.push({ search: queryString.stringify(search) }); navigate({ search: searchParams.toString() });
}} }}
visible={selectedvendor} visible={selectedvendor}
> >
<VendorsFormContainer /> <VendorsFormContainer />
</Drawer> </Drawer>
</div> </div>
); );
} }

View File

@@ -1,7 +1,6 @@
import { Tabs } from "antd"; import { Tabs } from "antd";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useNavigate, useLocation } from "react-router-dom"; import { useNavigate, useSearchParams } 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 ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container";
import ShopInfoContainer from "../../components/shop-info/shop-info.container"; import ShopInfoContainer from "../../components/shop-info/shop-info.container";
@@ -26,8 +25,9 @@ const mapDispatchToProps = (dispatch) => ({
export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) { export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
const { t } = useTranslation(); const { t } = useTranslation();
const history = useNavigate(); const navigate = useNavigate();
const search = queryString.parse(useLocation().search); const [searchParams] = useSearchParams();
const { tab } = Object.fromEntries(searchParams);
useEffect(() => { useEffect(() => {
document.title = t("titles.shop"); document.title = t("titles.shop");
@@ -41,29 +41,32 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) {
}, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]); }, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]);
useEffect(() => { useEffect(() => {
if (!search.tab) history.push({ search: "?tab=info" }); if (!tab) navigate({ search: "?tab=info" });
}, [history, search]); }, [navigate, tab]);
return ( return (
<RbacWrapper action="shop:config"> <RbacWrapper action="shop:config">
<Tabs <Tabs
defaultActiveKey={search.tab} defaultActiveKey={tab}
onChange={(key) => history.push({ search: `?tab=${key}` })} onChange={(key) => {
> searchParams.set("tab", key);
<Tabs.TabPane tab={t("bodyshop.labels.shopinfo")} key="info"> navigate({ search: searchParams.toString() });
<ShopInfoContainer /> }}
</Tabs.TabPane> >
<Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees"> <Tabs.TabPane tab={t("bodyshop.labels.shopinfo")} key="info">
<ShopEmployeesContainer /> <ShopInfoContainer />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing"> <Tabs.TabPane tab={t("bodyshop.labels.employees")} key="employees">
<ShopInfoUsersComponent /> <ShopEmployeesContainer />
</Tabs.TabPane> </Tabs.TabPane>
<Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq"> <Tabs.TabPane tab={t("bodyshop.labels.licensing")} key="licensing">
<ShopCsiConfig /> <ShopInfoUsersComponent />
</Tabs.TabPane> </Tabs.TabPane>
</Tabs> <Tabs.TabPane tab={t("bodyshop.labels.csiq")} key="csiq">
</RbacWrapper> <ShopCsiConfig />
</Tabs.TabPane>
</Tabs>
</RbacWrapper>
); );
} }
export default connect(mapStateToProps, mapDispatchToProps)(ShopPage); export default connect(mapStateToProps, mapDispatchToProps)(ShopPage);

View File

@@ -14,29 +14,29 @@ import UpdateAlert from "../../components/update-alert/update-alert.component";
import { selectTechnician } from "../../redux/tech/tech.selectors"; import { selectTechnician } from "../../redux/tech/tech.selectors";
import "./tech.page.styles.scss"; import "./tech.page.styles.scss";
const TimeTicketModalContainer = lazy(() => const TimeTicketModalContainer = lazy(() =>
import("../../components/time-ticket-modal/time-ticket-modal.container") import("../../components/time-ticket-modal/time-ticket-modal.container")
); );
const EmailOverlayContainer = lazy(() => const EmailOverlayContainer = lazy(() =>
import("../../components/email-overlay/email-overlay.container.jsx") import("../../components/email-overlay/email-overlay.container.jsx")
); );
const PrintCenterModalContainer = lazy(() => const PrintCenterModalContainer = lazy(() =>
import("../../components/print-center-modal/print-center-modal.container") import("../../components/print-center-modal/print-center-modal.container")
); );
const TechLogin = lazy(() => const TechLogin = lazy(() =>
import("../../components/tech-login/tech-login.component") import("../../components/tech-login/tech-login.component")
); );
const TechLookup = lazy(() => import("../tech-lookup/tech-lookup.container")); const TechLookup = lazy(() => import("../tech-lookup/tech-lookup.container"));
const ProductionListPage = lazy(() => const ProductionListPage = lazy(() =>
import("../production-list/production-list.container") import("../production-list/production-list.container")
); );
const ProductionBoardPage = lazy(() => const ProductionBoardPage = lazy(() =>
import("../production-board/production-board.container") import("../production-board/production-board.container")
); );
const TechJobClock = lazy(() => const TechJobClock = lazy(() =>
import("../tech-job-clock/tech-job-clock.component") import("../tech-job-clock/tech-job-clock.component")
); );
const TechShiftClock = lazy(() => const TechShiftClock = lazy(() =>
import("../tech-shift-clock/tech-shift-clock.component") import("../tech-shift-clock/tech-shift-clock.component")
); );
const { Content } = Layout; const { Content } = Layout;
@@ -56,66 +56,41 @@ export function TechPage({ technician, match }) {
document.title = t("titles.app"); document.title = t("titles.app");
}, [t]); }, [t]);
if (!technician) return navigate(`${match.path}/login`
);
return ( return (
<Layout className="tech-layout-container"> <Layout className="tech-layout-container">
<TechSider /> <TechSider />
<Layout> <Layout>
<UpdateAlert /> {technician ? null : navigate(`${match.path}/login`)}
<TechHeader /> <UpdateAlert />
<TechHeader />
<Content className="tech-content-container"> <Content className="tech-content-container">
<ErrorBoundary> <ErrorBoundary>
<Suspense <Suspense
fallback={ fallback={
<LoadingSpinner message={t("general.labels.loadingapp")} /> <LoadingSpinner message={t("general.labels.loadingapp")} />
} }
> >
<FeatureWrapper featureName="tech-console"> <FeatureWrapper featureName="tech-console">
<TimeTicketModalContainer /> <TimeTicketModalContainer />
<EmailOverlayContainer /> <EmailOverlayContainer />
<PrintCenterModalContainer /> <PrintCenterModalContainer />
<Routes> <Routes>
<Route <Route path={`${match.path}/login`} element={<TechLogin />} />
exact <Route path={`${match.path}/joblookup`} element={<TechLookup />} />
path={`${match.path}/login`} <Route path={`${match.path}/list`} element={<ProductionListPage />} />
component={TechLogin} <Route path={`${match.path}/jobclock`} element={<TechJobClock />} />
/> <Route path={`${match.path}/shiftclock`} element={<TechShiftClock />} />
<Route <Route path={`${match.path}/board`} element={<ProductionBoardPage />} />
exact </Routes>
path={`${match.path}/joblookup`} </FeatureWrapper>
component={TechLookup} </Suspense>
/> </ErrorBoundary>
<Route
exact
path={`${match.path}/list`}
component={ProductionListPage}
/>
<Route
exact
path={`${match.path}/jobclock`}
component={TechJobClock}
/>
<Route
exact
path={`${match.path}/shiftclock`}
component={TechShiftClock}
/>
<Route
exact
path={`${match.path}/board`}
component={ProductionBoardPage}
/>
</Routes>
</FeatureWrapper>
</Suspense>
</ErrorBoundary>
<BackTop /> <BackTop />
</Content> </Content>
</Layout>
</Layout> </Layout>
</Layout>
); );
} }
export default connect(mapStateToProps, mapDispatchToProps)(TechPage); export default connect(mapStateToProps, mapDispatchToProps)(TechPage);

View File

@@ -1,11 +1,10 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Col, Row, Space } from "antd"; import { Col, Row, Space } from "antd";
import moment from "moment"; import moment from "moment";
import queryString from "query-string";
import React, { useEffect } from "react"; import React, { useEffect } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { useLocation } from "react-router-dom"; import { useSearchParams } from "react-router-dom";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import AlertComponent from "../../components/alert/alert.component"; import AlertComponent from "../../components/alert/alert.component";
import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component";
@@ -28,28 +27,17 @@ const mapDispatchToProps = (dispatch) => ({
}); });
export function TimeTicketsContainer({ export function TimeTicketsContainer({
bodyshop, bodyshop,
setBreadcrumbs, setBreadcrumbs,
setSelectedHeader, setSelectedHeader,
}) { }) {
const { t } = useTranslation(); const { t } = useTranslation();
useEffect(() => { const [searchParams] = useSearchParams();
document.title = t("titles.timetickets"); const { start, end } = Object.fromEntries(searchParams);
setSelectedHeader("timetickets");
setBreadcrumbs([
{
link: "/manage/timetickets",
label: t("titles.bc.timetickets"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
const searchParams = queryString.parse(useLocation().search);
const { start, end } = searchParams;
const startDate = start const startDate = start
? moment(start) ? moment(start)
: moment().startOf("week").subtract(7, "days"); : moment().startOf("week").subtract(7, "days");
const endDate = end ? moment(end) : moment().endOf("week"); const endDate = end ? moment(end) : moment().endOf("week");
const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, { const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, {
@@ -61,38 +49,49 @@ export function TimeTicketsContainer({
nextFetchPolicy: "network-only", nextFetchPolicy: "network-only",
}); });
useEffect(() => {
document.title = t("titles.timetickets");
setSelectedHeader("timetickets");
setBreadcrumbs([
{
link: "/manage/timetickets",
label: t("titles.bc.timetickets"),
},
]);
}, [t, setBreadcrumbs, setSelectedHeader]);
if (error) return <AlertComponent message={error.message} type="error" />; if (error) return <AlertComponent message={error.message} type="error" />;
return ( return (
<RbacWrapper action="timetickets:list"> <RbacWrapper action="timetickets:list">
<Row gutter={[16, 16]}> <Row gutter={[16, 16]}>
<Col span={24}> <Col span={24}>
<TimeTicketList <TimeTicketList
loading={loading} loading={loading}
timetickets={data ? data.timetickets : []} timetickets={data ? data.timetickets : []}
extra={ extra={
<Space wrap> <Space wrap>
<TimeTicketsAttendanceTable /> <TimeTicketsAttendanceTable />
<TimeTicketsPayrollTable /> <TimeTicketsPayrollTable />
<TimeTicketsDatesSelector /> <TimeTicketsDatesSelector />
</Space> </Space>
} }
/> />
</Col> </Col>
<Col span={24}> <Col span={24}>
<TimeTicketsSummaryEmployees <TimeTicketsSummaryEmployees
loading={loading} loading={loading}
timetickets={data ? data.timetickets : []} timetickets={data ? data.timetickets : []}
startDate={startDate} startDate={startDate}
endDate={endDate} endDate={endDate}
/> />
</Col> </Col>
</Row> </Row>
</RbacWrapper> </RbacWrapper>
); );
} }
export default connect( export default connect(
mapStateToProps, mapStateToProps,
mapDispatchToProps mapDispatchToProps
)(TimeTicketsContainer); )(TimeTicketsContainer);

View File

@@ -1,20 +1,21 @@
import React from "react"; import React, { useEffect } from 'react';
import { useNavigate, Route, useLocation } from "react-router-dom"; import { Outlet, useSearchParams, useNavigate } from 'react-router-dom';
function PrivateRoute({ component: Component, isAuthorized, ...rest }) { const PrivateRoute = ({ isAuthorized }) => {
const location = useLocation(); const [searchParams] = useSearchParams();
const navigate = useNavigate(); const navigate = useNavigate();
if (!isAuthorized) { useEffect(() => {
navigate(`/signin?redirect=${location.pathname}`); if (!isAuthorized) {
} console.log('is not authorized');
return ( searchParams.set("redirect", window.location.pathname);
<Route navigate(`/signin?${searchParams.toString()}`);
{...rest} } else {
render={(props) => <Component {...props} /> console.log('isAuthorized');
} }
/> }, [isAuthorized, navigate, searchParams]);
);
return <Outlet />;
} }
export default PrivateRoute; export default PrivateRoute;

View File

@@ -15,4 +15,22 @@ function Prompt(props) {
) )
} }
export default Prompt export default Prompt
// Potential new solution:
// import { useBlocker } from 'react-router-dom';
//
// function Prompt({ when, message }) {
// useBlocker((transition) => {
// if (when) {
// transition.retry();
// return !window.confirm(message);
// }
// return false;
// }, when);
//
// return null;
// }
//
// export default Prompt;