diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index 199bbd26d..1b2931d8b 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -4,7 +4,7 @@ import LogRocket from "logrocket"; import React, { lazy, Suspense, useEffect } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { Route } from "react-router-dom"; +import { Route, Routes } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import DocumentEditorContainer from "../components/document-editor/document-editor.container"; import ErrorBoundary from "../components/error-boundary/error-boundary.component"; @@ -73,6 +73,7 @@ export function App({ window.addEventListener("online", function (e) { setOnline(true); }); + useEffect(() => { if (currentUser.authorized && bodyshop) { client.setAttribute("imexshopid", bodyshop.imexshopid); @@ -107,54 +108,77 @@ export function App({ /> ); + // + // }> + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + // + + return ( - - }> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + }> + + + } /> + } /> + } /> + } /> + } /> + } /> + }> + } /> + + }> + } /> + + }> + } /> + + + + ); } diff --git a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx index f92a4a349..fd78843ad 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit-component.jsx @@ -1,21 +1,17 @@ -import { useMutation, useQuery } from "@apollo/client"; -import { Button, Form, PageHeader, Popconfirm, Space } from "antd"; +import {useMutation, useQuery} from "@apollo/client"; +import {Button, Form, PageHeader, Popconfirm, Space} from "antd"; import moment from "moment"; import queryString from "query-string"; -import React, { useState } from "react"; -import { useTranslation } from "react-i18next"; -import { connect } from "react-redux"; -import { useLocation } from "react-router-dom"; -import { createStructuredSelector } from "reselect"; -import { - DELETE_BILL_LINE, - INSERT_NEW_BILL_LINES, - UPDATE_BILL_LINE -} from "../../graphql/bill-lines.queries"; -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 React, {useState} from "react"; +import {useTranslation} from "react-i18next"; +import {connect} from "react-redux"; +import {useSearchParams} from "react-router-dom"; +import {createStructuredSelector} from "reselect"; +import {DELETE_BILL_LINE, INSERT_NEW_BILL_LINES, UPDATE_BILL_LINE} from "../../graphql/bill-lines.queries"; +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 AlertComponent from "../alert/alert.component"; 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"; const mapStateToProps = createStructuredSelector({ - bodyshop: selectBodyshop, + bodyshop: selectBodyshop, }); const mapDispatchToProps = (dispatch) => ({ - setPartsOrderContext: (context) => - dispatch(setModalContext({ context: context, modal: "partsOrder" })), - insertAuditTrail: ({ jobid, operation }) => - dispatch(insertAuditTrail({ jobid, operation })), + setPartsOrderContext: (context) => + dispatch(setModalContext({context: context, modal: "partsOrder"})), + insertAuditTrail: ({jobid, operation}) => + dispatch(insertAuditTrail({jobid, operation})), }); export default connect( - mapStateToProps, - mapDispatchToProps + mapStateToProps, + mapDispatchToProps )(BillDetailEditcontainer); -export function BillDetailEditcontainer({ - setPartsOrderContext, - insertAuditTrail, - bodyshop, -}) { - const search = queryString.parse(useLocation().search); +export function BillDetailEditcontainer({setPartsOrderContext, insertAuditTrail, bodyshop,}) { + const search = queryString.parse(useSearchParams().toString()); - const { t } = useTranslation(); - const [form] = Form.useForm(); - const [visible, setVisible] = useState(false); - const [updateLoading, setUpdateLoading] = useState(false); - const [update_bill] = useMutation(UPDATE_BILL); - const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES); - const [updateBillLine] = useMutation(UPDATE_BILL_LINE); - const [deleteBillLine] = useMutation(DELETE_BILL_LINE); + const {t} = useTranslation(); + const [form] = Form.useForm(); + const [visible, setVisible] = useState(false); + const [updateLoading, setUpdateLoading] = useState(false); + const [update_bill] = useMutation(UPDATE_BILL); + const [insertBillLine] = useMutation(INSERT_NEW_BILL_LINES); + const [updateBillLine] = useMutation(UPDATE_BILL_LINE); + const [deleteBillLine] = useMutation(DELETE_BILL_LINE); - const { loading, error, data, refetch } = useQuery(QUERY_BILL_BY_PK, { - variables: { billid: search.billid }, - skip: !!!search.billid, - fetchPolicy: "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; + const {loading, error, data, refetch} = useQuery(QUERY_BILL_BY_PK, { + variables: {billid: search.billid}, + skip: !!!search.billid, + fetchPolicy: "network-only", + nextFetchPolicy: "network-only", }); - //Find bill lines that were deleted. - const deletedJobLines = []; + // ... rest of the code remains the same - data.bills_by_pk.billlines.forEach((a) => { - const matchingRecord = billlines.find((b) => b.id === a.id); - if (!matchingRecord) { - deletedJobLines.push(a); - } - }); + 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(); + } + }; - deletedJobLines.forEach((d) => { - updates.push(deleteBillLine({ variables: { id: d.id } })); - }); + const handleFinish = async (values) => { + setUpdateLoading(true); + //let adjustmentsToInsert = {}; - billlines.forEach((billline) => { - const { deductedfromlbr, inventories, jobline, ...il } = billline; - delete il.__typename; - - if (il.id) { + const {billlines, upload, ...bill} = values; + const updates = []; updates.push( - updateBillLine({ - variables: { - billLineId: il.id, - billLine: { - ...il, - deductedfromlbr: deductedfromlbr, - joblineid: il.joblineid === "noline" ? null : il.joblineid, - }, - }, - }) + update_bill({ + variables: {billId: search.billid, bill: bill}, + }) ); - } 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({ - jobid: bill.jobid, - billid: search.billid, - operation: AuditTrailMapping.billupdated(bill.invoice_number), - }); + //Find bill lines that were deleted. + const deletedJobLines = []; - await refetch(); - form.setFieldsValue(transformData(data)); - form.resetFields(); - setVisible(false); - setUpdateLoading(false); - }; + data.bills_by_pk.billlines.forEach((a) => { + const matchingRecord = billlines.find((b) => b.id === a.id); + if (!matchingRecord) { + deletedJobLines.push(a); + } + }); - if (error) return ; - if (!search.billid) return <>; //
{t("bills.labels.noneselected")}
; + deletedJobLines.forEach((d) => { + 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 ( - <> - {loading && } - {data && ( + if (il.id) { + updates.push( + updateBillLine({ + 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 ; + if (!search.billid) return <>; //
{t("bills.labels.noneselected")}
; + + const exported = data && data.bills_by_pk && data.bills_by_pk.exported; + + return ( <> - - + {loading && } + {data && ( + <> + + - form.submit()} - onCancel={() => setVisible(false)} - okButtonProps={{ loading: updateLoading }} - title={t("bills.labels.editadjwarning")} - > - - - - - - } - /> -
- + form.submit()} + onCancel={() => setVisible(false)} + okButtonProps={{loading: updateLoading}} + title={t("bills.labels.editadjwarning")} + > + + + + + + } + /> + + - {bodyshop.uselocalmediaserver ? ( - - ) : ( - + {bodyshop.uselocalmediaserver ? ( + + ) : ( + + )} + + )} - - )} - - ); + ); } const transformData = (data) => { - return data - ? { - ...data.bills_by_pk, + return data + ? { + ...data.bills_by_pk, - billlines: data.bills_by_pk.billlines.map((i) => { - return { - ...i, - joblineid: !!i.joblineid ? i.joblineid : "noline", - applicable_taxes: { - federal: - (i.applicable_taxes && i.applicable_taxes.federal) || false, - state: (i.applicable_taxes && i.applicable_taxes.state) || false, - local: (i.applicable_taxes && i.applicable_taxes.local) || false, - }, - }; - }), - date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null, - } - : {}; + billlines: data.bills_by_pk.billlines.map((i) => { + return { + ...i, + joblineid: !!i.joblineid ? i.joblineid : "noline", + applicable_taxes: { + federal: + (i.applicable_taxes && i.applicable_taxes.federal) || false, + state: (i.applicable_taxes && i.applicable_taxes.state) || false, + local: (i.applicable_taxes && i.applicable_taxes.local) || false, + }, + }; + }), + date: data.bills_by_pk ? moment(data.bills_by_pk.date) : null, + } + : {}; }; diff --git a/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx b/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx index 32d27e3cd..987c03b38 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit-return.component.jsx @@ -3,7 +3,7 @@ import queryString from "query-string"; import React, { useEffect, useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { useNavigate, useLocation } from "react-router-dom"; +import { useSearchParams, useNavigate } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { insertAuditTrail } from "../../redux/application/application.actions"; import { setModalContext } from "../../redux/modals/modals.actions"; @@ -32,7 +32,7 @@ export function BillDetailEditReturn({ data, disabled, }) { - const search = queryString.parse(useLocation().search); + const search = queryString.parse(useSearchParams().toString()); const history = useNavigate(); const { t } = useTranslation(); const [form] = Form.useForm(); @@ -67,7 +67,7 @@ export function BillDetailEditReturn({ }); delete search.billid; - history.push({ search: queryString.stringify(search) }); + history({ search: queryString.stringify(search) }); setVisible(false); }; useEffect(() => { diff --git a/client/src/components/bill-detail-edit/bill-detail-edit.container.jsx b/client/src/components/bill-detail-edit/bill-detail-edit.container.jsx index dd9490d77..63a3180c7 100644 --- a/client/src/components/bill-detail-edit/bill-detail-edit.container.jsx +++ b/client/src/components/bill-detail-edit/bill-detail-edit.container.jsx @@ -1,11 +1,11 @@ import { Drawer, Grid } from "antd"; import queryString from "query-string"; 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"; export default function BillDetailEditcontainer() { - const search = queryString.parse(useLocation().search); + const search = queryString.parse(useSearchParams().toString()); const history = useNavigate(); const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) @@ -29,7 +29,7 @@ export default function BillDetailEditcontainer() { width={drawerPercentage} onClose={() => { delete search.billid; - history.push({ search: queryString.stringify(search) }); + history({ search: queryString.stringify(search) }); }} destroyOnClose open={search.billid} diff --git a/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx b/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx index 1fea48f5b..bf6200ed4 100644 --- a/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx +++ b/client/src/components/billline-add-inventory/billline-add-inventory.component.jsx @@ -13,7 +13,7 @@ import { } from "../../redux/user/user.selectors"; import { CalculateBillTotal } from "../bill-form/bill-form.totals.utility"; import queryString from "query-string"; -import { useLocation } from "react-router-dom"; +import { useSearchParams } from "react-router-dom"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, @@ -35,7 +35,7 @@ export function BilllineAddInventory({ jobid, }) { const [loading, setLoading] = useState(false); - const { billid } = queryString.parse(useLocation().search); + const { billid } = queryString.parse(useSearchParams().toString()); const [insertInventoryLine] = useMutation(INSERT_INVENTORY_AND_CREDIT); diff --git a/client/src/components/bills-vendors-list/bills-vendors-list.component.jsx b/client/src/components/bills-vendors-list/bills-vendors-list.component.jsx index 9af21662b..e9e24197d 100644 --- a/client/src/components/bills-vendors-list/bills-vendors-list.component.jsx +++ b/client/src/components/bills-vendors-list/bills-vendors-list.component.jsx @@ -2,14 +2,14 @@ import React, { useState } from "react"; import { QUERY_ALL_VENDORS } from "../../graphql/vendors.queries"; import { useQuery } from "@apollo/client"; 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 { useTranslation } from "react-i18next"; import { alphaSort } from "../../utils/sorters"; import AlertComponent from "../alert/alert.component"; export default function BillsVendorsList() { - const search = queryString.parse(useLocation().search); + const search = queryString.parse(useSearchParams().toString()); const history = useNavigate(); const { loading, error, data } = useQuery(QUERY_ALL_VENDORS, { diff --git a/client/src/components/contracts-list/contracts-list.component.jsx b/client/src/components/contracts-list/contracts-list.component.jsx index 8495bf340..92136ba34 100644 --- a/client/src/components/contracts-list/contracts-list.component.jsx +++ b/client/src/components/contracts-list/contracts-list.component.jsx @@ -3,7 +3,7 @@ import { Button, Card, Input, Space, Table, Typography } from "antd"; import queryString from "query-string"; import React, { useState } from "react"; 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 { DateTimeFormatter } from "../../utils/DateFormatter"; import { alphaSort } from "../../utils/sorters"; @@ -40,7 +40,7 @@ export function ContractsList({ filteredInfo: { text: "" }, }); const history = useNavigate(); - const search = queryString.parse(useLocation().search); + const search = queryString.parse(useSearchParams().toString()); const { page } = search; const { t } = useTranslation(); @@ -164,7 +164,7 @@ export function ContractsList({ search.page = pagination.current; search.sortcolumn = sorter.columnKey; search.sortorder = sorter.order; - history.push({ search: queryString.stringify(search) }); + history({ search: queryString.stringify(search) }); }; return ( @@ -179,7 +179,7 @@ export function ContractsList({ - - - ), - }, - ]; + ellipsis: true, + render: (text, record) => ( + + + + + ), + }, + ]; - const handleTableChange = (pagination, filters, sorter) => { - search.page = pagination.current; - search.sortcolumn = sorter.column && sorter.column.key; - search.sortorder = sorter.order; - history.push({ search: queryString.stringify(search) }); - }; + const handleTableChange = (pagination, filters, sorter) => { + search.page = pagination.current; + search.sortcolumn = sorter.column && sorter.column.key; + search.sortorder = sorter.order; + history({search: queryString.stringify(search)}); + }; - return ( - - {search.search && ( - <> - - {t("general.labels.searchresults", { search: search.search })} - - + + )} + + + + + { + search.search = value; + history({search: queryString.stringify(search)}); + }} + enterButton + /> + + } + > + - {t("general.actions.clear")} - - - )} - - - - - { - search.search = value; - history.push({ search: queryString.stringify(search) }); - }} - enterButton - /> - - } - > -
- - ); + columns={columns} + rowKey="id" + dataSource={jobs} + onChange={handleTableChange} + /> + + ); } + export default connect(mapStateToProps, mapDispatchToProps)(JobsList); diff --git a/client/src/components/inventory-list/inventory-list.container.jsx b/client/src/components/inventory-list/inventory-list.container.jsx index e98266464..0b85b4433 100644 --- a/client/src/components/inventory-list/inventory-list.container.jsx +++ b/client/src/components/inventory-list/inventory-list.container.jsx @@ -2,7 +2,7 @@ import { useQuery } from "@apollo/client"; import queryString from "query-string"; import React from "react"; import { connect } from "react-redux"; -import { useLocation } from "react-router-dom"; +import { useSearchParams } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { QUERY_INVENTORY_PAGINATED } from "../../graphql/inventory.queries"; import { @@ -23,7 +23,7 @@ const mapDispatchToProps = (dispatch) => ({ }); 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 { loading, error, data, refetch } = useQuery( diff --git a/client/src/components/job-at-change/schedule-event.component.jsx b/client/src/components/job-at-change/schedule-event.component.jsx index 2651c5e27..9bb08e2f8 100644 --- a/client/src/components/job-at-change/schedule-event.component.jsx +++ b/client/src/components/job-at-change/schedule-event.component.jsx @@ -17,7 +17,7 @@ import queryString from "query-string"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; 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 { openChatByPhone, @@ -60,7 +60,7 @@ export function ScheduleEventComponent({ const { t } = useTranslation(); const [visible, setVisible] = useState(false); const history = useNavigate(); - const searchParams = queryString.parse(useLocation().search); + const searchParams = queryString.parse(useSearchParams().toString()); const [updateAppointment] = useMutation(UPDATE_APPOINTMENT); const [title, setTitle] = useState(event.title); const blockContent = ( @@ -172,7 +172,7 @@ export function ScheduleEventComponent({ {event.job ? ( - - - - - - - + + + + + + + + + + ); } -export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer); +export default connect(mapStateToProps, mapDispatchToProps)(ShopCsiContainer); \ No newline at end of file diff --git a/client/src/pages/shop-vendor/shop-vendor.page.component.jsx b/client/src/pages/shop-vendor/shop-vendor.page.component.jsx index dafa7ffbe..00acb0ff6 100644 --- a/client/src/pages/shop-vendor/shop-vendor.page.component.jsx +++ b/client/src/pages/shop-vendor/shop-vendor.page.component.jsx @@ -1,45 +1,44 @@ import { Drawer, Grid } from "antd"; -import queryString from "query-string"; 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 VendorsListContainer from "../../components/vendors-list/vendors-list.container"; export default function ShopVendorPageComponent() { - const search = queryString.parse(useLocation().search); - const { selectedvendor } = search; - const history = useNavigate(); + const [searchParams] = useSearchParams(); + const { selectedvendor } = Object.fromEntries(searchParams); + const navigate = useNavigate(); - const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) - .filter((screen) => !!screen[1]) - .slice(-1)[0]; + const selectedBreakpoint = Object.entries(Grid.useBreakpoint()) + .filter((screen) => !!screen[1]) + .slice(-1)[0]; - const bpoints = { - xs: "100%", - sm: "100%", - md: "100%", - lg: "50%", - xl: "50%", - xxl: "45%", - }; - const drawerPercentage = selectedBreakpoint - ? bpoints[selectedBreakpoint[0]] - : "100%"; + const bpoints = { + xs: "100%", + sm: "100%", + md: "100%", + lg: "50%", + xl: "50%", + xxl: "45%", + }; + const drawerPercentage = selectedBreakpoint + ? bpoints[selectedBreakpoint[0]] + : "100%"; - return ( -
- + return ( +
+ - { - delete search.selectedvendor; - history.push({ search: queryString.stringify(search) }); - }} - visible={selectedvendor} - > - - -
- ); -} + { + searchParams.delete("selectedvendor"); + navigate({ search: searchParams.toString() }); + }} + visible={selectedvendor} + > + + +
+ ); +} \ No newline at end of file diff --git a/client/src/pages/shop/shop.page.component.jsx b/client/src/pages/shop/shop.page.component.jsx index 0ce020a54..3c14f3c99 100644 --- a/client/src/pages/shop/shop.page.component.jsx +++ b/client/src/pages/shop/shop.page.component.jsx @@ -1,7 +1,6 @@ import { Tabs } from "antd"; import React, { useEffect } from "react"; -import { useNavigate, useLocation } from "react-router-dom"; -import queryString from "query-string"; +import { useNavigate, useSearchParams } from "react-router-dom"; import { useTranslation } from "react-i18next"; import ShopEmployeesContainer from "../../components/shop-employees/shop-employees.container"; import ShopInfoContainer from "../../components/shop-info/shop-info.container"; @@ -26,8 +25,9 @@ const mapDispatchToProps = (dispatch) => ({ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) { const { t } = useTranslation(); - const history = useNavigate(); - const search = queryString.parse(useLocation().search); + const navigate = useNavigate(); + const [searchParams] = useSearchParams(); + const { tab } = Object.fromEntries(searchParams); useEffect(() => { document.title = t("titles.shop"); @@ -41,29 +41,32 @@ export function ShopPage({ bodyshop, setSelectedHeader, setBreadcrumbs }) { }, [t, setSelectedHeader, setBreadcrumbs, bodyshop.shopname]); useEffect(() => { - if (!search.tab) history.push({ search: "?tab=info" }); - }, [history, search]); + if (!tab) navigate({ search: "?tab=info" }); + }, [navigate, tab]); return ( - - history.push({ search: `?tab=${key}` })} - > - - - - - - - - - - - - - - + + { + searchParams.set("tab", key); + navigate({ search: searchParams.toString() }); + }} + > + + + + + + + + + + + + + + ); } -export default connect(mapStateToProps, mapDispatchToProps)(ShopPage); +export default connect(mapStateToProps, mapDispatchToProps)(ShopPage); \ No newline at end of file diff --git a/client/src/pages/tech/tech.page.component.jsx b/client/src/pages/tech/tech.page.component.jsx index cdf0d6e1b..a5db31778 100644 --- a/client/src/pages/tech/tech.page.component.jsx +++ b/client/src/pages/tech/tech.page.component.jsx @@ -14,29 +14,29 @@ import UpdateAlert from "../../components/update-alert/update-alert.component"; import { selectTechnician } from "../../redux/tech/tech.selectors"; import "./tech.page.styles.scss"; const TimeTicketModalContainer = lazy(() => - import("../../components/time-ticket-modal/time-ticket-modal.container") + import("../../components/time-ticket-modal/time-ticket-modal.container") ); const EmailOverlayContainer = lazy(() => - import("../../components/email-overlay/email-overlay.container.jsx") + import("../../components/email-overlay/email-overlay.container.jsx") ); const PrintCenterModalContainer = lazy(() => - import("../../components/print-center-modal/print-center-modal.container") + import("../../components/print-center-modal/print-center-modal.container") ); 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 ProductionListPage = lazy(() => - import("../production-list/production-list.container") + import("../production-list/production-list.container") ); const ProductionBoardPage = lazy(() => - import("../production-board/production-board.container") + import("../production-board/production-board.container") ); const TechJobClock = lazy(() => - import("../tech-job-clock/tech-job-clock.component") + import("../tech-job-clock/tech-job-clock.component") ); const TechShiftClock = lazy(() => - import("../tech-shift-clock/tech-shift-clock.component") + import("../tech-shift-clock/tech-shift-clock.component") ); const { Content } = Layout; @@ -56,66 +56,41 @@ export function TechPage({ technician, match }) { document.title = t("titles.app"); }, [t]); - if (!technician) return navigate(`${match.path}/login` - ); return ( - - - - - + + + + {technician ? null : navigate(`${match.path}/login`)} + + - - - - } - > - - - - - - - - - - - - - - - + + + + } + > + + + + + + } /> + } /> + } /> + } /> + } /> + } /> + + + + - - + + + - ); } -export default connect(mapStateToProps, mapDispatchToProps)(TechPage); +export default connect(mapStateToProps, mapDispatchToProps)(TechPage); \ No newline at end of file diff --git a/client/src/pages/time-tickets/time-tickets.container.jsx b/client/src/pages/time-tickets/time-tickets.container.jsx index 03cfdda50..bb9f6c2d1 100644 --- a/client/src/pages/time-tickets/time-tickets.container.jsx +++ b/client/src/pages/time-tickets/time-tickets.container.jsx @@ -1,11 +1,10 @@ import { useQuery } from "@apollo/client"; import { Col, Row, Space } from "antd"; import moment from "moment"; -import queryString from "query-string"; import React, { useEffect } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { useLocation } from "react-router-dom"; +import { useSearchParams } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import AlertComponent from "../../components/alert/alert.component"; import RbacWrapper from "../../components/rbac-wrapper/rbac-wrapper.component"; @@ -28,28 +27,17 @@ const mapDispatchToProps = (dispatch) => ({ }); export function TimeTicketsContainer({ - bodyshop, - setBreadcrumbs, - setSelectedHeader, -}) { + bodyshop, + setBreadcrumbs, + setSelectedHeader, + }) { const { t } = useTranslation(); - useEffect(() => { - document.title = t("titles.timetickets"); - 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 [searchParams] = useSearchParams(); + const { start, end } = Object.fromEntries(searchParams); const startDate = start - ? moment(start) - : moment().startOf("week").subtract(7, "days"); + ? moment(start) + : moment().startOf("week").subtract(7, "days"); const endDate = end ? moment(end) : moment().endOf("week"); const { loading, error, data } = useQuery(QUERY_TIME_TICKETS_IN_RANGE, { @@ -61,38 +49,49 @@ export function TimeTicketsContainer({ 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 ; return ( - - -
- - - - - - } - /> - - - - - - + + + + + + + + + } + /> + + + + + + ); } export default connect( - mapStateToProps, - mapDispatchToProps -)(TimeTicketsContainer); + mapStateToProps, + mapDispatchToProps +)(TimeTicketsContainer); \ No newline at end of file diff --git a/client/src/utils/private-route.js b/client/src/utils/private-route.js index 13b7c837d..5108c7507 100644 --- a/client/src/utils/private-route.js +++ b/client/src/utils/private-route.js @@ -1,20 +1,21 @@ -import React from "react"; -import { useNavigate, Route, useLocation } from "react-router-dom"; +import React, { useEffect } from 'react'; +import { Outlet, useSearchParams, useNavigate } from 'react-router-dom'; -function PrivateRoute({ component: Component, isAuthorized, ...rest }) { - const location = useLocation(); - const navigate = useNavigate(); +const PrivateRoute = ({ isAuthorized }) => { + const [searchParams] = useSearchParams(); + const navigate = useNavigate(); - if (!isAuthorized) { - navigate(`/signin?redirect=${location.pathname}`); - } - return ( - - } - /> - ); + useEffect(() => { + if (!isAuthorized) { + console.log('is not authorized'); + searchParams.set("redirect", window.location.pathname); + navigate(`/signin?${searchParams.toString()}`); + } else { + console.log('isAuthorized'); + } + }, [isAuthorized, navigate, searchParams]); + + return ; } -export default PrivateRoute; +export default PrivateRoute; \ No newline at end of file diff --git a/client/src/utils/prompt.js b/client/src/utils/prompt.js index 718029f73..0d60f0911 100644 --- a/client/src/utils/prompt.js +++ b/client/src/utils/prompt.js @@ -15,4 +15,22 @@ function Prompt(props) { ) } -export default Prompt \ No newline at end of file +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; \ No newline at end of file