From bead394ebd07d178ce4c12f6593f39d3a1a329df Mon Sep 17 00:00:00 2001 From: david Date: Mon, 19 May 2025 13:59:13 +0200 Subject: [PATCH] . --- apps/web/src/app.tsx | 3 +- .../lib/axios/create-axios-data-provider.ts | 8 +- apps/web/src/lib/hooks/index.ts | 1 - .../use-datasource/datasource-context.tsx | 11 -- .../web/src/lib/hooks/use-datasource/index.ts | 2 - apps/web/tsconfig.app.json | 6 +- modules/core/package.json | 7 + modules/core/src/dto/list.dto.ts | 18 +- modules/core/src/dto/money.dto.ts | 2 +- modules/core/src/dto/quantity.dto.ts | 2 +- modules/core/src/web/hooks/index.ts | 2 + .../use-datasource/datasource.interface.ts | 4 +- .../src/web/hooks/use-datasource/index.ts | 3 + .../hooks/use-datasource/use-datasource.tsx | 19 ++ .../src/web/hooks/use-datasource/use-list.ts | 87 +++++++++ .../use-datasource/use-loading-overtime.ts | 101 ++++++++++ .../core/src/web/hooks/use-query-key/index.ts | 5 + .../web/hooks/use-query-key/key-builder.ts | 181 ++++++++++++++++++ modules/invoices/package.json | 11 +- .../application/create-invoice.use-case.ts | 2 +- .../application/update-invoice.use-case.ts | 2 +- .../create-invoice.controller.ts | 2 +- .../presenter/create-invoice.presenter.ts | 2 +- .../presenter/get-invoice.presenter.ts | 2 +- .../presenter/list-invoices.presenter.ts | 2 +- .../invoices/src/api/presentation/index.ts | 1 - .../{api/presentation => common}/dto/index.ts | 0 .../dto/invoices.request.dto.ts | 0 .../dto/invoices.response.dto.ts | 2 +- .../dto/invoices.schemas.ts | 0 .../src/web/components/invoices-layout.tsx | 9 +- .../src/web/hooks/invoices-context.tsx | 2 +- .../invoices/src/web/hooks/useInvoices.tsx | 82 ++++++++ modules/invoices/src/web/pages/index.tsx | 2 +- .../web/pages/{invoices-list.tsx => list.tsx} | 0 .../src/Filters/FilterCriteria.ts | 4 +- packages/rdx-criteria/src/Order/Order.ts | 3 +- .../rdx-criteria/src/Order/OrderCriteria.ts | 4 +- packages/rdx-criteria/src/Order/OrderRoot.ts | 22 +-- .../src/Pagination/OffsetPaging.ts | 3 +- .../src/QuickSearch/QuickSearchCriteria.ts | 3 +- packages/rdx-criteria/src/helpers/index.ts | 2 - packages/rdx-utils/package.json | 6 + packages/rdx-utils/src/helpers/index.ts | 2 + .../src/helpers/result-collection.ts} | 2 +- .../src/helpers/rule-validator.ts} | 2 +- packages/shadcn-ui/src/components/sidebar.tsx | 1 + pnpm-lock.yaml | 41 ++++ 48 files changed, 598 insertions(+), 80 deletions(-) delete mode 100644 apps/web/src/lib/hooks/use-datasource/datasource-context.tsx delete mode 100644 apps/web/src/lib/hooks/use-datasource/index.ts rename apps/web/src/lib/hooks/use-datasource/datasource.ts => modules/core/src/web/hooks/use-datasource/datasource.interface.ts (95%) create mode 100644 modules/core/src/web/hooks/use-datasource/index.ts create mode 100644 modules/core/src/web/hooks/use-datasource/use-datasource.tsx create mode 100644 modules/core/src/web/hooks/use-datasource/use-list.ts create mode 100644 modules/core/src/web/hooks/use-datasource/use-loading-overtime.ts create mode 100644 modules/core/src/web/hooks/use-query-key/index.ts create mode 100644 modules/core/src/web/hooks/use-query-key/key-builder.ts rename modules/invoices/src/{api/presentation => common}/dto/index.ts (100%) rename modules/invoices/src/{api/presentation => common}/dto/invoices.request.dto.ts (100%) rename modules/invoices/src/{api/presentation => common}/dto/invoices.response.dto.ts (95%) rename modules/invoices/src/{api/presentation => common}/dto/invoices.schemas.ts (100%) create mode 100644 modules/invoices/src/web/hooks/useInvoices.tsx rename modules/invoices/src/web/pages/{invoices-list.tsx => list.tsx} (100%) rename packages/{rdx-criteria/src/helpers/ResultCollection.ts => rdx-utils/src/helpers/result-collection.ts} (96%) rename packages/{rdx-criteria/src/helpers/RuleValidator.ts => rdx-utils/src/helpers/rule-validator.ts} (97%) diff --git a/apps/web/src/app.tsx b/apps/web/src/app.tsx index b2d62ffa..08f19afa 100644 --- a/apps/web/src/app.tsx +++ b/apps/web/src/app.tsx @@ -4,9 +4,10 @@ import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; import { I18nextProvider } from "react-i18next"; import { createAxiosDataProvider } from "@/lib/axios/create-axios-data-provider"; -import { DataSourceProvider, UnsavedWarnProvider } from "@/lib/hooks"; +import { UnsavedWarnProvider } from "@/lib/hooks"; import { i18n } from "@/locales"; +import { DataSourceProvider } from "@erp/core/hooks"; import { AppRoutes } from "./app-routes"; import "./app.css"; diff --git a/apps/web/src/lib/axios/create-axios-data-provider.ts b/apps/web/src/lib/axios/create-axios-data-provider.ts index c23c760a..a96a1437 100644 --- a/apps/web/src/lib/axios/create-axios-data-provider.ts +++ b/apps/web/src/lib/axios/create-axios-data-provider.ts @@ -1,5 +1,6 @@ -import type { ListResponseDTO } from "@erp/core"; +import type { IListResponseDTO } from "@erp/core"; import { INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE } from "@repo/rdx-criteria"; +import type { IDataSource } from "../../../../../modules/core/src/web/hooks/use-datasource/datasource.interface"; import { getApiAuthorization as getApiAuthLib } from "../api"; import type { ICreateOneDataProviderParams, @@ -15,7 +16,6 @@ import type { IUpdateOneDataProviderParams, IUploadFileDataProviderParam, } from "../hooks/use-datasource"; -import type { IDataSource } from "../hooks/use-datasource/datasource"; import { createAxiosInstance, defaultAxiosRequestConfig } from "./axios-instance"; export const createAxiosDataProvider = ( @@ -28,7 +28,7 @@ export const createAxiosDataProvider = ( getApiAuthorization: getApiAuthLib, - getList: async (params: IGetListDataProviderParams): Promise> => { + getList: async (params: IGetListDataProviderParams): Promise> => { const { resource, quickSearchTerm, pagination, filters = [], sort = [] } = params; const url = `${apiUrl}/${resource}`; @@ -53,7 +53,7 @@ export const createAxiosDataProvider = ( urlParams.append("$filters", queryFilters.join(",")); } - const response = await httpClient.request>({ + const response = await httpClient.request>({ url: `${url}?${urlParams.toString()}`, method: "GET", }); diff --git a/apps/web/src/lib/hooks/index.ts b/apps/web/src/lib/hooks/index.ts index b1a92548..775fb608 100644 --- a/apps/web/src/lib/hooks/index.ts +++ b/apps/web/src/lib/hooks/index.ts @@ -1,3 +1,2 @@ -export * from "./use-datasource"; export * from "./use-theme"; export * from "./use-unsaved-changes-notifier"; diff --git a/apps/web/src/lib/hooks/use-datasource/datasource-context.tsx b/apps/web/src/lib/hooks/use-datasource/datasource-context.tsx deleted file mode 100644 index 60d099de..00000000 --- a/apps/web/src/lib/hooks/use-datasource/datasource-context.tsx +++ /dev/null @@ -1,11 +0,0 @@ -import { type PropsWithChildren, createContext } from "react"; -import { type IDataSource } from "./datasource"; - -export const DataSourceContext = createContext(undefined); - -export const DataSourceProvider = ({ - dataSource, - children, -}: PropsWithChildren<{ - dataSource: IDataSource; -}>) => {children}; diff --git a/apps/web/src/lib/hooks/use-datasource/index.ts b/apps/web/src/lib/hooks/use-datasource/index.ts deleted file mode 100644 index 9499cefa..00000000 --- a/apps/web/src/lib/hooks/use-datasource/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./datasource-context"; -export * from "./datasource"; diff --git a/apps/web/tsconfig.app.json b/apps/web/tsconfig.app.json index 9eb96c89..e301ec5d 100644 --- a/apps/web/tsconfig.app.json +++ b/apps/web/tsconfig.app.json @@ -27,6 +27,10 @@ "noUncheckedSideEffectImports": true, "allowUnreachableCode": true }, - "include": ["src"], + "include": [ + "src", + "../../modules/core/src/web/hooks/use-datasource/use-datasource.tsx", + "../../modules/core/src/web/hooks/use-datasource/datasource.interface.ts" + ], "exclude": ["node_modules"] } diff --git a/modules/core/package.json b/modules/core/package.json index eba7c5d7..ddb434d4 100644 --- a/modules/core/package.json +++ b/modules/core/package.json @@ -5,11 +5,13 @@ "types": "src/index.ts", "exports": { ".": "./src/index.ts", + "./dto": "./src/dto/index.ts", "./hooks": "./src/web/hooks/index.ts", "./components": "./src/web/components/index.tsx", "./components/*": "./src/web/components/*.tsx" }, "peerDependencies": { + "joi": "^17.13.3", "react": "^18 || ^19", "react-dom": "^18 || ^19", "sequelize": "^6.37.5" @@ -17,13 +19,18 @@ "devDependencies": { "@biomejs/biome": "1.9.4", "@testing-library/react-hooks": "^8.0.1", + "@types/axios": "^0.14.4", "@types/jest": "29.5.14", "@types/react": "^19.1.2", "@types/react-dom": "^19.1.3", "typescript": "^5.8.3" }, "dependencies": { + "@repo/rdx-utils": "workspace:*", "@repo/rdx-criteria": "workspace:*", + "@tanstack/react-query": "^5.75.4", + "axios": "^1.9.0", + "joi": "^17.13.3", "react": "^19.1.0", "react-dom": "^19.1.0", "react-router-dom": "^6.26.0", diff --git a/modules/core/src/dto/list.dto.ts b/modules/core/src/dto/list.dto.ts index 19cd9f6a..4642eaf9 100644 --- a/modules/core/src/dto/list.dto.ts +++ b/modules/core/src/dto/list.dto.ts @@ -1,19 +1,15 @@ -export interface ListResponseDTO { +export interface IListResponseDTO { page: number; perpage: number; - totalpages: number; - totalitems: number; + total_pages: number; + total_items: number; items: T[]; } -export const IsResponseAListDTO = (response: any): response is ListResponseDTO => { - return ( - typeof response === "object" && - response !== null && - Object.prototype.hasOwnProperty.call(response, "totalitems") - ); +export const isResponseAListDTO = (data: any): data is IListResponseDTO => { + return data && typeof data.total_items === "number"; }; -export const existsMoreReponsePages = (response: any): response is ListResponseDTO => { - return IsResponseAListDTO(response) && response.page + 1 < response.totalpages; +export const existsMoreReponsePages = (response: any): response is IListResponseDTO => { + return isResponseAListDTO(response) && response.page + 1 < response.total_pages; }; diff --git a/modules/core/src/dto/money.dto.ts b/modules/core/src/dto/money.dto.ts index 784de5e0..45b52d80 100644 --- a/modules/core/src/dto/money.dto.ts +++ b/modules/core/src/dto/money.dto.ts @@ -1,5 +1,5 @@ +import { Result, RuleValidator } from "@repo/rdx-utils"; import Joi from "joi"; -import { Result, RuleValidator } from "../../domain"; export interface IMoneyDTO { amount: number | null; diff --git a/modules/core/src/dto/quantity.dto.ts b/modules/core/src/dto/quantity.dto.ts index 6cfa0266..eda16b07 100644 --- a/modules/core/src/dto/quantity.dto.ts +++ b/modules/core/src/dto/quantity.dto.ts @@ -1,5 +1,5 @@ +import { Result, RuleValidator } from "@repo/rdx-utils"; import Joi from "joi"; -import { Result, RuleValidator } from "../../domain"; export interface IQuantityDTO { amount: number | null; diff --git a/modules/core/src/web/hooks/index.ts b/modules/core/src/web/hooks/index.ts index 77665106..42765c58 100644 --- a/modules/core/src/web/hooks/index.ts +++ b/modules/core/src/web/hooks/index.ts @@ -1,2 +1,4 @@ +export * from "./use-datasource"; export * from "./use-pagination"; +export * from "./use-query-key"; export * from "./use-toggle"; diff --git a/apps/web/src/lib/hooks/use-datasource/datasource.ts b/modules/core/src/web/hooks/use-datasource/datasource.interface.ts similarity index 95% rename from apps/web/src/lib/hooks/use-datasource/datasource.ts rename to modules/core/src/web/hooks/use-datasource/datasource.interface.ts index 8a60f50a..d009fdfa 100644 --- a/apps/web/src/lib/hooks/use-datasource/datasource.ts +++ b/modules/core/src/web/hooks/use-datasource/datasource.interface.ts @@ -1,4 +1,4 @@ -import type { ListResponseDTO } from "@erp/core"; +import type { IListResponseDTO } from "@erp/core"; import { type AxiosHeaderValue, type ResponseType } from "axios"; export interface IPaginationDataProviderParam { @@ -87,7 +87,7 @@ export interface ICustomDataProviderParam { export interface IDataSource { name: () => string; - getList: (params: IGetListDataProviderParams) => Promise>; + getList: (params: IGetListDataProviderParams) => Promise>; getOne: (params: IGetOneDataProviderParams) => Promise; //saveOne: (params: ISaveOneDataProviderParams

) => Promise; createOne: (params: ICreateOneDataProviderParams

) => Promise; diff --git a/modules/core/src/web/hooks/use-datasource/index.ts b/modules/core/src/web/hooks/use-datasource/index.ts new file mode 100644 index 00000000..3076a7ab --- /dev/null +++ b/modules/core/src/web/hooks/use-datasource/index.ts @@ -0,0 +1,3 @@ +export * from "./datasource.interface"; +export * from "./use-datasource"; +export * from "./use-list"; diff --git a/modules/core/src/web/hooks/use-datasource/use-datasource.tsx b/modules/core/src/web/hooks/use-datasource/use-datasource.tsx new file mode 100644 index 00000000..fa424eef --- /dev/null +++ b/modules/core/src/web/hooks/use-datasource/use-datasource.tsx @@ -0,0 +1,19 @@ +import { type PropsWithChildren, createContext, useContext } from "react"; +import { IDataSource } from "./datasource.interface"; + +export const DataSourceContext = createContext(undefined); + +export const DataSourceProvider = ({ + dataSource, + children, +}: PropsWithChildren<{ + dataSource: IDataSource; +}>) => {children}; + +export const useDataSource = () => { + const context = useContext(DataSourceContext); + if (context === undefined) + throw new Error("useDataSource must be used within a DataSourceProvider"); + + return context; +}; diff --git a/modules/core/src/web/hooks/use-datasource/use-list.ts b/modules/core/src/web/hooks/use-datasource/use-list.ts new file mode 100644 index 00000000..3f48a697 --- /dev/null +++ b/modules/core/src/web/hooks/use-datasource/use-list.ts @@ -0,0 +1,87 @@ +import { + QueryFunctionContext, + QueryKey, + UseQueryOptions, + UseQueryResult, + keepPreviousData, + useQuery, +} from "@tanstack/react-query"; + +import { isResponseAListDTO } from "@erp/core/dto"; +import { + UseLoadingOvertimeOptionsProps, + UseLoadingOvertimeReturnType, + useLoadingOvertime, +} from "./use-loading-overtime"; + +const DEFAULT_REFETCH_INTERVAL = 2 * 60 * 1000; // 2 minutes +const DEFAULT_STALE_TIME = 60 * 1000; // 1 minute + +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export type UseListQueryOptions = { + queryKey: QueryKey; + queryFn: (context: QueryFunctionContext) => Promise; + enabled?: boolean; + refetchInterval?: number | false; + select?: (data: TUseListQueryData) => TUseListQueryData; + queryOptions?: Partial>; +} & UseLoadingOvertimeOptionsProps; + +export type UseListQueryResult = UseQueryResult< + TUseListQueryData, + TUseListQueryError +> & { + isEmpty: boolean; +} & UseLoadingOvertimeReturnType; + +/** + * Hook para manejar consultas de listas con React Query, + * incluye detección de listas vacías y control de sobretiempo de carga. + */ +export const useList = ({ + queryKey, + queryFn, + enabled, + refetchInterval, + select, + queryOptions = {}, + overtimeOptions, +}: UseListQueryOptions): UseListQueryResult< + TUseListQueryData, + TUseListQueryError +> => { + if (!queryFn) { + console.error("queryFn es requerido en useList"); + throw new Error("queryFn es requerido en useList"); + } + + const queryResponse = useQuery({ + queryKey, + queryFn, + placeholderData: keepPreviousData, + staleTime: DEFAULT_STALE_TIME, + refetchInterval: refetchInterval ?? DEFAULT_REFETCH_INTERVAL, + refetchOnWindowFocus: true, + enabled: enabled && !!queryFn, + select, + ...queryOptions, + }); + + const { elapsedTime } = useLoadingOvertime({ + isPending: queryResponse.isFetching, + interval: overtimeOptions?.interval, + onInterval: overtimeOptions?.onInterval, + }); + + const isEmpty = + queryResponse.isSuccess && + isResponseAListDTO(queryResponse.data) && + queryResponse.data.total_items === 0; + + const result = { + ...queryResponse, + overtime: { elapsedTime }, + isEmpty, + }; + return result; +}; diff --git a/modules/core/src/web/hooks/use-datasource/use-loading-overtime.ts b/modules/core/src/web/hooks/use-datasource/use-loading-overtime.ts new file mode 100644 index 00000000..b23487cb --- /dev/null +++ b/modules/core/src/web/hooks/use-datasource/use-loading-overtime.ts @@ -0,0 +1,101 @@ +import { useEffect, useState } from "react"; + +export type UseLoadingOvertimeRefineContext = Omit< + UseLoadingOvertimeCoreProps, + "isPending" | "interval" +> & + Required>; + +export type UseLoadingOvertimeOptionsProps = { + overtimeOptions?: UseLoadingOvertimeCoreOptions; +}; + +export type UseLoadingOvertimeReturnType = { + overtime: { + elapsedTime?: number; + }; +}; + +type UseLoadingOvertimeCoreOptions = Omit; + +type UseLoadingOvertimeCoreReturnType = { + elapsedTime?: number; +}; + +export type UseLoadingOvertimeCoreProps = { + /** + * The pengind state. If true, the elapsed time will be calculated. + */ + isPending: boolean; + + /** + * The interval in milliseconds. If the pending time exceeds this time, the `onInterval` callback will be called. + * If not specified, the `interval` value from the `overtime` option of the `RefineProvider` will be used. + * + * @default: 1000 (1 second) + */ + interval?: number; + + /** + * The callback function that will be called when the pending time exceeds the specified time. + * If not specified, the `onInterval` value from the `overtime` option of the `RefineProvider` will be used. + * + * @param elapsedInterval The elapsed time in milliseconds. + */ + onInterval?: (elapsedInterval: number) => void; +}; + +/** + * if you need to do something when the loading time exceeds the specified time, refine provides the `useLoadingOvertime` hook. + * It returns the elapsed time in milliseconds. + * + * @example + * const { elapsedTime } = useLoadingOvertime({ + * isLoading, + * interval: 1000, + * onInterval(elapsedInterval) { + * console.log("loading overtime", elapsedInterval); + * }, + * }); + */ +export const useLoadingOvertime = ({ + isPending, + interval = 1000, + onInterval, +}: UseLoadingOvertimeCoreProps): UseLoadingOvertimeCoreReturnType => { + const [elapsedTime, setElapsedTime] = useState(undefined); + + useEffect(() => { + let intervalFn: ReturnType; + + if (isPending) { + intervalFn = setInterval(() => { + // increase elapsed time + setElapsedTime((prevElapsedTime) => { + if (prevElapsedTime === undefined) { + return interval; + } + + return prevElapsedTime + interval; + }); + }, interval); + } + + return () => { + clearInterval(intervalFn); + // reset elapsed time + setElapsedTime(undefined); + }; + }, [isPending, interval]); + + useEffect(() => { + // call onInterval callback + if (onInterval && elapsedTime) { + onInterval(elapsedTime); + } + }, [onInterval, elapsedTime]); + + return { + elapsedTime, + }; +}; diff --git a/modules/core/src/web/hooks/use-query-key/index.ts b/modules/core/src/web/hooks/use-query-key/index.ts new file mode 100644 index 00000000..ae7a8b41 --- /dev/null +++ b/modules/core/src/web/hooks/use-query-key/index.ts @@ -0,0 +1,5 @@ +import { keys } from "./key-builder"; + +export const useQueryKey = () => { + return keys; +}; diff --git a/modules/core/src/web/hooks/use-query-key/key-builder.ts b/modules/core/src/web/hooks/use-query-key/key-builder.ts new file mode 100644 index 00000000..5f674bda --- /dev/null +++ b/modules/core/src/web/hooks/use-query-key/key-builder.ts @@ -0,0 +1,181 @@ +type BaseKey = string | number; + +type ParametrizedDataActions = "list" | "infinite"; +type IdRequiredDataActions = "one" | "report" | "upload"; +type IdsRequiredDataActions = "many"; +type DataMutationActions = + | "custom" + | "customMutation" + | "create" + | "createMany" + | "update" + | "updateMany" + | "delete" + | "deleteMany"; + +type AuthActionType = + | "login" + | "logout" + | "profile" + | "register" + | "forgotPassword" + | "check" + | "onError" + | "permissions" + | "updatePassword"; + +type AuditActionType = "list" | "log" | "rename"; + +type IdType = BaseKey; +type IdsType = IdType[]; + +type ParamsType = any; + +type KeySegment = string | IdType | IdsType | ParamsType; + +export function arrayFindIndex(array: T[], slice: T[]): number { + return array.findIndex( + (_, index) => + index <= array.length - slice.length && + slice.every((sliceItem, sliceIndex) => array[index + sliceIndex] === sliceItem) + ); +} + +export function arrayReplace(array: T[], partToBeReplaced: T[], newPart: T[]): T[] { + const newArray: T[] = [...array]; + const startIndex = arrayFindIndex(array, partToBeReplaced); + + if (startIndex !== -1) { + newArray.splice(startIndex, partToBeReplaced.length, ...newPart); + } + + return newArray; +} + +export function stripUndefined(segments: KeySegment[]) { + return segments.filter((segment) => segment !== undefined); +} + +class BaseKeyBuilder { + segments: KeySegment[] = []; + + constructor(segments: KeySegment[] = []) { + this.segments = segments; + } + + key() { + return this.segments; + } + + get() { + return this.segments; + } +} + +class ParamsKeyBuilder extends BaseKeyBuilder { + params(paramsValue?: ParamsType) { + return new BaseKeyBuilder([...this.segments, paramsValue]); + } +} + +class DataIdRequiringKeyBuilder extends BaseKeyBuilder { + id(idValue?: IdType) { + return new ParamsKeyBuilder([...this.segments, idValue ? String(idValue) : undefined]); + } +} + +class DataIdsRequiringKeyBuilder extends BaseKeyBuilder { + ids(...idsValue: IdsType) { + return new ParamsKeyBuilder([ + ...this.segments, + ...(idsValue.length ? [idsValue.map((el) => String(el))] : []), + ]); + } +} + +class DataResourceKeyBuilder extends BaseKeyBuilder { + action(actionType: ParametrizedDataActions): ParamsKeyBuilder; + action(actionType: IdRequiredDataActions): DataIdRequiringKeyBuilder; + action(actionType: IdsRequiredDataActions): DataIdsRequiringKeyBuilder; + action( + actionType: ParametrizedDataActions | IdRequiredDataActions | IdsRequiredDataActions + ): ParamsKeyBuilder | DataIdRequiringKeyBuilder | DataIdsRequiringKeyBuilder { + if (["one", "report"].includes(actionType)) { + return new DataIdRequiringKeyBuilder([...this.segments, actionType]); + } + if (actionType === "many") { + return new DataIdsRequiringKeyBuilder([...this.segments, actionType]); + } + if (["list", "infinite"].includes(actionType)) { + return new ParamsKeyBuilder([...this.segments, actionType]); + } + throw new Error("Invalid action type"); + } +} + +class DataKeyBuilder extends BaseKeyBuilder { + resource(resourceName?: string) { + return new DataResourceKeyBuilder([...this.segments, resourceName]); + } + + mutation(mutationName: DataMutationActions) { + return new ParamsKeyBuilder([ + ...(mutationName === "custom" ? this.segments : [this.segments[0]]), + mutationName, + ]); + } +} + +class AuthKeyBuilder extends BaseKeyBuilder { + action(actionType: AuthActionType) { + return new ParamsKeyBuilder([...this.segments, actionType]); + } +} + +class AccessResourceKeyBuilder extends BaseKeyBuilder { + action(resourceName: string) { + return new ParamsKeyBuilder([...this.segments, resourceName]); + } +} + +class AccessKeyBuilder extends BaseKeyBuilder { + resource(resourceName?: string) { + return new AccessResourceKeyBuilder([...this.segments, resourceName]); + } +} + +class AuditActionKeyBuilder extends BaseKeyBuilder { + action(actionType: Extract) { + return new ParamsKeyBuilder([...this.segments, actionType]); + } +} + +class AuditKeyBuilder extends BaseKeyBuilder { + resource(resourceName?: string) { + return new AuditActionKeyBuilder([...this.segments, resourceName]); + } + + action(actionType: Extract) { + return new ParamsKeyBuilder([...this.segments, actionType]); + } +} + +export class KeyBuilder extends BaseKeyBuilder { + data(name?: string) { + return new DataKeyBuilder(["data", name || "default"]); + } + + auth() { + return new AuthKeyBuilder(["auth"]); + } + + access() { + return new AccessKeyBuilder(["access"]); + } + + audit() { + return new AuditKeyBuilder(["audit"]); + } +} + +export const keys = () => new KeyBuilder([]); diff --git a/modules/invoices/package.json b/modules/invoices/package.json index 85a8984a..eff6ff46 100644 --- a/modules/invoices/package.json +++ b/modules/invoices/package.json @@ -8,14 +8,17 @@ "./api": "./src/api/index.ts", "./dto": "./src/common/dto/index.ts", "./manifest": "./src/web/manifest.ts", - "./hooks/*": ["./src/web/hooks/*.tsx", "./src/hooks/*.ts"], + "./hooks/*": [ + "./src/web/hooks/*.tsx", + "./src/hooks/*.ts" + ], "./components": "./src/web/components/index.tsx", "./components/*": "./src/web/components/*.tsx", "./locales": "./src/common/locales/index.tsx" }, "peerDependencies": { - "ag-grid-react": "^33.3.0", "ag-grid-community": "^33.3.0", + "ag-grid-react": "^33.3.0", "i18next": "^25.1.1", "react": "^18 || ^19", "react-dom": "^18 || ^19", @@ -38,6 +41,8 @@ "react": "^19.1.0", "react-dom": "^19.1.0", "react-i18next": "^15.5.1", - "react-router-dom": "^6.26.0" + "react-router-dom": "^6.26.0", + "slugify": "^1.6.6", + "zod": "^3.24.4" } } diff --git a/modules/invoices/src/api/application/create-invoice.use-case.ts b/modules/invoices/src/api/application/create-invoice.use-case.ts index bf26d503..bb34de40 100644 --- a/modules/invoices/src/api/application/create-invoice.use-case.ts +++ b/modules/invoices/src/api/application/create-invoice.use-case.ts @@ -11,7 +11,7 @@ import { import { ITransactionManager } from "@/core/common/infrastructure/database"; import { logger } from "@/core/logger"; import { Result } from "@repo/rdx-utils"; -import { ICreateInvoiceRequestDTO } from "../presentation/dto"; +import { ICreateInvoiceRequestDTO } from "../../common/dto"; export class CreateInvoiceUseCase { constructor( diff --git a/modules/invoices/src/api/application/update-invoice.use-case.ts b/modules/invoices/src/api/application/update-invoice.use-case.ts index 919568ae..04a7cba0 100644 --- a/modules/invoices/src/api/application/update-invoice.use-case.ts +++ b/modules/invoices/src/api/application/update-invoice.use-case.ts @@ -1,8 +1,8 @@ import { UniqueID } from "@/core/common/domain"; import { ITransactionManager } from "@/core/common/infrastructure/database"; import { Result } from "@repo/rdx-utils"; +import { IUpdateInvoiceRequestDTO } from "../../common/dto"; import { IInvoiceService, Invoice } from "../domain"; -import { IUpdateInvoiceRequestDTO } from "../presentation/dto"; export class CreateInvoiceUseCase { constructor( diff --git a/modules/invoices/src/api/presentation/controllers/create-invoice/create-invoice.controller.ts b/modules/invoices/src/api/presentation/controllers/create-invoice/create-invoice.controller.ts index 56f5116f..a4628bf8 100644 --- a/modules/invoices/src/api/presentation/controllers/create-invoice/create-invoice.controller.ts +++ b/modules/invoices/src/api/presentation/controllers/create-invoice/create-invoice.controller.ts @@ -1,6 +1,6 @@ import { CreateInvoiceUseCase } from "@/contexts/invoices/application/create-invoice.use-case"; import { ExpressController, UniqueID } from "@/core"; -import { ICreateInvoiceRequestDTO } from "../../dto"; +import { ICreateInvoiceRequestDTO } from "../../../../common/dto"; import { ICreateInvoicePresenter } from "./presenter"; export class CreateInvoiceController extends ExpressController { diff --git a/modules/invoices/src/api/presentation/controllers/create-invoice/presenter/create-invoice.presenter.ts b/modules/invoices/src/api/presentation/controllers/create-invoice/presenter/create-invoice.presenter.ts index 24f7846d..86e59104 100644 --- a/modules/invoices/src/api/presentation/controllers/create-invoice/presenter/create-invoice.presenter.ts +++ b/modules/invoices/src/api/presentation/controllers/create-invoice/presenter/create-invoice.presenter.ts @@ -1,5 +1,5 @@ import { Invoice } from "@/contexts/invoices/domain"; -import { ICreateInvoiceResponseDTO } from "../../../dto"; +import { ICreateInvoiceResponseDTO } from "../../../../../common/dto"; export interface ICreateInvoicePresenter { toDTO: (invoice: Invoice) => ICreateInvoiceResponseDTO; diff --git a/modules/invoices/src/api/presentation/controllers/get-invoice/presenter/get-invoice.presenter.ts b/modules/invoices/src/api/presentation/controllers/get-invoice/presenter/get-invoice.presenter.ts index d11cb74f..d663f964 100644 --- a/modules/invoices/src/api/presentation/controllers/get-invoice/presenter/get-invoice.presenter.ts +++ b/modules/invoices/src/api/presentation/controllers/get-invoice/presenter/get-invoice.presenter.ts @@ -1,5 +1,5 @@ +import { IGetInvoiceResponseDTO } from "../../../../../common/dto"; import { Invoice, InvoiceItem } from "../../../../domain"; -import { IGetInvoiceResponseDTO } from "../../../dto"; export interface IGetInvoicePresenter { toDTO: (invoice: Invoice) => IGetInvoiceResponseDTO; diff --git a/modules/invoices/src/api/presentation/controllers/list-invoices/presenter/list-invoices.presenter.ts b/modules/invoices/src/api/presentation/controllers/list-invoices/presenter/list-invoices.presenter.ts index 57f7f57a..2c359446 100644 --- a/modules/invoices/src/api/presentation/controllers/list-invoices/presenter/list-invoices.presenter.ts +++ b/modules/invoices/src/api/presentation/controllers/list-invoices/presenter/list-invoices.presenter.ts @@ -1,6 +1,6 @@ import { Invoice } from "@/contexts/invoices/domain"; import { Collection } from "@/core"; -import { IListInvoicesResponseDTO } from "../../../dto"; +import { IListInvoicesResponseDTO } from "../../../../../common/dto"; export interface IListInvoicesPresenter { toDTO: (invoices: Collection) => IListInvoicesResponseDTO[]; diff --git a/modules/invoices/src/api/presentation/index.ts b/modules/invoices/src/api/presentation/index.ts index a123289d..6b67c80e 100644 --- a/modules/invoices/src/api/presentation/index.ts +++ b/modules/invoices/src/api/presentation/index.ts @@ -1,2 +1 @@ export * from "./controllers"; -export * from "./dto"; diff --git a/modules/invoices/src/api/presentation/dto/index.ts b/modules/invoices/src/common/dto/index.ts similarity index 100% rename from modules/invoices/src/api/presentation/dto/index.ts rename to modules/invoices/src/common/dto/index.ts diff --git a/modules/invoices/src/api/presentation/dto/invoices.request.dto.ts b/modules/invoices/src/common/dto/invoices.request.dto.ts similarity index 100% rename from modules/invoices/src/api/presentation/dto/invoices.request.dto.ts rename to modules/invoices/src/common/dto/invoices.request.dto.ts diff --git a/modules/invoices/src/api/presentation/dto/invoices.response.dto.ts b/modules/invoices/src/common/dto/invoices.response.dto.ts similarity index 95% rename from modules/invoices/src/api/presentation/dto/invoices.response.dto.ts rename to modules/invoices/src/common/dto/invoices.response.dto.ts index 821fc882..44a334ba 100644 --- a/modules/invoices/src/api/presentation/dto/invoices.response.dto.ts +++ b/modules/invoices/src/common/dto/invoices.response.dto.ts @@ -1,4 +1,4 @@ -import { IMoneyDTO, IQuantityDTO } from "@/core/common/presentation"; +import { IMoneyDTO, IQuantityDTO } from "@erp/core"; export interface IListInvoicesResponseDTO { id: string; diff --git a/modules/invoices/src/api/presentation/dto/invoices.schemas.ts b/modules/invoices/src/common/dto/invoices.schemas.ts similarity index 100% rename from modules/invoices/src/api/presentation/dto/invoices.schemas.ts rename to modules/invoices/src/common/dto/invoices.schemas.ts diff --git a/modules/invoices/src/web/components/invoices-layout.tsx b/modules/invoices/src/web/components/invoices-layout.tsx index 2d0cbc7a..67038e05 100644 --- a/modules/invoices/src/web/components/invoices-layout.tsx +++ b/modules/invoices/src/web/components/invoices-layout.tsx @@ -1,15 +1,10 @@ import { PropsWithChildren } from "react"; -import { SectionCards } from "@repo/rdx-ui/components/layout/section-cards"; import { useTranslation } from "react-i18next"; +import { InvoicesProvider } from "../hooks"; export const InvoicesLayout = ({ children }: PropsWithChildren) => { const { t } = useTranslation("invoices"); - return ( - <> - - {children} - - ); + return {children}; }; diff --git a/modules/invoices/src/web/hooks/invoices-context.tsx b/modules/invoices/src/web/hooks/invoices-context.tsx index bb37c434..e9162e03 100644 --- a/modules/invoices/src/web/hooks/invoices-context.tsx +++ b/modules/invoices/src/web/hooks/invoices-context.tsx @@ -15,7 +15,7 @@ export const InvoicesProvider = ({ children }: PropsWithChildren) => { setPagination, }} > - {children} +

{children}
); }; diff --git a/modules/invoices/src/web/hooks/useInvoices.tsx b/modules/invoices/src/web/hooks/useInvoices.tsx new file mode 100644 index 00000000..0e7991ca --- /dev/null +++ b/modules/invoices/src/web/hooks/useInvoices.tsx @@ -0,0 +1,82 @@ +import { IListResponseDTO } from "@erp/core"; +import { + IGetListDataProviderParams, + UseListQueryResult, + useDataSource, + useList, + useQueryKey, +} from "@erp/core/hooks"; +import { IListInvoicesResponseDTO } from "@erp/invoices/common/dto"; + +export type UseInvoicesListParams = Omit & { + status?: string; + enabled?: boolean; + queryOptions?: Record; +}; + +export type UseInvoicesListResponse = UseListQueryResult< + IListResponseDTO, + unknown +>; + +export type UseInvoicesGetParamsType = { + enabled?: boolean; + queryOptions?: Record; +}; + +export type UseInvoicesReportParamsType = { + enabled?: boolean; + queryOptions?: Record; +}; + +export const useInvoices = () => { + const actions = { + /** + * Hook para obtener la lista de facturas + * @param params - Parámetros para la consulta de la lista de facturas + * @returns - Respuesta de la consulta de la lista de facturas + */ + useList: (params: UseInvoicesListParams): UseInvoicesListResponse => { + const dataSource = useDataSource(); + const keys = useQueryKey(); + + const { + pagination, + status = "draft", + quickSearchTerm = undefined, + enabled = true, + queryOptions, + } = params; + + return useList({ + queryKey: keys().data().resource("invoices").action("list").params(params).get(), + queryFn: () => { + return dataSource.getList({ + resource: "invoices", + quickSearchTerm, + filters: + status !== "all" + ? [ + { + field: "status", + operator: "eq", + value: status, + }, + ] + : [ + { + field: "status", + operator: "ne", + value: "archived", + }, + ], + pagination, + }); + }, + enabled, + queryOptions, + }); + }, + }; + return actions; +}; diff --git a/modules/invoices/src/web/pages/index.tsx b/modules/invoices/src/web/pages/index.tsx index 5428d072..491ccf0c 100644 --- a/modules/invoices/src/web/pages/index.tsx +++ b/modules/invoices/src/web/pages/index.tsx @@ -1 +1 @@ -export * from "./invoices-list"; +export * from "./list"; diff --git a/modules/invoices/src/web/pages/invoices-list.tsx b/modules/invoices/src/web/pages/list.tsx similarity index 100% rename from modules/invoices/src/web/pages/invoices-list.tsx rename to modules/invoices/src/web/pages/list.tsx diff --git a/packages/rdx-criteria/src/Filters/FilterCriteria.ts b/packages/rdx-criteria/src/Filters/FilterCriteria.ts index f5bca612..454eef48 100644 --- a/packages/rdx-criteria/src/Filters/FilterCriteria.ts +++ b/packages/rdx-criteria/src/Filters/FilterCriteria.ts @@ -1,5 +1,5 @@ -import { Result, UndefinedOr } from "@repo/rdx-utils"; -import { ResultCollection, RuleValidator, StringValueObject } from "../helpers"; +import { Result, ResultCollection, RuleValidator, UndefinedOr } from "@repo/rdx-utils"; +import { StringValueObject } from "../helpers"; import { Filter, IFilter } from "./Filter"; export interface IFilterCriteria { diff --git a/packages/rdx-criteria/src/Order/Order.ts b/packages/rdx-criteria/src/Order/Order.ts index 1f235374..be2cc05f 100644 --- a/packages/rdx-criteria/src/Order/Order.ts +++ b/packages/rdx-criteria/src/Order/Order.ts @@ -1,7 +1,6 @@ import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; +import { Result, RuleValidator } from "@repo/rdx-utils"; import Joi from "joi"; -import { RuleValidator } from "../helpers"; export interface IOrderProps { type: string; diff --git a/packages/rdx-criteria/src/Order/OrderCriteria.ts b/packages/rdx-criteria/src/Order/OrderCriteria.ts index 959b86e9..6dd1758f 100644 --- a/packages/rdx-criteria/src/Order/OrderCriteria.ts +++ b/packages/rdx-criteria/src/Order/OrderCriteria.ts @@ -1,5 +1,5 @@ -import { Result, UndefinedOr } from "@repo/rdx-utils"; -import { ResultCollection, RuleValidator, StringValueObject } from "../helpers"; +import { Result, ResultCollection, RuleValidator, UndefinedOr } from "@repo/rdx-utils"; +import { StringValueObject } from "../helpers"; import { IOrderProps, Order } from "./Order"; import { IOrderCollection, OrderCollection } from "./OrderCollection"; diff --git a/packages/rdx-criteria/src/Order/OrderRoot.ts b/packages/rdx-criteria/src/Order/OrderRoot.ts index ed5ebeb2..9b3255ad 100644 --- a/packages/rdx-criteria/src/Order/OrderRoot.ts +++ b/packages/rdx-criteria/src/Order/OrderRoot.ts @@ -1,6 +1,5 @@ -import { DomainError } from "../../../errors"; -import { Result } from "../../Result"; -import { ValueObject } from "../../ValueObject"; +import { ValueObject } from "@repo/rdx-ddd"; +import { Result } from "@repo/rdx-utils"; import { Order } from "./Order"; import { OrderCollection } from "./OrderCollection"; @@ -17,19 +16,16 @@ export interface IOrderRoot { toObject(): Record; } -export class OrderRoot - extends ValueObject - implements IOrderRoot -{ +export class OrderRoot extends ValueObject implements IOrderRoot { public static createASC(value: Order[]): Result { - return this.create({ + return OrderRoot.create({ type: "asc", value, }); } public static createDESC(value: Order[]): Result { - return this.create({ + return OrderRoot.create({ type: "desc", value, }); @@ -37,7 +33,7 @@ export class OrderRoot public static create(orderRootProps: any): Result { // Validación de props - const valid = this.validate(orderRootProps); + const valid = OrderRoot.validate(orderRootProps); if (valid.isFailure) { return Result.fail(valid.error); } @@ -51,7 +47,7 @@ export class OrderRoot } protected static validate(OrderRootRoot: IOrderRootProps): Result { - throw DomainError.create("NOT IMPLEMENT", "OrderRoot.validate()"); + throw new Error("NOT IMPLEMENT OrderRoot.validate()"); /*return Validator.isOneOf( { @@ -75,6 +71,10 @@ export class OrderRoot this._items = props.items; } + getValue() { + return this.props; + } + get type(): string { return this._type; } diff --git a/packages/rdx-criteria/src/Pagination/OffsetPaging.ts b/packages/rdx-criteria/src/Pagination/OffsetPaging.ts index b96d14d2..0f17c327 100644 --- a/packages/rdx-criteria/src/Pagination/OffsetPaging.ts +++ b/packages/rdx-criteria/src/Pagination/OffsetPaging.ts @@ -1,8 +1,7 @@ import Joi from "joi"; import { ValueObject } from "@repo/rdx-ddd"; -import { Result } from "@repo/rdx-utils"; -import { RuleValidator } from "../helpers"; +import { Result, RuleValidator } from "@repo/rdx-utils"; import { INITIAL_PAGE_INDEX, INITIAL_PAGE_SIZE, diff --git a/packages/rdx-criteria/src/QuickSearch/QuickSearchCriteria.ts b/packages/rdx-criteria/src/QuickSearch/QuickSearchCriteria.ts index 515f633b..a5a1a8bc 100644 --- a/packages/rdx-criteria/src/QuickSearch/QuickSearchCriteria.ts +++ b/packages/rdx-criteria/src/QuickSearch/QuickSearchCriteria.ts @@ -1,7 +1,6 @@ import { ValueObject } from "@repo/rdx-ddd"; -import { Result, UndefinedOr } from "@repo/rdx-utils"; +import { Result, RuleValidator, UndefinedOr } from "@repo/rdx-utils"; import Joi from "joi"; -import { RuleValidator } from "../helpers"; export interface IQuickSearchCriteria { searchTerms: string[]; diff --git a/packages/rdx-criteria/src/helpers/index.ts b/packages/rdx-criteria/src/helpers/index.ts index e39a6944..842edd71 100644 --- a/packages/rdx-criteria/src/helpers/index.ts +++ b/packages/rdx-criteria/src/helpers/index.ts @@ -1,3 +1 @@ -export * from "./RuleValidator"; -export * from "./ResultCollection"; export * from "./StringValueObject"; diff --git a/packages/rdx-utils/package.json b/packages/rdx-utils/package.json index c1b4c2ed..c40c5083 100644 --- a/packages/rdx-utils/package.json +++ b/packages/rdx-utils/package.json @@ -13,5 +13,11 @@ "@repo/typescript-config": "workspace:*", "@types/node": "^22.15.12", "typescript": "^5.8.3" + }, + "dependencies": { + "joi": "^17.13.3" + }, + "peerDependencies": { + "joi": "^17.13.3" } } diff --git a/packages/rdx-utils/src/helpers/index.ts b/packages/rdx-utils/src/helpers/index.ts index 5d1da0b4..c675c2eb 100644 --- a/packages/rdx-utils/src/helpers/index.ts +++ b/packages/rdx-utils/src/helpers/index.ts @@ -1,4 +1,6 @@ export * from "./collection"; export * from "./maybe"; export * from "./result"; +export * from "./result-collection"; +export * from "./rule-validator"; export * from "./utils"; diff --git a/packages/rdx-criteria/src/helpers/ResultCollection.ts b/packages/rdx-utils/src/helpers/result-collection.ts similarity index 96% rename from packages/rdx-criteria/src/helpers/ResultCollection.ts rename to packages/rdx-utils/src/helpers/result-collection.ts index 71297bb2..ec4d2f7d 100644 --- a/packages/rdx-criteria/src/helpers/ResultCollection.ts +++ b/packages/rdx-utils/src/helpers/result-collection.ts @@ -1,4 +1,4 @@ -import { Result } from "@repo/rdx-utils"; +import { Result } from "./result"; export interface IResultCollection { add(result: Result): void; diff --git a/packages/rdx-criteria/src/helpers/RuleValidator.ts b/packages/rdx-utils/src/helpers/rule-validator.ts similarity index 97% rename from packages/rdx-criteria/src/helpers/RuleValidator.ts rename to packages/rdx-utils/src/helpers/rule-validator.ts index 0d1b82a9..6f3caf6a 100644 --- a/packages/rdx-criteria/src/helpers/RuleValidator.ts +++ b/packages/rdx-utils/src/helpers/rule-validator.ts @@ -1,5 +1,5 @@ -import { Result } from "@repo/rdx-utils"; import Joi, { ValidationError } from "joi"; +import { Result } from "./result"; export type TRuleValidatorResult = Result; diff --git a/packages/shadcn-ui/src/components/sidebar.tsx b/packages/shadcn-ui/src/components/sidebar.tsx index 8dc6a22a..5ba38984 100644 --- a/packages/shadcn-ui/src/components/sidebar.tsx +++ b/packages/shadcn-ui/src/components/sidebar.tsx @@ -110,6 +110,7 @@ function SidebarProvider({ // This makes it easier to style the sidebar with Tailwind classes. const state = open ? "expanded" : "collapsed"; + // biome-ignore lint/correctness/useExhaustiveDependencies: const contextValue = React.useMemo( () => ({ state, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32135970..f47de410 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -338,6 +338,18 @@ importers: '@repo/rdx-criteria': specifier: workspace:* version: link:../../packages/rdx-criteria + '@repo/rdx-utils': + specifier: workspace:* + version: link:../../packages/rdx-utils + '@tanstack/react-query': + specifier: ^5.75.4 + version: 5.75.4(react@19.1.0) + axios: + specifier: ^1.9.0 + version: 1.9.0 + joi: + specifier: ^17.13.3 + version: 17.13.3 react: specifier: ^19.1.0 version: 19.1.0 @@ -357,6 +369,9 @@ importers: '@testing-library/react-hooks': specifier: ^8.0.1 version: 8.0.1(@types/react@19.1.3)(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + '@types/axios': + specifier: ^0.14.4 + version: 0.14.4 '@types/jest': specifier: 29.5.14 version: 29.5.14 @@ -405,6 +420,12 @@ importers: react-router-dom: specifier: ^6.26.0 version: 6.30.0(react-dom@19.1.0(react@19.1.0))(react@19.1.0) + slugify: + specifier: ^1.6.6 + version: 1.6.6 + zod: + specifier: ^3.24.4 + version: 3.24.4 devDependencies: '@biomejs/biome': specifier: 1.9.4 @@ -570,6 +591,10 @@ importers: version: 5.1.4(typescript@5.8.3)(vite@6.3.5(@types/node@22.15.12)(jiti@2.4.2)(less@4.3.0)(lightningcss@1.29.2)(sass@1.87.0)(stylus@0.62.0)(terser@5.39.0)(tsx@4.19.4)(yaml@2.7.1)) packages/rdx-utils: + dependencies: + joi: + specifier: ^17.13.3 + version: 17.13.3 devDependencies: '@repo/typescript-config': specifier: workspace:* @@ -2611,6 +2636,10 @@ packages: resolution: {integrity: sha512-NxPRAT/mywJ6agqLuVsOag1btEUbPYacVqCndQjvkm5EN0DfjvBIYCsXA/i2Q+Z0hqX84UeIIfIXAQiXpAXZmA==} hasBin: true + '@types/axios@0.14.4': + resolution: {integrity: sha512-9JgOaunvQdsQ/qW2OPmE5+hCeUB52lQSolecrFrthct55QekhmXEwT203s20RL+UHtCQc15y3VXpby9E7Kkh/g==} + deprecated: This is a stub types definition. axios provides its own type definitions, so you do not need this installed. + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} @@ -5468,6 +5497,10 @@ packages: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slugify@1.6.6: + resolution: {integrity: sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==} + engines: {node: '>=8.0.0'} + smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -8028,6 +8061,12 @@ snapshots: semver: 7.6.2 update-check: 1.5.4 + '@types/axios@0.14.4': + dependencies: + axios: 1.9.0 + transitivePeerDependencies: + - debug + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.27.1 @@ -11136,6 +11175,8 @@ snapshots: slash@3.0.0: {} + slugify@1.6.6: {} + smart-buffer@4.2.0: {} snake-case@2.1.0: