diff --git a/.vscode/launch.json b/.vscode/launch.json index ca8478f4..fde3489c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,12 +1,20 @@ { "version": "0.2.0", "configurations": [ + { + "name": "WEB: Run in Development Mode", + "type": "node", + "request": "launch", + "runtimeExecutable": "pnpm", + "runtimeArgs": ["run", "dev", "--filter", "web"], + "console": "integratedTerminal" + }, { "name": "SERVER: Run in Development Mode", "type": "node", "request": "launch", - "runtimeExecutable": "npm", - "runtimeArgs": ["run", "dev"], + "runtimeExecutable": "pnpm", + "runtimeArgs": ["run", "dev", "--filter", "server"], "console": "integratedTerminal" }, { diff --git a/apps/server/package.json b/apps/server/package.json index 7912c40d..1afb3c87 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -42,6 +42,7 @@ "dependencies": { "@erp/core": "workspace:*", "@erp/auth": "workspace:*", + "@erp/invoices": "workspace:*", "bcrypt": "^5.1.1", "cls-rtracer": "^2.6.3", "cors": "^2.8.5", diff --git a/apps/server/src/index.ts b/apps/server/src/index.ts index 65d5cc03..77071f86 100644 --- a/apps/server/src/index.ts +++ b/apps/server/src/index.ts @@ -5,9 +5,12 @@ import os from "node:os"; import { createApp } from "./app"; import { ENV } from "./config"; import { tryConnectToDatabase } from "./config/database"; +import { listRoutes } from "./lib"; import { initModules } from "./lib/modules"; import { registerModules } from "./register-modules"; +const API_BASE_PATH = "/api/v1"; + // Guardamos información del estado del servidor export const currentState = { launchedAt: DateTime.now(), @@ -129,7 +132,10 @@ process.on("uncaughtException", (error: Error) => { // initStructure(sequelizeConn.connection); // insertUsers(); - await initModules({ app, database, baseRoutePath: "/api/v1", logger }); + await initModules({ app, database, baseRoutePath: API_BASE_PATH, logger }); + + logger.info("holaaaaaaaaaaaaaaaaa"); + console.log(listRoutes(app._router, API_BASE_PATH)); server.listen(currentState.port, () => { server.emit("listening"); diff --git a/apps/server/src/lib/index.ts b/apps/server/src/lib/index.ts index 52f44797..ebd9f210 100644 --- a/apps/server/src/lib/index.ts +++ b/apps/server/src/lib/index.ts @@ -1,2 +1,3 @@ +export * from "./list-routes"; export * from "./logger"; export * from "./modules"; diff --git a/apps/server/src/lib/list-routes.ts b/apps/server/src/lib/list-routes.ts new file mode 100644 index 00000000..1d5e4622 --- /dev/null +++ b/apps/server/src/lib/list-routes.ts @@ -0,0 +1,30 @@ +// Función para listar rutas +export function listRoutes(appOrRouter, basePath = "") { + const routes = []; + + appOrRouter.stack.forEach((middleware) => { + if (middleware.route) { + // Es una ruta directa + const methods = Object.keys(middleware.route.methods).map((m) => m.toUpperCase()); + routes.push({ + path: basePath + middleware.route.path, + methods, + }); + } else if (middleware.name === "router" && middleware.handle.stack) { + // Es un router anidado + const newBasePath = + basePath + + (middleware.regexp?.source !== "^\\/?$" + ? middleware.regexp + ?.toString() + .replace(/^\/\^\\/, "") + .replace(/\\\/\?\(\?=\\\/\|\$\)\/i$/, "") + .replace(/\\\//g, "/") + : ""); + const childRoutes = listRoutes(middleware.handle, basePath + (middleware?.path || "")); + routes.push(...childRoutes); + } + }); + + return routes; +} diff --git a/apps/server/src/lib/modules/module-loader.ts b/apps/server/src/lib/modules/module-loader.ts index 3c6f64f7..7cf4c36a 100644 --- a/apps/server/src/lib/modules/module-loader.ts +++ b/apps/server/src/lib/modules/module-loader.ts @@ -7,10 +7,10 @@ const registeredModules: Map = new Map(); const initializedModules = new Set(); export function registerModule(pkg: IModuleServer) { - if (registeredModules.has(pkg.metadata.name)) { - throw new Error(`❌ Paquete "${pkg.metadata.name}" ya registrado.`); + if (registeredModules.has(pkg.name)) { + throw new Error(`❌ Paquete "${pkg.name}" ya registrado.`); } - registeredModules.set(pkg.metadata.name, pkg); + registeredModules.set(pkg.name, pkg); } export async function initModules(params: ModuleParams) { @@ -27,7 +27,7 @@ const loadModule = (name: string, params: ModuleParams) => { if (!pkg) throw new Error(`❌ Paquete "${name}" no encontrado.`); // Resolver dependencias primero - const deps = pkg.metadata.dependencies || []; + const deps = pkg.dependencies || []; deps.forEach((dep) => loadModule(dep, params)); // Inicializar el module @@ -44,7 +44,7 @@ const loadModule = (name: string, params: ModuleParams) => { if (pkgApi?.services) { const services = pkgApi.services; if (services && typeof services === "object") { - registerService(pkg.metadata.name, services); + registerService(pkg.name, services); } } diff --git a/apps/server/src/register-modules.ts b/apps/server/src/register-modules.ts index 0a46169a..3ab62493 100644 --- a/apps/server/src/register-modules.ts +++ b/apps/server/src/register-modules.ts @@ -1,8 +1,8 @@ import { authAPIModule } from "@erp/auth/api"; +import { invoicesAPIModule } from "@erp/invoices/api"; import { registerModule } from "./lib"; -//import { invoicesAPIModule } from "@erp/invoices/api"; export const registerModules = () => { registerModule(authAPIModule); - //registerModule(invoicesAPIModule); + registerModule(invoicesAPIModule); }; diff --git a/apps/web/src/register-modules.tsx b/apps/web/src/register-modules.tsx index 6391d8b5..1db77faf 100644 --- a/apps/web/src/register-modules.tsx +++ b/apps/web/src/register-modules.tsx @@ -1,5 +1,5 @@ import { AuthModuleManifiest } from "@erp/auth/client"; import { IModuleClient } from "@erp/core/client"; -//import InvoicesModule from "@erp/invoices/client"; +import { InvoicesModuleManifiest } from "@erp/invoices/client"; -export const modules: IModuleClient[] = [AuthModuleManifiest]; +export const modules: IModuleClient[] = [AuthModuleManifiest, InvoicesModuleManifiest]; diff --git a/apps/web/src/routes/app-routes.tsx b/apps/web/src/routes/app-routes.tsx index 3b76918d..a43700b1 100644 --- a/apps/web/src/routes/app-routes.tsx +++ b/apps/web/src/routes/app-routes.tsx @@ -32,6 +32,8 @@ export const AppRoutes = (): JSX.Element => { const grouped = groupModulesByLayout(modules); + console.log(grouped); + return ( diff --git a/modules/auth/src/api/index.ts b/modules/auth/src/api/index.ts index f54b5a86..ccae0889 100644 --- a/modules/auth/src/api/index.ts +++ b/modules/auth/src/api/index.ts @@ -1,11 +1,9 @@ -import { IModuleServer, ModuleParams } from "@erp/core"; +import { IModuleServer, ModuleParams } from "@erp/core/api"; export const authAPIModule: IModuleServer = { - metadata: { - name: "auth", - version: "1.0.0", - dependencies: [], - }, + name: "auth", + version: "1.0.0", + dependencies: [], init(params: ModuleParams) { // const contacts = getService("contacts"); const { logger } = params; diff --git a/modules/auth/src/web/context/auth-context.tsx b/modules/auth/src/web/context/auth-context.tsx index ba5c606f..7d6884e0 100644 --- a/modules/auth/src/web/context/auth-context.tsx +++ b/modules/auth/src/web/context/auth-context.tsx @@ -1,12 +1,12 @@ import { PropsWithChildren, createContext, useEffect, useState } from "react"; import { IAuthService } from "../services"; -export interface AuthContextType { +export type AuthContextType = { token: string | null; isAuthenticated: boolean; login: (email: string, password: string) => Promise; logout: () => void; -} +}; export interface AuthContextParams { authService: IAuthService; @@ -20,7 +20,10 @@ export const AuthContext = createContext(undefined) /** * Proveedor de autenticación para toda la app. */ -export const AuthProvider = ({ params, children }: PropsWithChildren<{ params: any }>) => { +export const AuthProvider = ({ + params, + children, +}: PropsWithChildren<{ params: AuthContextParams }>) => { const { getAccessToken, setAccessToken, clearAccessToken, authService } = params; const [token, setToken] = useState(getAccessToken()); @@ -30,9 +33,9 @@ export const AuthProvider = ({ params, children }: PropsWithChildren<{ params: a }, []); const login = async (email: string, password: string) => { - const { access_token } = await authService.login({ email, password }); - setAccessToken(access_token); - setToken(access_token); + const { token } = await authService.login({ email, password }); + setAccessToken(token); + setToken(token); }; const logout = () => { diff --git a/modules/auth/src/web/hooks/use-auth.ts b/modules/auth/src/web/hooks/use-auth.ts index d0363e84..a497658f 100644 --- a/modules/auth/src/web/hooks/use-auth.ts +++ b/modules/auth/src/web/hooks/use-auth.ts @@ -7,7 +7,7 @@ import { AuthContext, AuthContextType } from "../context"; export const useAuth = (): AuthContextType => { const context = useContext(AuthContext); if (!context) { - throw new Error("useAuth debe usarse dentro de "); + throw new Error("useAuth must be used within a AuthProvider"); } return context; }; diff --git a/modules/invoices/src/api/application/list-invoices.use-case.ts b/modules/invoices/src/api/application/list-invoices.use-case.ts index 906ff0ca..657b8de5 100644 --- a/modules/invoices/src/api/application/list-invoices.use-case.ts +++ b/modules/invoices/src/api/application/list-invoices.use-case.ts @@ -1,4 +1,4 @@ -import { ITransactionManager } from "@erp/core"; +import { ITransactionManager } from "@erp/core/api"; import { Criteria } from "@repo/rdx-criteria/server"; import { Collection, Result } from "@repo/rdx-utils"; import { Transaction } from "sequelize"; diff --git a/modules/invoices/src/api/index.ts b/modules/invoices/src/api/index.ts index e937883a..45a34445 100644 --- a/modules/invoices/src/api/index.ts +++ b/modules/invoices/src/api/index.ts @@ -1,12 +1,11 @@ -import { IModuleServer, ModuleParams } from "@erp/core"; +import { IModuleServer, ModuleParams } from "@erp/core/api"; import { invoicesRouter, models } from "./infrastructure"; export const invoicesAPIModule: IModuleServer = { - metadata: { - name: "invoices", - version: "1.0.0", - dependencies: [], - }, + name: "invoices", + version: "1.0.0", + dependencies: [], + init(params: ModuleParams) { // const contacts = getService("contacts"); const { logger } = params; diff --git a/modules/invoices/src/api/infrastructure/express/invoices.routes.ts b/modules/invoices/src/api/infrastructure/express/invoices.routes.ts index 2bb20fff..a54eaf62 100644 --- a/modules/invoices/src/api/infrastructure/express/invoices.routes.ts +++ b/modules/invoices/src/api/infrastructure/express/invoices.routes.ts @@ -1,4 +1,4 @@ -import { ModuleParams } from "@erp/core"; +import { ModuleParams } from "@erp/core/api"; import { Application, NextFunction, Request, Response, Router } from "express"; import { Sequelize } from "sequelize"; import { buildListInvoicesController } from "../../presentation"; @@ -21,6 +21,8 @@ export const invoicesRouter = (params: ModuleParams) => { } ); + app.use(`${baseRoutePath}/invoices`, routes); + /*routes.get( "/:invoiceId", //checkTabContext, @@ -59,6 +61,4 @@ export const invoicesRouter = (params: ModuleParams) => { buildDeleteInvoiceController().execute(req, res, next); } );*/ - - app.use(`${baseRoutePath}/invoices`, routes); }; diff --git a/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts b/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts index 3fd27489..313510ac 100644 --- a/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts +++ b/modules/invoices/src/api/infrastructure/mappers/invoice-item.mapper.ts @@ -1,4 +1,4 @@ -import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core"; +import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core/api"; import { UniqueID } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { InferCreationAttributes } from "sequelize"; diff --git a/modules/invoices/src/api/infrastructure/mappers/invoice.mapper.ts b/modules/invoices/src/api/infrastructure/mappers/invoice.mapper.ts index a36d55e3..5583a678 100644 --- a/modules/invoices/src/api/infrastructure/mappers/invoice.mapper.ts +++ b/modules/invoices/src/api/infrastructure/mappers/invoice.mapper.ts @@ -1,4 +1,4 @@ -import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core"; +import { ISequelizeMapper, MapperParamsType, SequelizeMapper } from "@erp/core/api"; import { UniqueID, UtcDate } from "@repo/rdx-ddd"; import { Result } from "@repo/rdx-utils"; import { Invoice, InvoiceNumber, InvoiceSerie, InvoiceStatus } from "../../domain"; diff --git a/modules/invoices/src/api/infrastructure/sequelize/invoice.repository.ts b/modules/invoices/src/api/infrastructure/sequelize/invoice.repository.ts index d17b3e6c..96abf191 100644 --- a/modules/invoices/src/api/infrastructure/sequelize/invoice.repository.ts +++ b/modules/invoices/src/api/infrastructure/sequelize/invoice.repository.ts @@ -1,4 +1,4 @@ -import { SequelizeRepository } from "@erp/core"; +import { SequelizeRepository } from "@erp/core/api"; import { Criteria } from "@repo/rdx-criteria/server"; import { UniqueID } from "@repo/rdx-ddd"; import { Collection, Result } from "@repo/rdx-utils"; diff --git a/modules/invoices/src/api/presentation/get-invoice/get-invoice.controller.ts b/modules/invoices/src/api/presentation/get-invoice/get-invoice.controller.ts index ea556968..bd207f2f 100644 --- a/modules/invoices/src/api/presentation/get-invoice/get-invoice.controller.ts +++ b/modules/invoices/src/api/presentation/get-invoice/get-invoice.controller.ts @@ -1,4 +1,4 @@ -import { ExpressController } from "@erp/core"; +import { ExpressController } from "@erp/core/api"; import { UniqueID } from "@repo/rdx-ddd"; import { GetInvoiceUseCase } from "../../application"; import { IGetInvoicePresenter } from "./presenter"; diff --git a/modules/invoices/src/api/presentation/get-invoice/index.ts b/modules/invoices/src/api/presentation/get-invoice/index.ts index c2f030da..a93d19e5 100644 --- a/modules/invoices/src/api/presentation/get-invoice/index.ts +++ b/modules/invoices/src/api/presentation/get-invoice/index.ts @@ -1,4 +1,4 @@ -import { SequelizeTransactionManager } from "@erp/core"; +import { SequelizeTransactionManager } from "@erp/core/api"; import { Sequelize } from "sequelize"; import { InvoiceService } from "../../domain"; import { InvoiceRepository, invoiceMapper } from "../../infrastructure"; diff --git a/modules/invoices/src/api/presentation/list-invoices/index.ts b/modules/invoices/src/api/presentation/list-invoices/index.ts index 9d33eef3..9ba5660f 100644 --- a/modules/invoices/src/api/presentation/list-invoices/index.ts +++ b/modules/invoices/src/api/presentation/list-invoices/index.ts @@ -1,4 +1,4 @@ -import { SequelizeTransactionManager } from "@erp/core"; +import { SequelizeTransactionManager } from "@erp/core/api"; import { Sequelize } from "sequelize"; import { ListInvoicesUseCase } from "../../application"; import { InvoiceService } from "../../domain"; diff --git a/modules/invoices/src/api/presentation/list-invoices/list-invoices.controller.ts b/modules/invoices/src/api/presentation/list-invoices/list-invoices.controller.ts index dd9d7d9d..46f5e4ad 100644 --- a/modules/invoices/src/api/presentation/list-invoices/list-invoices.controller.ts +++ b/modules/invoices/src/api/presentation/list-invoices/list-invoices.controller.ts @@ -1,4 +1,4 @@ -import { ExpressController } from "@erp/core"; +import { ExpressController } from "@erp/core/api"; import { ListInvoicesUseCase } from "../../application"; import { IListInvoicesPresenter } from "./presenter"; diff --git a/modules/invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts b/modules/invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts index f4c795a3..88366aa1 100644 --- a/modules/invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts +++ b/modules/invoices/src/api/presentation/list-invoices/presenter/list-invoices.presenter.ts @@ -1,4 +1,4 @@ -import { IListResponseDTO } from "@erp/core"; +import { IListResponseDTO } from "@erp/core/api"; import { Criteria } from "@repo/rdx-criteria/server"; import { Collection } from "@repo/rdx-utils"; import { IListInvoicesResponseDTO } from "../../../../common/dto"; diff --git a/modules/invoices/src/web/components/invoices-layout.tsx b/modules/invoices/src/web/components/invoices-layout.tsx index 9e6e1a96..20c4d529 100644 --- a/modules/invoices/src/web/components/invoices-layout.tsx +++ b/modules/invoices/src/web/components/invoices-layout.tsx @@ -1,10 +1,10 @@ -import { Outlet } from "react-router-dom"; -import { InvoicesProvider } from "../hooks"; +import { PropsWithChildren } from "react"; -export const InvoicesLayout = () => { +export const InvoicesLayout = ({ children }: PropsWithChildren) => { return ( - - - + <> +

hola

+ {children} + ); }; diff --git a/modules/invoices/src/web/context/index.ts b/modules/invoices/src/web/context/index.ts new file mode 100644 index 00000000..b7449222 --- /dev/null +++ b/modules/invoices/src/web/context/index.ts @@ -0,0 +1 @@ +export * from "./invoices-context"; diff --git a/modules/invoices/src/web/context/invoices-context.tsx b/modules/invoices/src/web/context/invoices-context.tsx new file mode 100644 index 00000000..7542591b --- /dev/null +++ b/modules/invoices/src/web/context/invoices-context.tsx @@ -0,0 +1,21 @@ +import { usePagination } from "@erp/core/client"; +import { PropsWithChildren, createContext } from "react"; + +export type InvoicesContextType = {}; + +export const InvoicesContext = createContext(null); + +export const InvoicesProvider = ({ children }: PropsWithChildren) => { + const [pagination, setPagination] = usePagination(); + + return ( + + {children} + + ); +}; diff --git a/modules/invoices/src/web/hooks/invoices-context.tsx b/modules/invoices/src/web/hooks/invoices-context.tsx index 92e62659..34cde6a5 100644 --- a/modules/invoices/src/web/hooks/invoices-context.tsx +++ b/modules/invoices/src/web/hooks/invoices-context.tsx @@ -1,27 +1,11 @@ -import { usePagination } from "@erp/core/hooks"; -import { PropsWithChildren, createContext, useContext } from "react"; +import { useContext } from "react"; +import { InvoicesContext, InvoicesContextType } from "../context"; -export type IInvoicesContextState = {}; - -export const InvoicesContext = createContext(null); - -export const InvoicesProvider = ({ children }: PropsWithChildren) => { - const [pagination, setPagination] = usePagination(); - - return ( - - {children} - - ); -}; - -export const useInvoicesContext = () => { +export const useInvoices = (): InvoicesContextType => { const context = useContext(InvoicesContext); - if (context === null) throw new Error("useInvoices must be used within a InvoicesProvider"); + if (!context) { + throw new Error("useInvoices must be used within a InvoicesProvider"); + } + return context; }; diff --git a/modules/invoices/src/web/hooks/use-invoices.tsx b/modules/invoices/src/web/hooks/use-invoices.tsx index 25a7d795..626a41f8 100644 --- a/modules/invoices/src/web/hooks/use-invoices.tsx +++ b/modules/invoices/src/web/hooks/use-invoices.tsx @@ -1,11 +1,4 @@ -import { IListResponseDTO } from "@erp/core"; -import { - IGetListDataProviderParams, - UseListQueryResult, - useDataSource, - useList, - useQueryKey, -} from "@erp/core/client"; +import { useDataSource, useQueryKey } from "@erp/core/client"; import { IListInvoicesResponseDTO } from "@erp/invoices/common/dto"; export type UseInvoicesListParams = Omit & { diff --git a/modules/invoices/src/web/invoice-routes.tsx b/modules/invoices/src/web/invoice-routes.tsx index f0ad627b..b26371a7 100644 --- a/modules/invoices/src/web/invoice-routes.tsx +++ b/modules/invoices/src/web/invoice-routes.tsx @@ -1,6 +1,6 @@ -//import { ProtectedRoute } from "@erp/auth/components"; -import { JSX, lazy } from "react"; -import { Route } from "react-router-dom"; +import { ModuleClientParams } from "@erp/core/client"; +import { lazy } from "react"; +import { Outlet, RouteObject } from "react-router-dom"; // Lazy load components const InvoicesLayout = lazy(() => @@ -27,24 +27,32 @@ 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 = (): JSX.Element => { - return ( - }> - } /> - } /> +export const InvoiceRoutes = (params: ModuleClientParams): RouteObject[] => { + return [ + { + path: "*", + element: ( + + + + ), + children: [ + { path: "", element: }, // index + { path: "list", element: }, + { path: "*", element: }, - {/*} /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } />*/} - - } /> - - ); + // + /*{ path: "create", element: }, + { path: ":id", element: }, + { path: ":id/edit", element: }, + { path: ":id/delete", element: }, + { path: ":id/view", element: }, + { path: ":id/print", element: }, + { path: ":id/email", element: }, + { path: ":id/download", element: }, + { path: ":id/duplicate", element: }, + { path: ":id/preview", element: },*/ + ], + }, + ]; }; diff --git a/modules/invoices/src/web/manifest.ts b/modules/invoices/src/web/manifest.ts index 4a98d5e0..e4184396 100644 --- a/modules/invoices/src/web/manifest.ts +++ b/modules/invoices/src/web/manifest.ts @@ -1,4 +1,4 @@ -import { IModuleClient } from "@erp/core/client"; +import { IModuleClient, ModuleClientParams } from "@erp/core/client"; import i18next from "i18next"; import enResources from "../common/locales/en.json"; import esResources from "../common/locales/es.json"; @@ -7,18 +7,18 @@ import { InvoiceRoutes } from "./invoice-routes"; const MODULE_NAME = "invoices"; const MODULE_VERSION = "1.0.0"; -export const InvoicesModuleManifest: IModuleClient = { +export const InvoicesModuleManifiest: IModuleClient = { name: MODULE_NAME, version: MODULE_VERSION, dependencies: ["auth"], protected: true, layout: "app", - routes: () => { + routes: (params: ModuleClientParams) => { i18next.addResourceBundle("en", MODULE_NAME, enResources, true, true); i18next.addResourceBundle("es", MODULE_NAME, esResources, true, true); - return InvoiceRoutes(); + return InvoiceRoutes(params); }, }; -export default InvoicesModuleManifest; +export default InvoicesModuleManifiest; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1d72a80b..0939efbc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -41,6 +41,9 @@ importers: '@erp/core': specifier: workspace:* version: link:../../modules/core + '@erp/invoices': + specifier: workspace:* + version: link:../../modules/invoices bcrypt: specifier: ^5.1.1 version: 5.1.1