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} -
-
-
-
-
+ <> + + {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: