Merged in feature/IO-3499-React-19 (pull request #2902)

Feature/IO-3499 React 19
This commit is contained in:
Dave Richer
2026-01-28 02:31:43 +00:00
12 changed files with 516 additions and 495 deletions

View File

@@ -18,4 +18,3 @@ VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
VITE_APP_AMP_KEY=6228a598e57cd66875cfd41604f1f891 VITE_APP_AMP_KEY=6228a598e57cd66875cfd41604f1f891
VITE_ENABLE_COMPILER_IN_DEV=1

View File

@@ -20,4 +20,3 @@ VITE_PUBLIC_POSTHOG_KEY=phc_xtLmBIu0rjWwExY73Oj5DTH1bGbwq1G1Y8jnlTceien
VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com VITE_PUBLIC_POSTHOG_HOST=https://us.i.posthog.com
VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com VITE_APP_AMP_URL=https://vp8k908qy2.execute-api.ca-central-1.amazonaws.com
VITE_APP_AMP_KEY=46b1193a867d4e3131ae4c3a64a3fc78 VITE_APP_AMP_KEY=46b1193a867d4e3131ae4c3a64a3fc78
VITE_ENABLE_COMPILER_IN_DEV=1

3
client/.gitignore vendored
View File

@@ -13,3 +13,6 @@ playwright/.cache/
# Sentry Config File # Sentry Config File
.sentryclirc .sentryclirc
/dev-dist /dev-dist
# Local environment overrides (not version controlled)
.env.development.local.overrides

699
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -8,7 +8,7 @@
"private": true, "private": true,
"proxy": "http://localhost:4000", "proxy": "http://localhost:4000",
"dependencies": { "dependencies": {
"@amplitude/analytics-browser": "^2.33.5", "@amplitude/analytics-browser": "^2.34.0",
"@ant-design/pro-layout": "^7.22.6", "@ant-design/pro-layout": "^7.22.6",
"@apollo/client": "^4.1.2", "@apollo/client": "^4.1.2",
"@emotion/is-prop-valid": "^1.4.0", "@emotion/is-prop-valid": "^1.4.0",
@@ -21,14 +21,14 @@
"@jsreport/browser-client": "^3.1.0", "@jsreport/browser-client": "^3.1.0",
"@reduxjs/toolkit": "^2.11.2", "@reduxjs/toolkit": "^2.11.2",
"@sentry/cli": "^3.1.0", "@sentry/cli": "^3.1.0",
"@sentry/react": "^10.36.0", "@sentry/react": "^10.37.0",
"@sentry/vite-plugin": "^4.8.0", "@sentry/vite-plugin": "^4.8.0",
"@splitsoftware/splitio-react": "^2.6.1", "@splitsoftware/splitio-react": "^2.6.1",
"@tanem/react-nprogress": "^5.0.58", "@tanem/react-nprogress": "^5.0.58",
"antd": "^6.2.2", "antd": "^6.2.2",
"apollo-link-logger": "^3.0.0", "apollo-link-logger": "^3.0.0",
"autosize": "^6.0.1", "autosize": "^6.0.1",
"axios": "^1.13.3", "axios": "^1.13.4",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"css-box-model": "^1.2.1", "css-box-model": "^1.2.1",
"dayjs": "^1.11.19", "dayjs": "^1.11.19",
@@ -38,31 +38,31 @@
"env-cmd": "^11.0.0", "env-cmd": "^11.0.0",
"exifr": "^7.1.3", "exifr": "^7.1.3",
"graphql": "^16.12.0", "graphql": "^16.12.0",
"graphql-ws": "^6.0.6", "graphql-ws": "^6.0.7",
"i18next": "^25.8.0", "i18next": "^25.8.0",
"i18next-browser-languagedetector": "^8.2.0", "i18next-browser-languagedetector": "^8.2.0",
"immutability-helper": "^3.1.1", "immutability-helper": "^3.1.1",
"libphonenumber-js": "^1.12.35", "libphonenumber-js": "^1.12.35",
"lightningcss": "^1.31.1", "lightningcss": "^1.31.1",
"logrocket": "^11.0.0", "logrocket": "^12.0.0",
"markerjs2": "^2.32.7", "markerjs2": "^2.32.7",
"memoize-one": "^6.0.0", "memoize-one": "^6.0.0",
"normalize-url": "^8.1.1", "normalize-url": "^8.1.1",
"object-hash": "^3.0.0", "object-hash": "^3.0.0",
"phone": "^3.1.70", "phone": "^3.1.70",
"posthog-js": "^1.335.2", "posthog-js": "^1.335.5",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"query-string": "^9.3.1", "query-string": "^9.3.1",
"raf-schd": "^4.0.3", "raf-schd": "^4.0.3",
"react": "^19.2.3", "react": "^19.2.4",
"react-big-calendar": "^1.19.4", "react-big-calendar": "^1.19.4",
"react-color": "^2.19.3", "react-color": "^2.19.3",
"react-cookie": "^8.0.1", "react-cookie": "^8.0.1",
"react-dom": "^19.2.3", "react-dom": "^19.2.4",
"react-drag-listview": "^2.0.0", "react-drag-listview": "^2.0.0",
"react-grid-gallery": "^1.0.1", "react-grid-gallery": "^1.0.1",
"react-grid-layout": "^2.2.2", "react-grid-layout": "^2.2.2",
"react-i18next": "^16.5.3", "react-i18next": "^16.5.4",
"react-icons": "^5.5.0", "react-icons": "^5.5.0",
"react-image-lightbox": "^5.1.4", "react-image-lightbox": "^5.1.4",
"react-markdown": "^10.1.0", "react-markdown": "^10.1.0",
@@ -92,15 +92,17 @@
"postinstall": "echo 'when updating react-big-calendar, remember to check to localizer in the calendar wrapper'", "postinstall": "echo 'when updating react-big-calendar, remember to check to localizer in the calendar wrapper'",
"analyze": "source-map-explorer 'build/static/js/*.js'", "analyze": "source-map-explorer 'build/static/js/*.js'",
"start": "vite", "start": "vite",
"build": "dotenvx run --env-file=.env.development.imex -- vite build", "build": "vite build",
"start:imex": "dotenvx run --env-file=.env.development.imex -- vite", "build:dev:imex": "dotenvx run --env-file=.env.development.imex --env-file=.env.development.local.overrides -- vite build",
"start:rome": "dotenvx run --env-file=.env.development.rome -- vite", "build:dev:rome": "dotenvx run --env-file=.env.development.rome --env-file=.env.development.local.overrides -- vite build",
"preview:imex": "dotenvx run --env-file=.env.development.imex -- vite preview", "build:test:imex": "dotenvx run --env-file=.env.test.imex -- vite build",
"preview:rome": "dotenvx run --env-file=.env.development.rome -- vite preview", "build:test:rome": "dotenvx run --env-file=.env.test.rome -- vite build",
"build:test:imex": "env-cmd -f .env.test.imex -- npm run build", "build:production:imex": "env-cmd -f .env.production.imex vite build",
"build:test:rome": "env-cmd -f .env.test.rome -- npm run build", "build:production:rome": "env-cmd -f .env.production.rome vite build",
"build:production:imex": "env-cmd -f .env.production.imex -- npm run build", "start:imex": "dotenvx run --env-file=.env.development.imex --env-file=.env.development.local.overrides -- vite",
"build:production:rome": "env-cmd -f .env.production.rome -- npm run build", "start:rome": "dotenvx run --env-file=.env.development.rome --env-file=.env.development.local.overrides -- vite",
"preview:imex": "dotenvx run --env-file=.env.development.imex --env-file=.env.development.local.overrides -- vite preview",
"preview:rome": "dotenvx run --env-file=.env.development.rome --env-file=.env.development.local.overrides -- vite preview",
"madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular .", "madge": "madge --image ./madge-graph.svg --extensions js,jsx,ts,tsx --circular .",
"eulaize": "node src/utils/eulaize.js", "eulaize": "node src/utils/eulaize.js",
"test:unit": "vitest run", "test:unit": "vitest run",
@@ -151,7 +153,7 @@
"eslint": "^9.39.2", "eslint": "^9.39.2",
"eslint-plugin-react": "^7.37.5", "eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-compiler": "^19.1.0-rc.2", "eslint-plugin-react-compiler": "^19.1.0-rc.2",
"globals": "^17.1.0", "globals": "^17.2.0",
"jsdom": "^27.4.0", "jsdom": "^27.4.0",
"memfs": "^4.56.10", "memfs": "^4.56.10",
"os-browserify": "^0.3.0", "os-browserify": "^0.3.0",

View File

@@ -100,14 +100,7 @@ export function App({
if (currentUser.authorized && bodyshop) { if (currentUser.authorized && bodyshop) {
client.setAttribute("imexshopid", bodyshop.imexshopid); client.setAttribute("imexshopid", bodyshop.imexshopid);
if ( if (client.getTreatment("LogRocket_Tracking") === "on") {
client.getTreatment("LogRocket_Tracking") === "on" ||
window.location.hostname ===
InstanceRenderMgr({
imex: "beta.imex.online",
rome: "beta.romeonline.io"
})
) {
console.log("LR Start"); console.log("LR Start");
LogRocket.init( LogRocket.init(
InstanceRenderMgr({ InstanceRenderMgr({

View File

@@ -82,13 +82,14 @@ const rootEl = document.getElementById("root");
if (!rootEl) throw new Error('Missing root element: <div id="root" />'); if (!rootEl) throw new Error('Missing root element: <div id="root" />');
const appTree = import.meta.env.DEV ? ( const appTree =
<StrictMode> import.meta.env.DEV && import.meta.env?.VITE_DISABLE_STRICT_MODE !== "true" ? (
<StrictMode>
<App />
</StrictMode>
) : (
<App /> <App />
</StrictMode> );
) : (
<App />
);
ReactDOM.createRoot(rootEl).render(appTree); ReactDOM.createRoot(rootEl).render(appTree);

View File

@@ -2,7 +2,7 @@ import { FloatButton, Layout, Spin } from "antd";
import { Route, Routes } from "react-router-dom"; import { Route, Routes } from "react-router-dom";
// import preval from "preval.macro"; // import preval from "preval.macro";
import { lazy, Suspense, useEffect, useRef, useState } from "react"; import { Suspense, 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 { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -29,87 +29,88 @@ import {
import InstanceRenderManager from "../../utils/instanceRenderMgr.js"; import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx"; import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
import { selectDarkMode } from "../../redux/application/application.selectors.js"; import { selectDarkMode } from "../../redux/application/application.selectors.js";
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
const PrintCenterModalContainer = lazy( const PrintCenterModalContainer = lazyDev(
() => import("../../components/print-center-modal/print-center-modal.container") () => import("../../components/print-center-modal/print-center-modal.container")
); );
const NoteUpsertModal = lazy(() => import("../../components/note-upsert-modal/note-upsert-modal.container.jsx")); const NoteUpsertModal = lazyDev(() => import("../../components/note-upsert-modal/note-upsert-modal.container.jsx"));
const JobsPage = lazy(() => import("../jobs/jobs.page")); const JobsPage = lazyDev(() => import("../jobs/jobs.page"));
const CardPaymentModalContainer = lazy( const CardPaymentModalContainer = lazyDev(
() => import("../../components/card-payment-modal/card-payment-modal.container.jsx") () => import("../../components/card-payment-modal/card-payment-modal.container.jsx")
); );
const JobsDetailPage = lazy(() => import("../jobs-detail/jobs-detail.page.container")); const JobsDetailPage = lazyDev(() => import("../jobs-detail/jobs-detail.page.container"));
const InventoryListPage = lazy(() => import("../inventory/inventory.page")); const InventoryListPage = lazyDev(() => import("../inventory/inventory.page"));
const ProfilePage = lazy(() => import("../profile/profile.container.page")); const ProfilePage = lazyDev(() => import("../profile/profile.container.page"));
const JobsAvailablePage = lazy(() => import("../jobs-available/jobs-available.page.container")); const JobsAvailablePage = lazyDev(() => import("../jobs-available/jobs-available.page.container"));
const ScheduleContainer = lazy(() => import("../schedule/schedule.page.container")); const ScheduleContainer = lazyDev(() => import("../schedule/schedule.page.container"));
const VehiclesContainer = lazy(() => import("../vehicles/vehicles.page.container")); const VehiclesContainer = lazyDev(() => import("../vehicles/vehicles.page.container"));
const VehiclesDetailContainer = lazy(() => import("../vehicles-detail/vehicles-detail.page.container")); const VehiclesDetailContainer = lazyDev(() => import("../vehicles-detail/vehicles-detail.page.container"));
const OwnersContainer = lazy(() => import("../owners/owners.page.container")); const OwnersContainer = lazyDev(() => import("../owners/owners.page.container"));
const OwnersDetailContainer = lazy(() => import("../owners-detail/owners-detail.page.container")); const OwnersDetailContainer = lazyDev(() => import("../owners-detail/owners-detail.page.container"));
const ShopPage = lazy(() => import("../shop/shop.page.component")); const ShopPage = lazyDev(() => import("../shop/shop.page.component"));
const ShopVendorPageContainer = lazy(() => import("../shop-vendor/shop-vendor.page.container")); const ShopVendorPageContainer = lazyDev(() => import("../shop-vendor/shop-vendor.page.container"));
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx")); const EmailOverlayContainer = lazyDev(() => import("../../components/email-overlay/email-overlay.container.jsx"));
const JobsCreateContainerPage = lazy(() => import("../jobs-create/jobs-create.container")); const JobsCreateContainerPage = lazyDev(() => import("../jobs-create/jobs-create.container"));
const CourtesyCarCreateContainer = lazy(() => import("../courtesy-car-create/courtesy-car-create.page.container")); const CourtesyCarCreateContainer = lazyDev(() => import("../courtesy-car-create/courtesy-car-create.page.container"));
const CourtesyCarDetailContainer = lazy(() => import("../courtesy-car-detail/courtesy-car-detail.page.container")); const CourtesyCarDetailContainer = lazyDev(() => import("../courtesy-car-detail/courtesy-car-detail.page.container"));
const CourtesyCarsPage = lazy(() => import("../courtesy-cars/courtesy-cars.page.container")); const CourtesyCarsPage = lazyDev(() => import("../courtesy-cars/courtesy-cars.page.container"));
const ContractCreatePage = lazy(() => import("../contract-create/contract-create.page.container")); const ContractCreatePage = lazyDev(() => import("../contract-create/contract-create.page.container"));
const ContractDetailPage = lazy(() => import("../contract-detail/contract-detail.page.container")); const ContractDetailPage = lazyDev(() => import("../contract-detail/contract-detail.page.container"));
const ContractsList = lazy(() => import("../contracts/contracts.page.container")); const ContractsList = lazyDev(() => import("../contracts/contracts.page.container"));
const BillsListPage = lazy(() => import("../bills/bills.page.container")); const BillsListPage = lazyDev(() => import("../bills/bills.page.container"));
const FeatureRequestPage = lazy(() => import("../feature-request/feature-request.page.jsx")); const FeatureRequestPage = lazyDev(() => import("../feature-request/feature-request.page.jsx"));
const JobCostingModal = lazy(() => import("../../components/job-costing-modal/job-costing-modal.container")); const JobCostingModal = lazyDev(() => import("../../components/job-costing-modal/job-costing-modal.container"));
const ReportCenterModal = lazy(() => import("../../components/report-center-modal/report-center-modal.container")); const ReportCenterModal = lazyDev(() => import("../../components/report-center-modal/report-center-modal.container"));
const BillEnterModalContainer = lazy(() => import("../../components/bill-enter-modal/bill-enter-modal.container")); const BillEnterModalContainer = lazyDev(() => import("../../components/bill-enter-modal/bill-enter-modal.container"));
const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container")); const TimeTicketModalContainer = lazyDev(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const TimeTicketModalTask = lazy( const TimeTicketModalTask = lazyDev(
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container") () => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
); );
const PaymentModalContainer = lazy(() => import("../../components/payment-modal/payment-modal.container")); const PaymentModalContainer = lazyDev(() => import("../../components/payment-modal/payment-modal.container"));
const ProductionListPage = lazy(() => import("../production-list/production-list.container")); const ProductionListPage = lazyDev(() => import("../production-list/production-list.container"));
const ProductionBoardPage = lazy(() => import("../production-board/production-board.container")); const ProductionBoardPage = lazyDev(() => import("../production-board/production-board.container"));
// const ShopTemplates = lazy(() => // const ShopTemplates = lazyDev(() =>
// import("../shop-templates/shop-templates.container") // import("../shop-templates/shop-templates.container")
// ); // );
const JobIntake = lazy(() => import("../jobs-intake/jobs-intake.page.container")); const JobIntake = lazyDev(() => import("../jobs-intake/jobs-intake.page.container"));
const JobChecklistView = lazy(() => import("../jobs-checklist-view/jobs-checklist-view.page")); const JobChecklistView = lazyDev(() => import("../jobs-checklist-view/jobs-checklist-view.page"));
const JobDeliver = lazy(() => import("../jobs-deliver/jobs-delivery.page.container")); const JobDeliver = lazyDev(() => import("../jobs-deliver/jobs-delivery.page.container"));
const AccountingQboCallback = lazy(() => import("../accounting-qbo/accounting-qbo.page")); const AccountingQboCallback = lazyDev(() => import("../accounting-qbo/accounting-qbo.page"));
const AccountingReceivables = lazy(() => import("../accounting-receivables/accounting-receivables.container")); const AccountingReceivables = lazyDev(() => import("../accounting-receivables/accounting-receivables.container"));
const AccountingPayables = lazy(() => import("../accounting-payables/accounting-payables.container")); const AccountingPayables = lazyDev(() => import("../accounting-payables/accounting-payables.container"));
const AccountingPayments = lazy(() => import("../accounting-payments/accounting-payments.container")); const AccountingPayments = lazyDev(() => import("../accounting-payments/accounting-payments.container"));
const AllJobs = lazy(() => import("../jobs-all/jobs-all.container")); const AllJobs = lazyDev(() => import("../jobs-all/jobs-all.container"));
const ReadyJobs = lazy(() => import("../jobs-ready/jobs-ready.page")); const ReadyJobs = lazyDev(() => import("../jobs-ready/jobs-ready.page"));
const JobsClose = lazy(() => import("../jobs-close/jobs-close.container")); const JobsClose = lazyDev(() => import("../jobs-close/jobs-close.container"));
const JobsAdmin = lazy(() => import("../jobs-admin/jobs-admin.page")); const JobsAdmin = lazyDev(() => import("../jobs-admin/jobs-admin.page"));
const TempDocs = lazy(() => import("../temporary-docs/temporary-docs.container")); const TempDocs = lazyDev(() => import("../temporary-docs/temporary-docs.container"));
const ShopCsiPageContainer = lazy(() => import("../shop-csi/shop-csi.container.page")); const ShopCsiPageContainer = lazyDev(() => import("../shop-csi/shop-csi.container.page"));
const PaymentsAll = lazy(() => import("../payments-all/payments-all.container.page")); const PaymentsAll = lazyDev(() => import("../payments-all/payments-all.container.page"));
const ShiftClock = lazy(() => import("../shift-clock/shift-clock.page")); const ShiftClock = lazyDev(() => import("../shift-clock/shift-clock.page"));
const Scoreboard = lazy(() => import("../scoreboard/scoreboard.page.container")); const Scoreboard = lazyDev(() => import("../scoreboard/scoreboard.page.container"));
const TimeTicketsAll = lazy(() => import("../time-tickets/time-tickets.container")); const TimeTicketsAll = lazyDev(() => import("../time-tickets/time-tickets.container"));
const Help = lazy(() => import("../help/help.page")); const Help = lazyDev(() => import("../help/help.page"));
const PartsQueue = lazy(() => import("../parts-queue/parts-queue.page.container")); const PartsQueue = lazyDev(() => import("../parts-queue/parts-queue.page.container"));
const ExportLogs = lazy(() => import("../export-logs/export-logs.page.container")); const ExportLogs = lazyDev(() => import("../export-logs/export-logs.page.container"));
const Phonebook = lazy(() => import("../phonebook/phonebook.page.container")); const Phonebook = lazyDev(() => import("../phonebook/phonebook.page.container"));
const EmailTest = lazy(() => import("../../components/email-test/email-test-component")); const EmailTest = lazyDev(() => import("../../components/email-test/email-test-component"));
const Dashboard = lazy(() => import("../dashboard/dashboard.container")); const Dashboard = lazyDev(() => import("../dashboard/dashboard.container"));
const Dms = lazy(() => import("../dms/dms.container")); const Dms = lazyDev(() => import("../dms/dms.container"));
const DmsPayables = lazy(() => import("../dms-payables/dms-payables.container")); const DmsPayables = lazyDev(() => import("../dms-payables/dms-payables.container"));
const ManageRootPage = lazy(() => import("../manage-root/manage-root.page.container")); const ManageRootPage = lazyDev(() => import("../manage-root/manage-root.page.container"));
const TtApprovals = lazy(() => import("../tt-approvals/tt-approvals.page.container")); const TtApprovals = lazyDev(() => import("../tt-approvals/tt-approvals.page.container"));
const MyTasksPage = lazy(() => import("../tasks/myTasksPageContainer.jsx")); const MyTasksPage = lazyDev(() => import("../tasks/myTasksPageContainer.jsx"));
const AllTasksPage = lazy(() => import("../tasks/allTasksPageContainer.jsx")); const AllTasksPage = lazyDev(() => import("../tasks/allTasksPageContainer.jsx"));
const TaskUpsertModalContainer = lazy(() => import("../../components/task-upsert-modal/task-upsert-modal.container")); const TaskUpsertModalContainer = lazyDev(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
const { Content } = Layout; const { Content } = Layout;
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({

View File

@@ -1,6 +1,6 @@
import * as Sentry from "@sentry/react"; import * as Sentry from "@sentry/react";
import { FloatButton, Layout, Spin } from "antd"; import { FloatButton, Layout, Spin } from "antd";
import { lazy, Suspense, useEffect } from "react"; import { 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 { Navigate, Route, Routes, useLocation } from "react-router-dom"; import { Navigate, Route, Routes, useLocation } from "react-router-dom";
@@ -15,20 +15,21 @@ import UpdateAlert from "../../components/update-alert/update-alert.component.js
import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors.js"; import { selectBodyshop, selectInstanceConflict } from "../../redux/user/user.selectors.js";
import InstanceRenderManager from "../../utils/instanceRenderMgr.js"; import InstanceRenderManager from "../../utils/instanceRenderMgr.js";
import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx"; import useAlertsNotifications from "../../hooks/useAlertsNotifications.jsx";
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
const SimplifiedPartsJobsPage = lazy(() => import("../simplified-parts-jobs/simplified-parts-jobs.page.jsx")); const SimplifiedPartsJobsPage = lazyDev(() => import("../simplified-parts-jobs/simplified-parts-jobs.page.jsx"));
const SimplifiedPartsJobsDetailPage = lazy( const SimplifiedPartsJobsDetailPage = lazyDev(
() => import("../simplified-parts-jobs-detail/simplified-parts-jobs-detail.container.jsx") () => import("../simplified-parts-jobs-detail/simplified-parts-jobs-detail.container.jsx")
); );
const PartsSettingsPage = lazy(() => import("../parts-settings/parts-settings.page.component.jsx")); const PartsSettingsPage = lazyDev(() => import("../parts-settings/parts-settings.page.component.jsx"));
const ShopVendorPageContainer = lazy(() => import("../shop-vendor/shop-vendor.page.container.jsx")); const ShopVendorPageContainer = lazyDev(() => import("../shop-vendor/shop-vendor.page.container.jsx"));
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx")); const EmailOverlayContainer = lazyDev(() => import("../../components/email-overlay/email-overlay.container.jsx"));
const ReportCenterModal = lazy(() => import("../../components/report-center-modal/report-center-modal.container.jsx")); const ReportCenterModal = lazyDev(() => import("../../components/report-center-modal/report-center-modal.container.jsx"));
const PrintCenterModalContainer = lazy( const PrintCenterModalContainer = lazyDev(
() => import("../../components/print-center-modal/print-center-modal.container") () => import("../../components/print-center-modal/print-center-modal.container")
); );
const VehiclesContainer = lazy(() => import("../vehicles/vehicles.page.container.jsx")); const VehiclesContainer = lazyDev(() => import("../vehicles/vehicles.page.container.jsx"));
const VehiclesDetailContainer = lazy(() => import("../vehicles-detail/vehicles-detail.page.container.jsx")); const VehiclesDetailContainer = lazyDev(() => import("../vehicles-detail/vehicles-detail.page.container.jsx"));
const { Content } = Layout; const { Content } = Layout;
// Redirector to strip '/parts/jobs' from path for non-detail routes // Redirector to strip '/parts/jobs' from path for non-detail routes

View File

@@ -1,5 +1,5 @@
import { Card, FloatButton, Layout } from "antd"; import { Card, FloatButton, Layout } from "antd";
import { lazy, Suspense, useEffect } from "react"; import { 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, Routes, useNavigate } from "react-router-dom"; import { Route, Routes, useNavigate } from "react-router-dom";
@@ -15,25 +15,26 @@ import { selectTechnician } from "../../redux/tech/tech.selectors";
import InstanceRenderManager from "../../utils/instanceRenderMgr"; import InstanceRenderManager from "../../utils/instanceRenderMgr";
import "./tech.page.styles.scss"; import "./tech.page.styles.scss";
import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component.jsx"; import UpsellComponent, { upsellEnum } from "../../components/upsell/upsell.component.jsx";
import { lazyDev } from "../../utils/lazyWithPreload.jsx";
const TimeTicketModalContainer = lazy(() => import("../../components/time-ticket-modal/time-ticket-modal.container")); const TimeTicketModalContainer = lazyDev(() => import("../../components/time-ticket-modal/time-ticket-modal.container"));
const EmailOverlayContainer = lazy(() => import("../../components/email-overlay/email-overlay.container.jsx")); const EmailOverlayContainer = lazyDev(() => import("../../components/email-overlay/email-overlay.container.jsx"));
const PrintCenterModalContainer = lazy( const PrintCenterModalContainer = lazyDev(
() => 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")); const TechLogin = lazyDev(() => import("../../components/tech-login/tech-login.component"));
const TechLookup = lazy(() => import("../tech-lookup/tech-lookup.container")); const TechLookup = lazyDev(() => import("../tech-lookup/tech-lookup.container"));
const ProductionListPage = lazy(() => import("../production-list/production-list.container")); const ProductionListPage = lazyDev(() => import("../production-list/production-list.container"));
const ProductionBoardPage = lazy(() => import("../production-board/production-board.container")); const ProductionBoardPage = lazyDev(() => import("../production-board/production-board.container"));
const TechJobClock = lazy(() => import("../tech-job-clock/tech-job-clock.component")); const TechJobClock = lazyDev(() => import("../tech-job-clock/tech-job-clock.component"));
const TechShiftClock = lazy(() => import("../tech-shift-clock/tech-shift-clock.component")); const TechShiftClock = lazyDev(() => import("../tech-shift-clock/tech-shift-clock.component"));
const TimeTicketModalTask = lazy( const TimeTicketModalTask = lazyDev(
() => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container") () => import("../../components/time-ticket-task-modal/time-ticket-task-modal.container")
); );
const TechAssignedProdJobs = lazy(() => import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component")); const TechAssignedProdJobs = lazyDev(() => import("../tech-assigned-prod-jobs/tech-assigned-prod-jobs.component"));
const TechDispatchedParts = lazy(() => import("../tech-dispatched-parts/tech-dispatched-parts.page")); const TechDispatchedParts = lazyDev(() => import("../tech-dispatched-parts/tech-dispatched-parts.page"));
const TaskUpsertModalContainer = lazy(() => import("../../components/task-upsert-modal/task-upsert-modal.container")); const TaskUpsertModalContainer = lazyDev(() => import("../../components/task-upsert-modal/task-upsert-modal.container"));
const { Content } = Layout; const { Content } = Layout;

View File

@@ -0,0 +1,35 @@
import { lazy } from "react";
/**
* Conditionally uses lazy loading based on environment.
* By default, uses React.lazy in all environments.
* Set VITE_DISABLE_LAZY_LOADING=true to load modules immediately in development (avoids compilation delays).
*
* Usage: const MyComponent = lazyDev(() => import('./MyComponent'));
*/
export const lazyDev = (importFunc) => {
// Check if lazy loading should be disabled (dev only, opt-in via env var)
const disableLazyLoading = import.meta.env.DEV && import.meta.env?.VITE_DISABLE_LAZY_LOADING === "true";
if (!disableLazyLoading) {
// Default behavior: use React.lazy for code splitting
return lazy(importFunc);
}
// Dev mode with lazy loading disabled: load immediately to avoid delays
let Component = null;
const promise = importFunc().then((module) => {
Component = module.default;
});
const LazyDevComponent = (props) => {
if (!Component) {
throw promise; // Suspense will catch this
}
return <Component {...props} />;
};
LazyDevComponent.displayName = "LazyDevComponent";
return LazyDevComponent;
};

View File

@@ -11,6 +11,8 @@ import { VitePWA } from "vite-plugin-pwa";
import InstanceRenderManager from "./src/utils/instanceRenderMgr"; import InstanceRenderManager from "./src/utils/instanceRenderMgr";
import browserslist from "browserslist"; import browserslist from "browserslist";
import { browserslistToTargets } from "lightningcss"; import { browserslistToTargets } from "lightningcss";
import { fileURLToPath } from "url";
import { dirname, resolve } from "path";
process.env.VITE_APP_GIT_SHA_DATE = new Date().toLocaleString("en-US", { timeZone: "America/Los_Angeles" }); process.env.VITE_APP_GIT_SHA_DATE = new Date().toLocaleString("en-US", { timeZone: "America/Los_Angeles" });
const commitHash = child.execSync("git rev-parse HEAD").toString().trimEnd(); const commitHash = child.execSync("git rev-parse HEAD").toString().trimEnd();
@@ -43,13 +45,19 @@ const httpsCerts = {
cert: await fsPromises.readFile("../certs/cert.pem") cert: await fsPromises.readFile("../certs/cert.pem")
}; };
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
export default defineConfig(({ command, mode }) => { export default defineConfig(({ command, mode }) => {
// Only enable React Compiler on build in production/test (keeps dev as fast as possible) // React Compiler is always enabled for production/test builds
// In dev mode, it's enabled by default but can be disabled with VITE_DISABLE_COMPILER_IN_DEV=true
const isBuild = command === "build"; const isBuild = command === "build";
const isTestBuild = const isTestBuild =
mode === "test" || process.env.VITE_APP_IS_TEST === "true" || process.env.VITE_APP_IS_TEST === "1"; mode === "test" || process.env.VITE_APP_IS_TEST === "true" || process.env.VITE_APP_IS_TEST === "1";
const enableReactCompiler = const enableReactCompiler =
process.env.VITE_ENABLE_COMPILER_IN_DEV || (isBuild && (mode === "production" || isTestBuild)); (isBuild && (mode === "production" || isTestBuild)) || // Always enable for prod/test builds
process.env?.VITE_DISABLE_COMPILER_IN_DEV !== "true"; // In dev, enable unless explicitly disabled
logger.info( logger.info(
enableReactCompiler ? chalk.green.bold("React Compiler enabled") : chalk.yellow.bold("React Compiler disabled") enableReactCompiler ? chalk.green.bold("React Compiler enabled") : chalk.yellow.bold("React Compiler disabled")
@@ -57,6 +65,13 @@ export default defineConfig(({ command, mode }) => {
return { return {
base: "/", base: "/",
resolve: {
dedupe: ["styled-components", "react", "react-dom"],
alias: {
// Force all styled-components imports to resolve to the same location (absolute path)
"styled-components": resolve(__dirname, "node_modules/styled-components/dist/styled-components.browser.esm.js")
}
},
plugins: [ plugins: [
ViteEjsPlugin((viteConfig) => ({ env: viteConfig.env })), ViteEjsPlugin((viteConfig) => ({ env: viteConfig.env })),
@@ -243,7 +258,8 @@ export default defineConfig(({ command, mode }) => {
// Strip console/debugger in prod to shrink bundles // Strip console/debugger in prod to shrink bundles
esbuild: { esbuild: {
//drop: ["console", "debugger"] // drop: mode === "production" ? ["console", "debugger"] : [],
legalComments: "none" // Remove license comments in production
}, },
optimizeDeps: { optimizeDeps: {
@@ -265,11 +281,14 @@ export default defineConfig(({ command, mode }) => {
"@firebase/firestore", "@firebase/firestore",
"@firebase/auth", "@firebase/auth",
"@firebase/messaging", "@firebase/messaging",
"@firebase/util" "@firebase/util",
"styled-components"
], ],
esbuildOptions: { esbuildOptions: {
loader: { ".jsx": "jsx", ".tsx": "tsx" } loader: { ".jsx": "jsx", ".tsx": "tsx" }
} },
// Force styled-components to be pre-bundled and deduplicated
force: mode === "development"
}, },
css: { css: {