Files
bodyshop/client/src/pages/manage/manage.page.component.jsx

616 lines
20 KiB
JavaScript

import { FloatButton, Layout, Spin } from "antd";
import { Route, Routes } from "react-router-dom";
// import preval from "preval.macro";
import { lazy, Suspense, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import BreadCrumbs from "../../components/breadcrumbs/breadcrumbs.component";
import ChatAffixContainer from "../../components/chat-affix/chat-affix.container";
import ConflictComponent from "../../components/conflict/conflict.component";
import ErrorBoundary from "../../components/error-boundary/error-boundary.component";
//import FooterComponent from "../../components/footer/footer.component";
//Component Imports
import * as Sentry from "@sentry/react";
import TestComponent from "../../components/_test/test.page";
import GlobalFooter from "../../components/global-footer/global-footer.component.jsx";
import HeaderContainer from "../../components/header/header.container";
import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component";
import PartnerPingComponent from "../../components/partner-ping/partner-ping.component";
import ShopSubStatusComponent from "../../components/shop-sub-status/shop-sub-status.component";
import UpdateAlert from "../../components/update-alert/update-alert.component";
import {
selectBodyshop,
selectCurrentUser,
selectInstanceConflict,
selectPartsManagementOnly
} from "../../redux/user/user.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
import { selectDarkMode } from "../../redux/application/application.selectors.js";
const PrintCenterModalContainer = lazy(
() => import("../../components/print-center-modal/print-center-modal.container")
);
const JobsPage = lazy(() => import("../jobs/jobs.page"));
const CardPaymentModalContainer = lazy(
() => import("../../components/card-payment-modal/card-payment-modal.container.jsx")
);
const JobsDetailPage = lazy(() => import("../jobs-detail/jobs-detail.page.container"));
const InventoryListPage = lazy(() => import("../inventory/inventory.page"));
const ProfilePage = lazy(() => import("../profile/profile.container.page"));
const JobsAvailablePage = lazy(() => import("../jobs-available/jobs-available.page.container"));
const ScheduleContainer = lazy(() => import("../schedule/schedule.page.container"));
const VehiclesContainer = lazy(() => import("../vehicles/vehicles.page.container"));
const VehiclesDetailContainer = lazy(() => import("../vehicles-detail/vehicles-detail.page.container"));
const OwnersContainer = lazy(() => import("../owners/owners.page.container"));
const OwnersDetailContainer = lazy(() => import("../owners-detail/owners-detail.page.container"));
const ShopPage = lazy(() => import("../shop/shop.page.component"));
const ShopVendorPageContainer = lazy(() => import("../shop-vendor/shop-vendor.page.container"));
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx"));
const JobsCreateContainerPage = lazy(() => import("../jobs-create/jobs-create.container"));
const CourtesyCarCreateContainer = lazy(() => import("../courtesy-car-create/courtesy-car-create.page.container"));
const CourtesyCarDetailContainer = lazy(() => import("../courtesy-car-detail/courtesy-car-detail.page.container"));
const CourtesyCarsPage = lazy(() => import("../courtesy-cars/courtesy-cars.page.container"));
const ContractCreatePage = lazy(() => import("../contract-create/contract-create.page.container"));
const ContractDetailPage = lazy(() => import("../contract-detail/contract-detail.page.container"));
const ContractsList = lazy(() => import("../contracts/contracts.page.container"));
const BillsListPage = lazy(() => import("../bills/bills.page.container"));
const FeatureRequestPage = lazy(() => import("../feature-request/feature-request.page.jsx"));
const JobCostingModal = lazy(() => import("../../components/job-costing-modal/job-costing-modal.container"));
const ReportCenterModal = lazy(() => import("../../components/report-center-modal/report-center-modal.container"));
const BillEnterModalContainer = lazy(() => import("../../components/bill-enter-modal/bill-enter-modal.container"));
const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const TimeTicketModalTask = lazy(
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
);
const PaymentModalContainer = lazy(() => import("../../components/payment-modal/payment-modal.container"));
const ProductionListPage = lazy(() => import("../production-list/production-list.container"));
const ProductionBoardPage = lazy(() => import("../production-board/production-board.container"));
// const ShopTemplates = lazy(() =>
// import("../shop-templates/shop-templates.container")
// );
const JobIntake = lazy(() => import("../jobs-intake/jobs-intake.page.container"));
const JobChecklistView = lazy(() => import("../jobs-checklist-view/jobs-checklist-view.page"));
const JobDeliver = lazy(() => import("../jobs-deliver/jobs-delivery.page.container"));
const AccountingQboCallback = lazy(() => import("../accounting-qbo/accounting-qbo.page"));
const AccountingReceivables = lazy(() => import("../accounting-receivables/accounting-receivables.container"));
const AccountingPayables = lazy(() => import("../accounting-payables/accounting-payables.container"));
const AccountingPayments = lazy(() => import("../accounting-payments/accounting-payments.container"));
const AllJobs = lazy(() => import("../jobs-all/jobs-all.container"));
const ReadyJobs = lazy(() => import("../jobs-ready/jobs-ready.page"));
const JobsClose = lazy(() => import("../jobs-close/jobs-close.container"));
const JobsAdmin = lazy(() => import("../jobs-admin/jobs-admin.page"));
const TempDocs = lazy(() => import("../temporary-docs/temporary-docs.container"));
const ShopCsiPageContainer = lazy(() => import("../shop-csi/shop-csi.container.page"));
const PaymentsAll = lazy(() => import("../payments-all/payments-all.container.page"));
const ShiftClock = lazy(() => import("../shift-clock/shift-clock.page"));
const Scoreboard = lazy(() => import("../scoreboard/scoreboard.page.container"));
const TimeTicketsAll = lazy(() => import("../time-tickets/time-tickets.container"));
const Help = lazy(() => import("../help/help.page"));
const PartsQueue = lazy(() => import("../parts-queue/parts-queue.page.container"));
const ExportLogs = lazy(() => import("../export-logs/export-logs.page.container"));
const Phonebook = lazy(() => import("../phonebook/phonebook.page.container"));
const EmailTest = lazy(() => import("../../components/email-test/email-test-component"));
const Dashboard = lazy(() => import("../dashboard/dashboard.container"));
const Dms = lazy(() => import("../dms/dms.container"));
const DmsPayables = lazy(() => import("../dms-payables/dms-payables.container"));
const ManageRootPage = lazy(() => import("../manage-root/manage-root.page.container"));
const TtApprovals = lazy(() => import("../tt-approvals/tt-approvals.page.container"));
const MyTasksPage = lazy(() => import("../tasks/myTasksPageContainer.jsx"));
const AllTasksPage = lazy(() => import("../tasks/allTasksPageContainer.jsx"));
const TaskUpsertModalContainer = lazy(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
const { Content } = Layout;
const mapStateToProps = createStructuredSelector({
conflict: selectInstanceConflict,
bodyshop: selectBodyshop,
partsManagementOnly: selectPartsManagementOnly,
isDarkMode: selectDarkMode,
currentUser: selectCurrentUser
});
export function Manage({ conflict, bodyshop, partsManagementOnly, isDarkMode, currentUser }) {
const { t } = useTranslation();
const [chatVisible] = useState(false);
const didMount = useRef(false);
// Centralized alerts handling (fetch + dedupe + notifications)
useAlertsNotifications();
useEffect(() => {
if (didMount.current) return; // prevents dev StrictMode double-run
didMount.current = true;
window.Canny("initChangelog", {
appID: "680bd2c7ee501290377f6686",
position: "top",
align: "left",
theme: !isDarkMode ? "light" : "dark"
});
}, []);
useEffect(() => {
document.title = InstanceRenderManager({
imex: t("titles.imexonline"),
rome: t("titles.romeonline")
});
}, [t]);
// This is a required safety check to prevent parts management only users from accessing /manage based routes
if (partsManagementOnly && !import.meta.env.DEV) {
// This NEEDS to be done this way, DO NOT use the react router, it will cause a ton of side effects
window.location = "/parts";
return null; // Prevent further rendering
}
const AppRouteTable = (
<Suspense
fallback={
<LoadingSpinner
message={t("general.labels.loadingapp", {
app: InstanceRenderManager({
imex: "$t(titles.imexonline)",
rome: "$t(titles.romeonline)"
})
})}
/>
}
>
<PaymentModalContainer />
<CardPaymentModalContainer />
<TaskUpsertModalContainer />
<BreadCrumbs />
<BillEnterModalContainer />
<JobCostingModal />
<ReportCenterModal />
<EmailOverlayContainer />
<TimeTicketModalContainer />
<TimeTicketModalTask />
<PrintCenterModalContainer />
<Routes>
<Route path="/_test" element={<TestComponent />} />
<Route path="/" element={<ManageRootPage />} />
<Route
path="/jobs"
element={
<Suspense fallback={<Spin />}>
<JobsPage />
</Suspense>
}
/>
<Route
path="/jobs/:jobId/intake"
element={
<Suspense fallback={<Spin />}>
<JobIntake />
</Suspense>
}
/>
<Route
path="/jobs/:jobId/deliver"
element={
<Suspense fallback={<Spin />}>
<JobDeliver />
</Suspense>
}
/>
<Route
path="/jobs/:jobId/checklist"
element={
<Suspense fallback={<Spin />}>
<JobChecklistView />
</Suspense>
}
/>
<Route
path="/jobs/:jobId/close"
element={
<Suspense fallback={<Spin />}>
<JobsClose />
</Suspense>
}
/>
<Route
path="/jobs/:jobId/admin"
element={
<Suspense fallback={<Spin />}>
<JobsAdmin />
</Suspense>
}
/>
<Route
path="/jobs/all"
element={
<Suspense fallback={<Spin />}>
<AllJobs />
</Suspense>
}
/>
<Route
path="/jobs/ready"
element={
<Suspense fallback={<Spin />}>
<ReadyJobs />
</Suspense>
}
/>
<Route
path="/jobs/new"
element={
<Suspense fallback={<Spin />}>
<JobsCreateContainerPage />
</Suspense>
}
/>
<Route
path="/jobs/:jobId"
element={
<Suspense fallback={<Spin />}>
<JobsDetailPage />
</Suspense>
}
/>
<Route
path="/temporarydocs/"
element={
<Suspense fallback={<Spin />}>
<TempDocs />
</Suspense>
}
/>
<Route
path="/tasks/mytasks"
element={
<Suspense fallback={<Spin />}>
<MyTasksPage />
</Suspense>
}
/>
<Route
path="/tasks/alltasks"
element={
<Suspense fallback={<Spin />}>
<AllTasksPage />
</Suspense>
}
/>
<Route
path="/inventory/"
element={
<Suspense fallback={<Spin />}>
<InventoryListPage />
</Suspense>
}
/>
<Route
path="/courtesycars/"
element={
<Suspense fallback={<Spin />}>
<CourtesyCarsPage />
</Suspense>
}
/>
<Route
path="/courtesycars/new"
element={
<Suspense fallback={<Spin />}>
<CourtesyCarCreateContainer />
</Suspense>
}
/>
<Route
path="/courtesycars/contracts"
element={
<Suspense fallback={<Spin />}>
<ContractsList />
</Suspense>
}
/>
<Route
path="/courtesycars/contracts/new"
element={
<Suspense fallback={<Spin />}>
<ContractCreatePage />
</Suspense>
}
/>
<Route
path="/courtesycars/contracts/:contractId"
element={
<Suspense fallback={<Spin />}>
<ContractDetailPage />
</Suspense>
}
/>
<Route
path="/courtesycars/:ccId"
element={
<Suspense fallback={<Spin />}>
<CourtesyCarDetailContainer />
</Suspense>
}
/>
<Route
path="/profile"
element={
<Suspense fallback={<Spin />}>
<ProfilePage />
</Suspense>
}
/>
<Route
path="/vehicles"
element={
<Suspense fallback={<Spin />}>
<VehiclesContainer />
</Suspense>
}
/>
<Route
path="/production/list"
element={
<Suspense fallback={<Spin />}>
<ProductionListPage />
</Suspense>
}
/>
<Route
path="/production/board"
element={
<Suspense fallback={<Spin />}>
<ProductionBoardPage />
</Suspense>
}
/>
<Route
path="/vehicles/:vehId"
element={
<Suspense fallback={<Spin />}>
<VehiclesDetailContainer />
</Suspense>
}
/>
<Route
path="/bills"
element={
<Suspense fallback={<Spin />}>
<BillsListPage />
</Suspense>
}
/>
<Route
path="/owners"
element={
<Suspense fallback={<Spin />}>
<OwnersContainer />
</Suspense>
}
/>
<Route
path="/owners/:ownerId"
element={
<Suspense fallback={<Spin />}>
<OwnersDetailContainer />
</Suspense>
}
/>
<Route
path="/schedule"
element={
<Suspense fallback={<Spin />}>
<ScheduleContainer />
</Suspense>
}
/>
<Route
path="/available"
element={
<Suspense fallback={<Spin />}>
<JobsAvailablePage />
</Suspense>
}
/>
<Route
path="/shop"
element={
<Suspense fallback={<Spin />}>
<ShopPage />
</Suspense>
}
/>
{
// <Route
// path='/shop/templates'
// element={<ShopTemplates />}
// />
}
<Route path="/feature-request/*" index element={<FeatureRequestPage />} />
<Route
path="/shop/vendors"
element={
<Suspense fallback={<Spin />}>
<ShopVendorPageContainer />
</Suspense>
}
/>
<Route
path="/shop/csi"
element={
<Suspense fallback={<Spin />}>
<ShopCsiPageContainer />
</Suspense>
}
/>
<Route
path="/accounting/qbo"
element={
<Suspense fallback={<Spin />}>
<AccountingQboCallback />
</Suspense>
}
/>
<Route
path="/accounting/receivables"
element={
<Suspense fallback={<Spin />}>
<AccountingReceivables />
</Suspense>
}
/>
<Route
path="/accounting/payables"
element={
<Suspense fallback={<Spin />}>
<AccountingPayables />
</Suspense>
}
/>
<Route
path="/accounting/payments"
element={
<Suspense fallback={<Spin />}>
<AccountingPayments />
</Suspense>
}
/>
<Route
path="/accounting/exportlogs"
element={
<Suspense fallback={<Spin />}>
<ExportLogs />
</Suspense>
}
/>
<Route
path="/ttapprovals"
element={
<Suspense fallback={<Spin />}>
<TtApprovals />
</Suspense>
}
/>
<Route
path="/partsqueue"
element={
<Suspense fallback={<Spin />}>
<PartsQueue />
</Suspense>
}
/>
<Route
path="/phonebook"
element={
<Suspense fallback={<Spin />}>
<Phonebook />
</Suspense>
}
/>
<Route
path="/payments"
element={
<Suspense fallback={<Spin />}>
<PaymentsAll />
</Suspense>
}
/>
<Route
path="/shiftclock"
element={
<Suspense fallback={<Spin />}>
<ShiftClock />
</Suspense>
}
/>
<Route
path="/scoreboard"
element={
<Suspense fallback={<Spin />}>
<Scoreboard />
</Suspense>
}
/>
<Route
path="/timetickets"
element={
<Suspense fallback={<Spin />}>
<TimeTicketsAll />
</Suspense>
}
/>
<Route
path="/help"
element={
<Suspense fallback={<Spin />}>
<Help />
</Suspense>
}
/>
<Route path="/emailtest" element={<EmailTest />} />
<Route
path="/dashboard"
element={
<Suspense fallback={<Spin />}>
<Dashboard />
</Suspense>
}
/>
<Route
path="/dms"
element={
<Suspense fallback={<Spin />}>
<Dms />
</Suspense>
}
/>
<Route
path="/dmsap"
element={
<Suspense fallback={<Spin />}>
<DmsPayables />
</Suspense>
}
/>
</Routes>
</Suspense>
);
let PageContent;
if (conflict) PageContent = <ConflictComponent />;
else if (bodyshop && bodyshop.sub_status !== "active") PageContent = <ShopSubStatusComponent />;
else PageContent = AppRouteTable;
return (
<>
<ChatAffixContainer bodyshop={bodyshop} currentUser={currentUser} chatVisible={chatVisible} />
<Layout style={{ minHeight: "100vh" }} className="layout-container">
<UpdateAlert />
<HeaderContainer />
<Content className="content-container">
<PartnerPingComponent />
<Sentry.ErrorBoundary fallback={<ErrorBoundary />} showDialog>
{PageContent}
</Sentry.ErrorBoundary>
<FloatButton.BackTop style={{ right: 100, bottom: 25 }} />
</Content>
<GlobalFooter />
</Layout>
</>
);
}
export default connect(mapStateToProps)(Manage);