2026-03-14 14:44:40 -05:00
|
|
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
|
|
|
import React from "react";
|
|
|
|
|
import ReactDOM from "react-dom/client";
|
|
|
|
|
import { createBrowserRouter, Navigate, RouterProvider } from "react-router-dom";
|
|
|
|
|
import { permissions } from "@mrp/shared";
|
|
|
|
|
|
|
|
|
|
import { AppShell } from "./components/AppShell";
|
|
|
|
|
import { ProtectedRoute } from "./components/ProtectedRoute";
|
|
|
|
|
import { AuthProvider } from "./auth/AuthProvider";
|
|
|
|
|
import { DashboardPage } from "./modules/dashboard/DashboardPage";
|
|
|
|
|
import { LoginPage } from "./modules/login/LoginPage";
|
|
|
|
|
import { ThemeProvider } from "./theme/ThemeProvider";
|
|
|
|
|
import "./index.css";
|
|
|
|
|
|
|
|
|
|
const queryClient = new QueryClient();
|
|
|
|
|
|
2026-03-15 14:47:58 -05:00
|
|
|
const CompanySettingsPage = React.lazy(() =>
|
|
|
|
|
import("./modules/settings/CompanySettingsPage").then((module) => ({ default: module.CompanySettingsPage }))
|
|
|
|
|
);
|
|
|
|
|
const AdminDiagnosticsPage = React.lazy(() =>
|
|
|
|
|
import("./modules/settings/AdminDiagnosticsPage").then((module) => ({ default: module.AdminDiagnosticsPage }))
|
|
|
|
|
);
|
|
|
|
|
const UserManagementPage = React.lazy(() =>
|
|
|
|
|
import("./modules/settings/UserManagementPage").then((module) => ({ default: module.UserManagementPage }))
|
|
|
|
|
);
|
|
|
|
|
const CustomersPage = React.lazy(() =>
|
|
|
|
|
import("./modules/crm/CustomersPage").then((module) => ({ default: module.CustomersPage }))
|
|
|
|
|
);
|
|
|
|
|
const VendorsPage = React.lazy(() =>
|
|
|
|
|
import("./modules/crm/VendorsPage").then((module) => ({ default: module.VendorsPage }))
|
|
|
|
|
);
|
|
|
|
|
const CrmDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/crm/CrmDetailPage").then((module) => ({ default: module.CrmDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const CrmFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/crm/CrmFormPage").then((module) => ({ default: module.CrmFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const InventoryItemsPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/InventoryItemsPage").then((module) => ({ default: module.InventoryItemsPage }))
|
|
|
|
|
);
|
|
|
|
|
const InventoryDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/InventoryDetailPage").then((module) => ({ default: module.InventoryDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const InventoryFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/InventoryFormPage").then((module) => ({ default: module.InventoryFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const WarehousesPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/WarehousesPage").then((module) => ({ default: module.WarehousesPage }))
|
|
|
|
|
);
|
|
|
|
|
const WarehouseDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/WarehouseDetailPage").then((module) => ({ default: module.WarehouseDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const WarehouseFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/inventory/WarehouseFormPage").then((module) => ({ default: module.WarehouseFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const ProjectsPage = React.lazy(() =>
|
|
|
|
|
import("./modules/projects/ProjectsPage").then((module) => ({ default: module.ProjectsPage }))
|
|
|
|
|
);
|
|
|
|
|
const ProjectDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/projects/ProjectDetailPage").then((module) => ({ default: module.ProjectDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const ProjectFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/projects/ProjectFormPage").then((module) => ({ default: module.ProjectFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const ManufacturingPage = React.lazy(() =>
|
|
|
|
|
import("./modules/manufacturing/ManufacturingPage").then((module) => ({ default: module.ManufacturingPage }))
|
|
|
|
|
);
|
|
|
|
|
const WorkOrderDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/manufacturing/WorkOrderDetailPage").then((module) => ({ default: module.WorkOrderDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const WorkOrderFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/manufacturing/WorkOrderFormPage").then((module) => ({ default: module.WorkOrderFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const PurchaseListPage = React.lazy(() =>
|
|
|
|
|
import("./modules/purchasing/PurchaseListPage").then((module) => ({ default: module.PurchaseListPage }))
|
|
|
|
|
);
|
|
|
|
|
const PurchaseDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/purchasing/PurchaseDetailPage").then((module) => ({ default: module.PurchaseDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const PurchaseFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/purchasing/PurchaseFormPage").then((module) => ({ default: module.PurchaseFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const SalesListPage = React.lazy(() =>
|
|
|
|
|
import("./modules/sales/SalesListPage").then((module) => ({ default: module.SalesListPage }))
|
|
|
|
|
);
|
|
|
|
|
const SalesDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/sales/SalesDetailPage").then((module) => ({ default: module.SalesDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const SalesFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/sales/SalesFormPage").then((module) => ({ default: module.SalesFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const ShipmentListPage = React.lazy(() =>
|
|
|
|
|
import("./modules/shipping/ShipmentListPage").then((module) => ({ default: module.ShipmentListPage }))
|
|
|
|
|
);
|
|
|
|
|
const ShipmentDetailPage = React.lazy(() =>
|
|
|
|
|
import("./modules/shipping/ShipmentDetailPage").then((module) => ({ default: module.ShipmentDetailPage }))
|
|
|
|
|
);
|
|
|
|
|
const ShipmentFormPage = React.lazy(() =>
|
|
|
|
|
import("./modules/shipping/ShipmentFormPage").then((module) => ({ default: module.ShipmentFormPage }))
|
|
|
|
|
);
|
|
|
|
|
const GanttPage = React.lazy(() =>
|
|
|
|
|
import("./modules/gantt/GanttPage").then((module) => ({ default: module.GanttPage }))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
function RouteFallback() {
|
|
|
|
|
return (
|
|
|
|
|
<div className="rounded-[28px] border border-line/70 bg-surface/90 p-4 text-sm text-muted shadow-panel">
|
|
|
|
|
Loading module...
|
|
|
|
|
</div>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function lazyElement(element: React.ReactNode) {
|
|
|
|
|
return <React.Suspense fallback={<RouteFallback />}>{element}</React.Suspense>;
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 14:44:40 -05:00
|
|
|
const router = createBrowserRouter([
|
|
|
|
|
{ path: "/login", element: <LoginPage /> },
|
|
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute />,
|
|
|
|
|
children: [
|
|
|
|
|
{
|
|
|
|
|
element: <AppShell />,
|
|
|
|
|
children: [
|
|
|
|
|
{ path: "/", element: <DashboardPage /> },
|
|
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.companyRead]} />,
|
2026-03-15 14:47:58 -05:00
|
|
|
children: [{ path: "/settings/company", element: lazyElement(<CompanySettingsPage />) }],
|
2026-03-14 14:44:40 -05:00
|
|
|
},
|
2026-03-15 14:11:21 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.adminManage]} />,
|
2026-03-15 14:47:58 -05:00
|
|
|
children: [
|
|
|
|
|
{ path: "/settings/admin-diagnostics", element: lazyElement(<AdminDiagnosticsPage />) },
|
|
|
|
|
{ path: "/settings/users", element: lazyElement(<UserManagementPage />) },
|
|
|
|
|
],
|
2026-03-15 14:11:21 -05:00
|
|
|
},
|
2026-03-14 14:44:40 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.crmRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/crm/customers", element: lazyElement(<CustomersPage />) },
|
|
|
|
|
{ path: "/crm/customers/:customerId", element: lazyElement(<CrmDetailPage entity="customer" />) },
|
|
|
|
|
{ path: "/crm/vendors", element: lazyElement(<VendorsPage />) },
|
|
|
|
|
{ path: "/crm/vendors/:vendorId", element: lazyElement(<CrmDetailPage entity="vendor" />) },
|
2026-03-14 16:08:29 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 21:10:35 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.inventoryRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/inventory/items", element: lazyElement(<InventoryItemsPage />) },
|
|
|
|
|
{ path: "/inventory/items/:itemId", element: lazyElement(<InventoryDetailPage />) },
|
|
|
|
|
{ path: "/inventory/warehouses", element: lazyElement(<WarehousesPage />) },
|
|
|
|
|
{ path: "/inventory/warehouses/:warehouseId", element: lazyElement(<WarehouseDetailPage />) },
|
2026-03-14 21:10:35 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 10:13:53 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.projectsRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/projects", element: lazyElement(<ProjectsPage />) },
|
|
|
|
|
{ path: "/projects/:projectId", element: lazyElement(<ProjectDetailPage />) },
|
2026-03-15 10:13:53 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 11:12:58 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.manufacturingRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/manufacturing/work-orders", element: lazyElement(<ManufacturingPage />) },
|
|
|
|
|
{ path: "/manufacturing/work-orders/:workOrderId", element: lazyElement(<WorkOrderDetailPage />) },
|
2026-03-15 11:12:58 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 00:29:41 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={["purchasing.read"]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/purchasing/orders", element: lazyElement(<PurchaseListPage />) },
|
|
|
|
|
{ path: "/purchasing/orders/:orderId", element: lazyElement(<PurchaseDetailPage />) },
|
2026-03-15 00:29:41 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 23:03:17 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.salesRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/sales/quotes", element: lazyElement(<SalesListPage entity="quote" />) },
|
|
|
|
|
{ path: "/sales/quotes/:quoteId", element: lazyElement(<SalesDetailPage entity="quote" />) },
|
|
|
|
|
{ path: "/sales/orders", element: lazyElement(<SalesListPage entity="order" />) },
|
|
|
|
|
{ path: "/sales/orders/:orderId", element: lazyElement(<SalesDetailPage entity="order" />) },
|
2026-03-14 23:03:17 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 23:48:27 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.shippingRead]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/shipping/shipments", element: lazyElement(<ShipmentListPage />) },
|
|
|
|
|
{ path: "/shipping/shipments/:shipmentId", element: lazyElement(<ShipmentDetailPage />) },
|
2026-03-14 23:48:27 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 16:08:29 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.crmWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/crm/customers/new", element: lazyElement(<CrmFormPage entity="customer" mode="create" />) },
|
|
|
|
|
{ path: "/crm/customers/:customerId/edit", element: lazyElement(<CrmFormPage entity="customer" mode="edit" />) },
|
|
|
|
|
{ path: "/crm/vendors/new", element: lazyElement(<CrmFormPage entity="vendor" mode="create" />) },
|
|
|
|
|
{ path: "/crm/vendors/:vendorId/edit", element: lazyElement(<CrmFormPage entity="vendor" mode="edit" />) },
|
2026-03-14 14:44:40 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 10:13:53 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.projectsWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/projects/new", element: lazyElement(<ProjectFormPage mode="create" />) },
|
|
|
|
|
{ path: "/projects/:projectId/edit", element: lazyElement(<ProjectFormPage mode="edit" />) },
|
2026-03-15 10:13:53 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 11:12:58 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.manufacturingWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/manufacturing/work-orders/new", element: lazyElement(<WorkOrderFormPage mode="create" />) },
|
|
|
|
|
{ path: "/manufacturing/work-orders/:workOrderId/edit", element: lazyElement(<WorkOrderFormPage mode="edit" />) },
|
2026-03-15 11:12:58 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-15 00:29:41 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={["purchasing.write"]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/purchasing/orders/new", element: lazyElement(<PurchaseFormPage mode="create" />) },
|
|
|
|
|
{ path: "/purchasing/orders/:orderId/edit", element: lazyElement(<PurchaseFormPage mode="edit" />) },
|
2026-03-15 00:29:41 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 23:03:17 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.salesWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/sales/quotes/new", element: lazyElement(<SalesFormPage entity="quote" mode="create" />) },
|
|
|
|
|
{ path: "/sales/quotes/:quoteId/edit", element: lazyElement(<SalesFormPage entity="quote" mode="edit" />) },
|
|
|
|
|
{ path: "/sales/orders/new", element: lazyElement(<SalesFormPage entity="order" mode="create" />) },
|
|
|
|
|
{ path: "/sales/orders/:orderId/edit", element: lazyElement(<SalesFormPage entity="order" mode="edit" />) },
|
2026-03-14 23:03:17 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 23:48:27 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.shippingWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/shipping/shipments/new", element: lazyElement(<ShipmentFormPage mode="create" />) },
|
|
|
|
|
{ path: "/shipping/shipments/:shipmentId/edit", element: lazyElement(<ShipmentFormPage mode="edit" />) },
|
2026-03-14 23:48:27 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 21:10:35 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.inventoryWrite]} />,
|
|
|
|
|
children: [
|
2026-03-15 14:47:58 -05:00
|
|
|
{ path: "/inventory/items/new", element: lazyElement(<InventoryFormPage mode="create" />) },
|
|
|
|
|
{ path: "/inventory/items/:itemId/edit", element: lazyElement(<InventoryFormPage mode="edit" />) },
|
|
|
|
|
{ path: "/inventory/warehouses/new", element: lazyElement(<WarehouseFormPage mode="create" />) },
|
|
|
|
|
{ path: "/inventory/warehouses/:warehouseId/edit", element: lazyElement(<WarehouseFormPage mode="edit" />) },
|
2026-03-14 21:10:35 -05:00
|
|
|
],
|
|
|
|
|
},
|
2026-03-14 14:44:40 -05:00
|
|
|
{
|
|
|
|
|
element: <ProtectedRoute requiredPermissions={[permissions.ganttRead]} />,
|
2026-03-15 14:47:58 -05:00
|
|
|
children: [{ path: "/planning/gantt", element: lazyElement(<GanttPage />) }],
|
2026-03-14 14:44:40 -05:00
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{ path: "*", element: <Navigate to="/" replace /> },
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
|
|
|
<React.StrictMode>
|
|
|
|
|
<ThemeProvider>
|
|
|
|
|
<QueryClientProvider client={queryClient}>
|
|
|
|
|
<AuthProvider>
|
|
|
|
|
<RouterProvider router={router} />
|
|
|
|
|
</AuthProvider>
|
|
|
|
|
</QueryClientProvider>
|
|
|
|
|
</ThemeProvider>
|
|
|
|
|
</React.StrictMode>
|
|
|
|
|
);
|