diff --git a/apps/web/src/app-routes.tsx b/apps/web/src/app-routes.tsx
new file mode 100644
index 00000000..aa442b1a
--- /dev/null
+++ b/apps/web/src/app-routes.tsx
@@ -0,0 +1,64 @@
+import { AppLayout, LoadingOverlay, ScrollToTop } from "@repo/rdx-ui/components";
+import { JSX, Suspense } from "react";
+import { Route, BrowserRouter as Router, Routes } from "react-router-dom";
+import { ErrorPage } from "./pages";
+import { modules } from "./register-modules"; // Aquí ca
+
+// Lazy load components
+//const ErrorPage = lazy(() => import("./pages").then((m) => ({ default: m.ErrorPage })));
+
+//const LogoutPage = lazy(() => import("./app").then((m) => ({ default: m.LogoutPage })));
+
+/*const DealerLayout = lazy(() => import("./app").then((m) => ({ default: m.DealerLayout })));
+const DealersList = lazy(() => import("./app").then((m) => ({ default: m.DealersList })));
+
+const LoginPageWithLanguageSelector = lazy(() =>
+ import("./app").then((m) => ({ default: m.LoginPageWithLanguageSelector }))
+);
+
+const QuoteCreate = lazy(() => import("./app").then((m) => ({ default: m.QuoteCreate })));
+const QuoteEdit = lazy(() => import("./app").then((m) => ({ default: m.QuoteEdit })));
+const SettingsEditor = lazy(() => import("./app").then((m) => ({ default: m.SettingsEditor })));
+const SettingsLayout = lazy(() => import("./app").then((m) => ({ default: m.SettingsLayout })));
+const CatalogLayout = lazy(() => import("./app").then((m) => ({ default: m.CatalogLayout })));
+const CatalogList = lazy(() => import("./app").then((m) => ({ default: m.CatalogList })));
+const DashboardPage = lazy(() => import("./app").then((m) => ({ default: m.DashboardPage })));
+const QuotesLayout = lazy(() => import("./app").then((m) => ({ default: m.QuotesLayout })));
+const QuotesList = lazy(() => import("./app").then((m) => ({ default: m.QuotesList })));*/
+
+export const AppRoutes = (): JSX.Element => {
+ return (
+
+
+
+ }>
+
+ }>
+ {/* Main Layout */}
+ } />
+ } />
+ } />
+ } />
+ } />
+
+ {/* Dynamic Module Routes */}
+
+ {modules.map((module) => {
+ if (module.routes) {
+ return module.routes();
+ }
+ return null;
+ })}
+
+
+ {/* Auth Layout */}
+ {/*} />
+ } />*/}
+
+ {/* Fallback Route */}
+ } />
+
+
+
+ );
+};
diff --git a/apps/web/src/App.css b/apps/web/src/app.css
similarity index 100%
rename from apps/web/src/App.css
rename to apps/web/src/app.css
diff --git a/apps/web/src/App.tsx b/apps/web/src/app.tsx
similarity index 52%
rename from apps/web/src/App.tsx
rename to apps/web/src/app.tsx
index b8b0b78b..b2d62ffa 100644
--- a/apps/web/src/App.tsx
+++ b/apps/web/src/app.tsx
@@ -1,18 +1,16 @@
-import { LoadingOverlay, TailwindIndicator } from "@repo/rdx-ui/components";
import { Toaster, TooltipProvider } from "@repo/shadcn-ui/components";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
-import { Suspense } from "react";
import { I18nextProvider } from "react-i18next";
import { createAxiosDataProvider } from "@/lib/axios/create-axios-data-provider";
-import { DataSourceProvider, ThemeProvider, UnsavedWarnProvider } from "@/lib/hooks";
+import { DataSourceProvider, UnsavedWarnProvider } from "@/lib/hooks";
import { i18n } from "@/locales";
-import "./App.css";
-import { Routes } from "./routes";
+import { AppRoutes } from "./app-routes";
+import "./app.css";
-function App() {
+export const App = () => {
const queryClient = new QueryClient({
defaultOptions: {
queries: {
@@ -26,22 +24,16 @@ function App() {
-
-
-
- }>
-
-
-
-
-
-
- {import.meta.env.MODE === "development" && }
-
+
+
+
+
+
+
+
+ {import.meta.env.MODE === "development" && }
);
-}
-
-export default App;
+};
diff --git a/apps/web/src/main.tsx b/apps/web/src/main.tsx
index 902681bd..ff16b184 100644
--- a/apps/web/src/main.tsx
+++ b/apps/web/src/main.tsx
@@ -1,6 +1,8 @@
+import { ThemeProvider } from "@/lib/hooks";
+import { TailwindIndicator } from "@repo/rdx-ui/components";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
-import App from "./App.tsx";
+import { App } from "./app.tsx";
import "./global.css";
@@ -8,7 +10,10 @@ const rootElement = document.getElementById("factuges");
if (rootElement) {
createRoot(rootElement).render(
-
+
+
+
+
);
} else {
diff --git a/apps/web/src/routes.tsx b/apps/web/src/routes.tsx
deleted file mode 100644
index 195b5dc9..00000000
--- a/apps/web/src/routes.tsx
+++ /dev/null
@@ -1,197 +0,0 @@
-import { LoadingOverlay } from "@repo/rdx-ui/components";
-import { Suspense, lazy } from "react";
-import { RouteObject, RouterProvider, createBrowserRouter } from "react-router-dom";
-import { modules } from "./register-modules"; // Aquí ca
-
-// Lazy load components
-const ErrorPage = lazy(() => import("./pages").then((m) => ({ default: m.ErrorPage })));
-
-//const LogoutPage = lazy(() => import("./app").then((m) => ({ default: m.LogoutPage })));
-
-/*const DealerLayout = lazy(() => import("./app").then((m) => ({ default: m.DealerLayout })));
-const DealersList = lazy(() => import("./app").then((m) => ({ default: m.DealersList })));
-
-const LoginPageWithLanguageSelector = lazy(() =>
- import("./app").then((m) => ({ default: m.LoginPageWithLanguageSelector }))
-);
-
-const QuoteCreate = lazy(() => import("./app").then((m) => ({ default: m.QuoteCreate })));
-const QuoteEdit = lazy(() => import("./app").then((m) => ({ default: m.QuoteEdit })));
-const SettingsEditor = lazy(() => import("./app").then((m) => ({ default: m.SettingsEditor })));
-const SettingsLayout = lazy(() => import("./app").then((m) => ({ default: m.SettingsLayout })));
-const CatalogLayout = lazy(() => import("./app").then((m) => ({ default: m.CatalogLayout })));
-const CatalogList = lazy(() => import("./app").then((m) => ({ default: m.CatalogList })));
-const DashboardPage = lazy(() => import("./app").then((m) => ({ default: m.DashboardPage })));
-const QuotesLayout = lazy(() => import("./app").then((m) => ({ default: m.QuotesLayout })));
-const QuotesList = lazy(() => import("./app").then((m) => ({ default: m.QuotesList })));*/
-
-export const Routes = () => {
- const routesForErrors = [
- {
- path: "*",
- Element: (
- }>
-
-
- ),
- },
- ];
-
- const routesForModules: RouteObject[] = [];
-
- modules.map((module) => {
- if (module.routes) {
- routesForModules.push(...module.routes());
- }
- });
-
- // Define routes accessible only to authenticated users
- /*const routesForAuthenticatedOnly = [
- {
- path: "/",
- element: (
-
-
-
- ),
- },
- {
- path: "/home",
- element: (
-
- }>
-
-
-
- ),
- },
- {
- path: "/catalog",
- element: (
- }>
-
-
-
-
- ),
- children: [
- {
- index: true,
- element: (
- }>
-
-
- ),
- },
- ],
- },
- {
- path: "/dealers",
- element: (
- }>
-
-
-
-
- ),
- children: [
- {
- index: true,
- element: (
- }>
-
-
- ),
- },
- ],
- },
- {
- path: "/quotes",
- element: (
- }>
-
-
-
-
- ),
- children: [
- {
- index: true,
- element: (
- }>
-
-
- ),
- },
- {
- path: "add",
- element: (
- }>
-
-
- ),
- },
- {
- path: "edit/:id",
- element: (
- }>
-
-
- ),
- },
- ],
- },
- {
- path: "/settings",
- element: (
- }>
-
-
-
-
- ),
- children: [
- {
- index: true,
- element: (
- }>
-
-
- ),
- },
- ],
- },
- {
- path: "/logout",
- element: ,
- },
- ];
-
- // Define routes accessible only to non-authenticated users
- const routesForNotAuthenticatedOnly = [
- {
- path: "/login",
- element: (
- }>
-
-
- ),
- },
- ];*/
-
- // Combine and conditionally include routes based on authentication status
- const router = createBrowserRouter(
- [
- //...routesForAuthenticatedOnly,
- //...routesForNotAuthenticatedOnly,
- ...routesForErrors,
- ...routesForModules,
- ],
- {
- //basename: "/app",
- }
- );
-
- // Provide the router configuration using RouterProvider
- return ;
-};
diff --git a/modules/core/src/modules/module-client.interface.ts b/modules/core/src/modules/module-client.interface.ts
index ea4cd097..9db99c4e 100644
--- a/modules/core/src/modules/module-client.interface.ts
+++ b/modules/core/src/modules/module-client.interface.ts
@@ -1,5 +1,4 @@
-import React, { ReactNode } from "react";
-import { RouteObject } from "react-router-dom";
+import React, { JSX, ReactNode } from "react";
import { ModuleMetadata } from "./types";
export interface ModuleClientMetadata extends ModuleMetadata {
@@ -9,7 +8,7 @@ export interface ModuleClientMetadata extends ModuleMetadata {
export interface IModuleClient {
metadata: ModuleClientMetadata;
- routes?: () => RouteObject[];
+ routes?: () => JSX.Element;
component?: React.FC;
setup?(): void;
}
diff --git a/modules/invoices/package.json b/modules/invoices/package.json
index 34cf8345..85a8984a 100644
--- a/modules/invoices/package.json
+++ b/modules/invoices/package.json
@@ -18,7 +18,8 @@
"ag-grid-community": "^33.3.0",
"i18next": "^25.1.1",
"react": "^18 || ^19",
- "react-dom": "^18 || ^19"
+ "react-dom": "^18 || ^19",
+ "react-router-dom": "^6.26.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
diff --git a/modules/invoices/src/web/components/invoices-grid.tsx b/modules/invoices/src/web/components/invoices-grid.tsx
index 847e3534..48fd0110 100644
--- a/modules/invoices/src/web/components/invoices-grid.tsx
+++ b/modules/invoices/src/web/components/invoices-grid.tsx
@@ -57,8 +57,9 @@ export const InvoicesGrid = () => {
{
field: "mission",
filter: true,
+ minWidth: 200,
},
- { field: "company" },
+ { field: "company", filter: false },
{ field: "location" },
{ field: "date" },
{
@@ -75,12 +76,17 @@ export const InvoicesGrid = () => {
const defaultColDef = useMemo(() => {
return {
filter: true,
+ sortable: false,
+ resizable: false,
};
}, []);
// Container: Defines the grid's theme & dimensions.
return (
-
+
{
const { t } = useTranslation("invoices");
return (
-
-
-
-
-
-
-
+ <>
+
+ {children}
+ >
);
};
diff --git a/modules/invoices/src/web/routes.tsx b/modules/invoices/src/web/invoice-routes.tsx
similarity index 61%
rename from modules/invoices/src/web/routes.tsx
rename to modules/invoices/src/web/invoice-routes.tsx
index e142cdbb..f0ad627b 100644
--- a/modules/invoices/src/web/routes.tsx
+++ b/modules/invoices/src/web/invoice-routes.tsx
@@ -1,8 +1,6 @@
//import { ProtectedRoute } from "@erp/auth/components";
-import { LoadingOverlay } from "@repo/rdx-ui/components";
-import { Suspense, lazy } from "react";
-import { Outlet, RouteObject } from "react-router-dom";
-import { InvoicesGrid } from "./components";
+import { JSX, lazy } from "react";
+import { Route } from "react-router-dom";
// Lazy load components
const InvoicesLayout = lazy(() =>
@@ -29,32 +27,24 @@ const DashboardPage = lazy(() => import("./app").then((m) => ({ default: m.Dashb
const InvoicesLayout = lazy(() => import("./app").then((m) => ({ default: m.InvoicesLayout })));
const InvoicesList = lazy(() => import("./app").then((m) => ({ default: m.InvoicesList })));*/
-export const InvoiceRoutes = (): RouteObject[] => {
- // Define routes accessible only to authenticated users
- const privateRoutes: RouteObject[] = [
- {
- path: "/invoices",
- element: (
- }>
-
-
-
-
- ),
- children: [
- {
- index: true,
- element: ,
- },
- ],
- },
- ];
+export const InvoiceRoutes = (): JSX.Element => {
+ return (
+ }>
+ } />
+ } />
- // Define routes accessible only to non-authenticated users
- const publicRoutes = [{}];
+ {/*} />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />*/}
- return privateRoutes;
-
- // Provide the router configuration using RouterProvider
- //return ;
+ } />
+
+ );
};
diff --git a/modules/invoices/src/web/manifest.ts b/modules/invoices/src/web/manifest.ts
index 20d5979c..ef53991f 100644
--- a/modules/invoices/src/web/manifest.ts
+++ b/modules/invoices/src/web/manifest.ts
@@ -2,7 +2,7 @@ import { IModuleClient } from "@erp/core";
import i18next from "i18next";
import enResources from "../common/locales/en.json";
import esResources from "../common/locales/es.json";
-import { InvoiceRoutes } from "./routes";
+import { InvoiceRoutes } from "./invoice-routes";
const MODULE_NAME = "invoices";
const MODULE_VERSION = "1.0.0";
diff --git a/packages/rdx-ui/package.json b/packages/rdx-ui/package.json
index 6048e810..d460ebc1 100644
--- a/packages/rdx-ui/package.json
+++ b/packages/rdx-ui/package.json
@@ -16,7 +16,8 @@
},
"peerDependencies": {
"react": "^18 || ^19",
- "react-dom": "^18 || ^19"
+ "react-dom": "^18 || ^19",
+ "react-router": "^6.26.0"
},
"devDependencies": {
"@biomejs/biome": "1.9.4",
@@ -49,6 +50,7 @@
"react-dom": "^19.1.0",
"react-i18next": "^15.5.1",
"react-router-dom": "^6.26.0",
+ "react-router": "^6.26.0",
"recharts": "^2.15.3",
"sonner": "^2.0.3",
"zod": "^3.24.4"
diff --git a/packages/rdx-ui/src/components/index.tsx b/packages/rdx-ui/src/components/index.tsx
index 7b66fa07..8c1124d2 100644
--- a/packages/rdx-ui/src/components/index.tsx
+++ b/packages/rdx-ui/src/components/index.tsx
@@ -1,5 +1,7 @@
-export * from "./tailwind-indicator.tsx";
-export * from "./loading-overlay/index.tsx";
+export * from "./buttons/index.tsx";
export * from "./custom-dialog.tsx";
export * from "./error-overlay.tsx";
-export * from "./buttons/index.tsx";
+export * from "./layout/index.tsx";
+export * from "./loading-overlay/index.tsx";
+export * from "./scroll-to-top.tsx";
+export * from "./tailwind-indicator.tsx";
diff --git a/packages/rdx-ui/src/components/layout/app-layout.tsx b/packages/rdx-ui/src/components/layout/app-layout.tsx
new file mode 100644
index 00000000..add928af
--- /dev/null
+++ b/packages/rdx-ui/src/components/layout/app-layout.tsx
@@ -0,0 +1,30 @@
+import { SidebarInset, SidebarProvider } from "@repo/shadcn-ui/components";
+import { Outlet } from "react-router";
+import { AppSidebar } from "./app-sidebar.tsx";
+import { SiteHeader } from "./site-header.tsx";
+
+export const AppLayout: React.FC = () => {
+ return (
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/packages/rdx-ui/src/components/layout/index.tsx b/packages/rdx-ui/src/components/layout/index.tsx
index 6175d1d0..615e1c50 100644
--- a/packages/rdx-ui/src/components/layout/index.tsx
+++ b/packages/rdx-ui/src/components/layout/index.tsx
@@ -1,9 +1 @@
-export * from "./app-sidebar.tsx";
-export * from "./chart-area-interactive.tsx";
-export * from "./data-table.tsx";
-export * from "./nav-documents.tsx";
-export * from "./nav-main.tsx";
-export * from "./nav-secondary.tsx";
-export * from "./nav-user.tsx";
-export * from "./section-cards.tsx";
-export * from "./site-header.tsx";
+export * from "./app-layout.tsx";
diff --git a/packages/rdx-ui/src/components/scroll-to-top.tsx b/packages/rdx-ui/src/components/scroll-to-top.tsx
new file mode 100644
index 00000000..361916b6
--- /dev/null
+++ b/packages/rdx-ui/src/components/scroll-to-top.tsx
@@ -0,0 +1,17 @@
+import { useEffect } from "react";
+import { useLocation } from "react-router";
+
+export function ScrollToTop() {
+ const { pathname } = useLocation();
+
+ // biome-ignore lint/correctness/useExhaustiveDependencies:
+ useEffect(() => {
+ window.scrollTo({
+ top: 0,
+ left: 0,
+ behavior: "smooth",
+ });
+ }, [pathname]);
+
+ return null;
+}
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 81e19382..32135970 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -170,7 +170,7 @@ importers:
version: 29.7.0(@types/node@22.15.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3))
ts-jest:
specifier: ^29.2.5
- version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@22.15.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3)))(typescript@5.8.3)
+ version: 29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.4)(jest@29.7.0(@types/node@22.15.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3)))(typescript@5.8.3)
tsconfig-paths:
specifier: ^4.2.0
version: 4.2.0
@@ -507,6 +507,9 @@ importers:
react-i18next:
specifier: ^15.5.1
version: 15.5.1(i18next@25.1.1(typescript@5.8.3))(react-dom@19.1.0(react@19.1.0))(react@19.1.0)(typescript@5.8.3)
+ react-router:
+ specifier: ^6.26.0
+ version: 6.30.0(react@19.1.0)
react-router-dom:
specifier: ^6.26.0
version: 6.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0)
@@ -11377,7 +11380,7 @@ snapshots:
ts-interface-checker@0.1.13: {}
- ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(jest@29.7.0(@types/node@22.15.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3)))(typescript@5.8.3):
+ ts-jest@29.3.2(@babel/core@7.27.1)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.1))(esbuild@0.25.4)(jest@29.7.0(@types/node@22.15.12)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3)))(typescript@5.8.3):
dependencies:
bs-logger: 0.2.6
ejs: 3.1.10
@@ -11396,6 +11399,7 @@ snapshots:
'@jest/transform': 29.7.0
'@jest/types': 29.6.3
babel-jest: 29.7.0(@babel/core@7.27.1)
+ esbuild: 0.25.4
ts-node@10.9.2(@types/node@22.15.12)(typescript@5.8.3):
dependencies: