.
This commit is contained in:
parent
4beb7aa207
commit
92faca9bfa
6
.vscode/settings.json
vendored
6
.vscode/settings.json
vendored
@ -5,6 +5,12 @@
|
||||
// Enable Font Ligatures
|
||||
"editor.fontLigatures": true,
|
||||
|
||||
// Lint
|
||||
"eslint.workingDirectories": [{ "mode": "auto" }],
|
||||
"eslint.run": "onType",
|
||||
"eslint.validate": ["javascript", "typescript", "typescriptreact"],
|
||||
"eslint.lintTask.enable": true,
|
||||
|
||||
// Javascript and TypeScript settings
|
||||
"js/ts.suggest.enabled": true,
|
||||
"js/ts.suggest.autoImports": true,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/factuges-server",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "tsup src/index.ts --config tsup.config.ts",
|
||||
|
||||
@ -125,14 +125,14 @@ async function setupModule(name: string, params: ModuleParams, stack: string[])
|
||||
// 4) models
|
||||
if (pkgApi?.models) {
|
||||
await withPhase(name, "registerModels", async () => {
|
||||
await Promise.resolve(registerModels(pkgApi.models, params, { moduleName: name }));
|
||||
await Promise.resolve(registerModels(pkgApi.models!, params, { moduleName: name }));
|
||||
});
|
||||
}
|
||||
|
||||
// 5) services (namespaced)
|
||||
if (pkgApi?.services) {
|
||||
await withPhase(name, "registerServices", async () => {
|
||||
validateModuleServices(name, pkgApi.services);
|
||||
validateModuleServices(name, pkgApi.services!);
|
||||
|
||||
for (const [serviceKey, serviceApi] of Object.entries(pkgApi.services!)) {
|
||||
const fullName = buildServiceName(name, serviceKey);
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/factuges-web",
|
||||
"private": true,
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite --host --clearScreen false",
|
||||
|
||||
@ -1,18 +1,18 @@
|
||||
import { Button } from "@repo/shadcn-ui/components";
|
||||
import * as React from "react";
|
||||
import { FallbackProps } from "react-error-boundary";
|
||||
import type { FallbackProps } from "react-error-boundary";
|
||||
|
||||
/**
|
||||
* 1) Fallback simple
|
||||
*/
|
||||
export function SimpleFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div role='alert' className='p-4 rounded-md border bg-red-50 text-red-700'>
|
||||
<p className='font-medium'>⚠️ Algo salió mal</p>
|
||||
<pre className='mt-2 text-sm whitespace-pre-wrap'>{error?.message}</pre>
|
||||
<div className="p-4 rounded-md border bg-red-50 text-red-700" role="alert">
|
||||
<p className="font-medium">⚠️ Algo salió mal</p>
|
||||
<pre className="mt-2 text-sm whitespace-pre-wrap">{error?.message}</pre>
|
||||
<Button
|
||||
className="mt-3 px-3 py-1.5 rounded-md bg-red-600 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='mt-3 px-3 py-1.5 rounded-md bg-red-600 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
@ -25,22 +25,22 @@ export function SimpleFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
*/
|
||||
export function SectionCardFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div role='alert' className='rounded-2xl border shadow-sm p-5 bg-white'>
|
||||
<div className='flex items-start gap-3'>
|
||||
<div className='shrink-0 rounded-full p-2 bg-red-100'>❗</div>
|
||||
<div className='grow'>
|
||||
<h3 className='font-semibold text-gray-900'>No se pudo cargar esta sección</h3>
|
||||
<p className='mt-1 text-sm text-gray-600'>{error?.message}</p>
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<div className="rounded-2xl border shadow-sm p-5 bg-white" role="alert">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="shrink-0 rounded-full p-2 bg-red-100">❗</div>
|
||||
<div className="grow">
|
||||
<h3 className="font-semibold text-gray-900">No se pudo cargar esta sección</h3>
|
||||
<p className="mt-1 text-sm text-gray-600">{error?.message}</p>
|
||||
<div className="mt-3 flex gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-gray-900 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md border"
|
||||
onClick={() => window.location.reload()}
|
||||
className='px-3 py-1.5 rounded-md border'
|
||||
>
|
||||
Refrescar página
|
||||
</Button>
|
||||
@ -56,15 +56,15 @@ export function SectionCardFallback({ error, resetErrorBoundary }: FallbackProps
|
||||
*/
|
||||
export function FullPageFallback({ error }: FallbackProps) {
|
||||
return (
|
||||
<div className='min-h-screen flex flex-col items-center justify-center px-6 bg-gray-50 text-center'>
|
||||
<div className='text-5xl'>😵</div>
|
||||
<h1 className='mt-4 text-2xl font-bold text-gray-900'>Ocurrió un error inesperado</h1>
|
||||
<p className='mt-2 text-gray-600'>{error?.message}</p>
|
||||
<div className='mt-6 flex flex-wrap items-center justify-center gap-3'>
|
||||
<a href='/' className='px-4 py-2 rounded-md bg-blue-600 text-white'>
|
||||
<div className="min-h-screen flex flex-col items-center justify-center px-6 bg-gray-50 text-center">
|
||||
<div className="text-5xl">😵</div>
|
||||
<h1 className="mt-4 text-2xl font-bold text-gray-900">Ocurrió un error inesperado</h1>
|
||||
<p className="mt-2 text-gray-600">{error?.message}</p>
|
||||
<div className="mt-6 flex flex-wrap items-center justify-center gap-3">
|
||||
<a className="px-4 py-2 rounded-md bg-blue-600 text-white" href="/">
|
||||
Volver al inicio
|
||||
</a>
|
||||
<Button onClick={() => window.location.reload()} className='px-4 py-2 rounded-md border'>
|
||||
<Button className="px-4 py-2 rounded-md border" onClick={() => window.location.reload()}>
|
||||
Recargar
|
||||
</Button>
|
||||
</div>
|
||||
@ -77,22 +77,22 @@ export function FullPageFallback({ error }: FallbackProps) {
|
||||
*/
|
||||
export function ListFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div role='alert' className='p-4 rounded-md border bg-amber-50'>
|
||||
<div className='flex items-start gap-3'>
|
||||
<span className='text-xl'>🗂️</span>
|
||||
<div className="p-4 rounded-md border bg-amber-50" role="alert">
|
||||
<div className="flex items-start gap-3">
|
||||
<span className="text-xl">🗂️</span>
|
||||
<div>
|
||||
<p className='font-medium text-amber-900'>No pudimos cargar la lista.</p>
|
||||
<p className='text-sm text-amber-800 mt-1'>{error?.message}</p>
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<p className="font-medium text-amber-900">No pudimos cargar la lista.</p>
|
||||
<p className="text-sm text-amber-800 mt-1">{error?.message}</p>
|
||||
<div className="mt-3 flex gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-amber-700 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-amber-700 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md border"
|
||||
onClick={() => window.location.reload()}
|
||||
className='px-3 py-1.5 rounded-md border'
|
||||
>
|
||||
Recargar
|
||||
</Button>
|
||||
@ -108,17 +108,17 @@ export function ListFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
*/
|
||||
export function FormFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div role='alert' className='rounded-md border p-4 bg-red-50'>
|
||||
<h4 className='font-semibold text-red-800'>No se pudo mostrar el formulario</h4>
|
||||
<p className='mt-1 text-sm text-red-700'>{error?.message}</p>
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<div className="rounded-md border p-4 bg-red-50" role="alert">
|
||||
<h4 className="font-semibold text-red-800">No se pudo mostrar el formulario</h4>
|
||||
<p className="mt-1 text-sm text-red-700">{error?.message}</p>
|
||||
<div className="mt-3 flex gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-red-600 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-red-600 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button onClick={() => history.back()} className='px-3 py-1.5 rounded-md border'>
|
||||
<Button className="px-3 py-1.5 rounded-md border" onClick={() => history.back()}>
|
||||
Volver atrás
|
||||
</Button>
|
||||
</div>
|
||||
@ -135,18 +135,18 @@ export function NetworkFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
: "Estás sin conexión. Revisa tu red y reintenta.";
|
||||
|
||||
return (
|
||||
<div role='alert' className='rounded-md border p-4 bg-blue-50 text-blue-900'>
|
||||
<div className='font-medium'>No pudimos obtener los datos</div>
|
||||
<p className='mt-1 text-sm'>{error?.message}</p>
|
||||
<p className='mt-1 text-xs opacity-80'>{note}</p>
|
||||
<div className='mt-3 flex gap-2'>
|
||||
<div className="rounded-md border p-4 bg-blue-50 text-blue-900" role="alert">
|
||||
<div className="font-medium">No pudimos obtener los datos</div>
|
||||
<p className="mt-1 text-sm">{error?.message}</p>
|
||||
<p className="mt-1 text-xs opacity-80">{note}</p>
|
||||
<div className="mt-3 flex gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-blue-700 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-blue-700 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button onClick={() => window.location.reload()} className='px-3 py-1.5 rounded-md border'>
|
||||
<Button className="px-3 py-1.5 rounded-md border" onClick={() => window.location.reload()}>
|
||||
Recargar
|
||||
</Button>
|
||||
</div>
|
||||
@ -160,23 +160,23 @@ export function NetworkFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
export function DevDetailsFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
return (
|
||||
<div role='alert' className='rounded-md border p-4 bg-gray-50'>
|
||||
<div className='flex items-center justify-between'>
|
||||
<p className='font-medium text-gray-900'>Algo falló</p>
|
||||
<div className='flex gap-2'>
|
||||
<div className="rounded-md border p-4 bg-gray-50" role="alert">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="font-medium text-gray-900">Algo falló</p>
|
||||
<div className="flex gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-gray-900 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
|
||||
>
|
||||
Reintentar
|
||||
</Button>
|
||||
<Button onClick={() => setOpen((v) => !v)} className='px-3 py-1.5 rounded-md border'>
|
||||
<Button className="px-3 py-1.5 rounded-md border" onClick={() => setOpen((v) => !v)}>
|
||||
{open ? "Ocultar detalles" : "Ver detalles"}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{open && (
|
||||
<pre className='mt-3 text-xs whitespace-pre-wrap bg-white p-3 rounded-md border overflow-auto'>
|
||||
<pre className="mt-3 text-xs whitespace-pre-wrap bg-white p-3 rounded-md border overflow-auto">
|
||||
{error?.stack || error?.message}
|
||||
</pre>
|
||||
)}
|
||||
@ -189,22 +189,22 @@ export function DevDetailsFallback({ error, resetErrorBoundary }: FallbackProps)
|
||||
*/
|
||||
export function SupportFallback({ error, resetErrorBoundary }: FallbackProps) {
|
||||
return (
|
||||
<div role='alert' className='rounded-md border p-4 bg-white'>
|
||||
<h4 className='font-semibold text-gray-900'>No pudimos completar la acción</h4>
|
||||
<p className='mt-1 text-gray-700'>{error?.message}</p>
|
||||
<div className='mt-3 flex flex-wrap gap-2'>
|
||||
<div className="rounded-md border p-4 bg-white" role="alert">
|
||||
<h4 className="font-semibold text-gray-900">No pudimos completar la acción</h4>
|
||||
<p className="mt-1 text-gray-700">{error?.message}</p>
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
<Button
|
||||
className="px-3 py-1.5 rounded-md bg-gray-900 text-white"
|
||||
onClick={resetErrorBoundary}
|
||||
className='px-3 py-1.5 rounded-md bg-gray-900 text-white'
|
||||
>
|
||||
Intentar de nuevo
|
||||
</Button>
|
||||
<a href='/ayuda' className='px-3 py-1.5 rounded-md border'>
|
||||
<a className="px-3 py-1.5 rounded-md border" href="/ayuda">
|
||||
Ir a Ayuda
|
||||
</a>
|
||||
<a
|
||||
href='mailto:soporte@tuapp.com?subject=Error%20en%20la%20aplicaci%C3%B3n'
|
||||
className='px-3 py-1.5 rounded-md border'
|
||||
className="px-3 py-1.5 rounded-md border"
|
||||
href="mailto:soporte@tuapp.com?subject=Error%20en%20la%20aplicaci%C3%B3n"
|
||||
>
|
||||
Contactar soporte
|
||||
</a>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { IModuleClient, ModuleClientParams } from "@erp/core/client";
|
||||
import { JSX } from "react";
|
||||
import { RouteObject, useRoutes } from "react-router-dom";
|
||||
import type { IModuleClient, ModuleClientParams } from "@erp/core/client";
|
||||
import type { JSX } from "react";
|
||||
import { type RouteObject, useRoutes } from "react-router-dom";
|
||||
|
||||
interface ModuleRoutesProps {
|
||||
modules: IModuleClient[];
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { AxiosInstance } from "axios";
|
||||
import type { AxiosInstance } from "axios";
|
||||
|
||||
/**
|
||||
* Datos requeridos para iniciar sesión.
|
||||
|
||||
@ -5,9 +5,14 @@ export default [
|
||||
{
|
||||
files: ["**/*.ts", "**/*.tsx"],
|
||||
ignores: [
|
||||
"**/docs/**",
|
||||
"**/dist/**",
|
||||
"**/out/**",
|
||||
"**/.turbo/**",
|
||||
"**/node_modules/**"
|
||||
"**/.vscode/**",
|
||||
"**/node_modules/**",
|
||||
"**/scripts/**",
|
||||
"**/tools/**"
|
||||
],
|
||||
languageOptions: {
|
||||
parser,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/auth",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/core",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,13 +1,21 @@
|
||||
import { type JsonTaxCatalogProvider, SpainTaxCatalogProvider } from "../../../common";
|
||||
import {
|
||||
FactuGESPaymentCatalogProvider,
|
||||
type JsonPaymentCatalogProvider,
|
||||
type JsonTaxCatalogProvider,
|
||||
SpainTaxCatalogProvider,
|
||||
} from "../../../common";
|
||||
|
||||
export interface ICatalogs {
|
||||
taxCatalog: JsonTaxCatalogProvider;
|
||||
paymentCatalog: JsonPaymentCatalogProvider;
|
||||
}
|
||||
|
||||
export const buildCatalogs = (): ICatalogs => {
|
||||
const taxCatalog = SpainTaxCatalogProvider();
|
||||
const paymentCatalog = FactuGESPaymentCatalogProvider();
|
||||
|
||||
return {
|
||||
taxCatalog,
|
||||
paymentCatalog,
|
||||
};
|
||||
};
|
||||
|
||||
@ -1 +1,2 @@
|
||||
export * from "./payments";
|
||||
export * from "./taxes";
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
[
|
||||
{
|
||||
"id": "019c2834-a766-7787-a626-fa89cac3a8a1",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "6",
|
||||
"description": "TRANSFERENCIA",
|
||||
"group": "General"
|
||||
},
|
||||
{
|
||||
"id": "57ed228f-88bd-431d-b5e6-0ed9cff01684",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "14",
|
||||
"description": "DOMICILIACION BANCARIA",
|
||||
"group": "General"
|
||||
},
|
||||
{
|
||||
"id": "336e477f-9260-4cb7-b6fd-76f3b088a395",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "15",
|
||||
"description": "TRANSFERENCIA BANCARIA",
|
||||
"group": "General"
|
||||
}
|
||||
]
|
||||
@ -0,0 +1,5 @@
|
||||
import factugesPaymentCatalog from "./factuges-payment-catalog.json";
|
||||
import { JsonPaymentCatalogProvider } from "./json-payment-catalog.provider";
|
||||
|
||||
export const FactuGESPaymentCatalogProvider = () =>
|
||||
new JsonPaymentCatalogProvider(factugesPaymentCatalog);
|
||||
4
modules/core/src/common/catalogs/payments/index.ts
Normal file
4
modules/core/src/common/catalogs/payments/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from "./factuges-payment-catalog.provider";
|
||||
export * from "./json-payment-catalog.provider";
|
||||
export * from "./payment-catalog.provider";
|
||||
export * from "./payment-catalog-types";
|
||||
@ -0,0 +1,64 @@
|
||||
// --- Adaptador que carga el catálogo JSON en memoria e indexa por code ---
|
||||
|
||||
import { Maybe } from "@repo/rdx-utils";
|
||||
|
||||
import type { PaymentCatalogProvider } from "./payment-catalog.provider";
|
||||
import type {
|
||||
PaymentCatalogType,
|
||||
PaymentItemType,
|
||||
PaymentLookupItems,
|
||||
} from "./payment-catalog-types";
|
||||
|
||||
export class JsonPaymentCatalogProvider implements PaymentCatalogProvider {
|
||||
// Índice por código normalizado
|
||||
private readonly catalog: Map<string, PaymentItemType>;
|
||||
|
||||
/**
|
||||
* @param catalog Catálogo ya parseado (p.ej. import JSON o fetch)
|
||||
*/
|
||||
constructor(catalog: PaymentCatalogType) {
|
||||
this.catalog = new Map<string, PaymentItemType>();
|
||||
// Normalizamos códigos a minúsculas y sin espacios
|
||||
for (const item of catalog) {
|
||||
const key = item.factuges_id;
|
||||
// En caso de duplicados, el último gana (o lanza error si prefieres)
|
||||
this.catalog.set(key, item);
|
||||
}
|
||||
}
|
||||
|
||||
static normalizeCode(code: string): string {
|
||||
return (code ?? "").trim().toLowerCase();
|
||||
}
|
||||
|
||||
findByFactuGESId(factuges_id: string): Maybe<PaymentItemType> {
|
||||
const found = this.catalog.get(factuges_id);
|
||||
return found ? Maybe.some(found) : Maybe.none<PaymentItemType>();
|
||||
}
|
||||
|
||||
findById(id: string): Maybe<PaymentItemType> {
|
||||
for (const value of this.catalog.values()) {
|
||||
if (value.id === id) {
|
||||
return Maybe.some(value);
|
||||
}
|
||||
}
|
||||
|
||||
return Maybe.none<PaymentItemType>();
|
||||
}
|
||||
getAll(): PaymentItemType[] {
|
||||
return Array.from(this.catalog.values());
|
||||
}
|
||||
|
||||
/** Devuelve un objeto indexado por código, compatible con PaymentMultiSelectField */
|
||||
toOptionLookup(): PaymentLookupItems {
|
||||
return this.getAll().map((item) => ({
|
||||
label: item.description,
|
||||
value: item.id,
|
||||
group: item.group,
|
||||
}));
|
||||
}
|
||||
|
||||
/** Devuelve la lista única de grupos disponibles */
|
||||
groups(): string[] {
|
||||
return Array.from(new Set(Array.from(this.catalog.values()).map((i) => i.group)));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
// --- DTOs del catálogo (comparten contrato entre frontend/backend) ---
|
||||
|
||||
export type PaymentItemType = {
|
||||
id: string;
|
||||
company_id: string;
|
||||
factuges_id: string;
|
||||
description: string;
|
||||
group: string;
|
||||
};
|
||||
|
||||
export type PaymentCatalogType = PaymentItemType[];
|
||||
|
||||
export type PaymentLookupItems = {
|
||||
label: string;
|
||||
value: string;
|
||||
group: string;
|
||||
}[];
|
||||
@ -0,0 +1,19 @@
|
||||
import type { Maybe } from "@repo/rdx-utils"; // Usa tu implementación real de Maybe
|
||||
|
||||
import type {
|
||||
PaymentCatalogType,
|
||||
PaymentItemType,
|
||||
PaymentLookupItems,
|
||||
} from "./payment-catalog-types";
|
||||
|
||||
export interface PaymentCatalogProvider {
|
||||
findByFactuGESId(factuges_id: string): Maybe<PaymentItemType>;
|
||||
findById(id: string): Maybe<PaymentItemType>;
|
||||
|
||||
// devuelve el catálogo completo como array
|
||||
getAll(): PaymentCatalogType;
|
||||
|
||||
toOptionLookup(): PaymentLookupItems;
|
||||
|
||||
groups(): string[]; //Devuelve una lista con los grupos
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/customer-invoices",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -401,6 +401,7 @@ export class Proforma extends AggregateRoot<ProformaInternalProps> implements IP
|
||||
this.props.status = InvoiceStatus.issued();
|
||||
return Result.ok();
|
||||
}
|
||||
|
||||
// Cálculos
|
||||
|
||||
/**
|
||||
|
||||
@ -258,6 +258,8 @@ export class ProformaItem extends DomainEntity<InternalProformaItemProps> implem
|
||||
// Calcular impuestos individuales a partir de la base imponible
|
||||
const { ivaAmount, recAmount, retentionAmount } = this.taxes.totals(taxableAmount);
|
||||
|
||||
// El importe de la retención ya va en negativo (-1) y
|
||||
// no hace falta indicarlo como resta.
|
||||
const taxesAmount = ivaAmount.add(recAmount).add(retentionAmount);
|
||||
const totalAmount = taxableAmount.add(taxesAmount);
|
||||
|
||||
|
||||
@ -18,6 +18,8 @@ type TaxGroupState = {
|
||||
retentionCode: Maybe<string>;
|
||||
retentionPercentage: Maybe<TaxPercentage>;
|
||||
retentionAmount: ItemAmount;
|
||||
|
||||
taxesAmount: ItemAmount;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -56,6 +58,8 @@ export function proformaComputeTaxGroups(items: IProformaItems): Map<string, Tax
|
||||
? Maybe.some(retention.unwrap().percentage)
|
||||
: Maybe.none(),
|
||||
retentionAmount: ItemAmount.zero(currency.code),
|
||||
|
||||
taxesAmount: ItemAmount.zero(currency.code),
|
||||
});
|
||||
}
|
||||
|
||||
@ -67,6 +71,7 @@ export function proformaComputeTaxGroups(items: IProformaItems): Map<string, Tax
|
||||
g.ivaAmount = g.ivaAmount.add(itemTotals.ivaAmount);
|
||||
g.recAmount = g.recAmount.add(itemTotals.recAmount);
|
||||
g.retentionAmount = g.retentionAmount.add(itemTotals.retentionAmount);
|
||||
g.taxesAmount = g.taxesAmount.add(itemTotals.taxesAmount);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@ -19,8 +19,8 @@ export interface IProformaItemsTotals {
|
||||
}
|
||||
|
||||
/**
|
||||
* Calcula los totales (scale 4) a partir de las líneas valoradas.
|
||||
* La lógica fiscal está en ProformaItem; aquí solo se agregan resultados.
|
||||
* Acumula los totales (scale 4) a partir de los totales de las líneas valoradas.
|
||||
* Aquí no se hace ningúna operación de cálculo.
|
||||
*/
|
||||
export class ProformaItemsTotalsCalculator {
|
||||
constructor(private readonly items: ProformaItems) {}
|
||||
|
||||
@ -30,16 +30,14 @@ export class ProformaTaxesCalculator {
|
||||
|
||||
public calculate(): Collection<IProformaTaxTotals> {
|
||||
const groups = proformaComputeTaxGroups(this.items); // <- devuelve en escala 4
|
||||
//const currencyCode = this.items.currencyCode;
|
||||
|
||||
// Vamos acumulando los importes, redondeando previamente a 2 decimales
|
||||
const rows = Array.from(groups.values()).map((g) => {
|
||||
const taxableAmount = this.toInvoiceAmount(g.taxableAmount);
|
||||
const ivaAmount = this.toInvoiceAmount(g.ivaAmount);
|
||||
const recAmount = this.toInvoiceAmount(g.recAmount);
|
||||
const retentionAmount = this.toInvoiceAmount(g.retentionAmount);
|
||||
//const taxesAmount = this.toInvoiceAmount(g.taxesAmount);
|
||||
|
||||
const taxesAmount = ivaAmount.add(recAmount).subtract(retentionAmount);
|
||||
const taxesAmount = this.toInvoiceAmount(g.taxesAmount);
|
||||
|
||||
return {
|
||||
taxableAmount,
|
||||
|
||||
@ -1,3 +1,3 @@
|
||||
export * from "./common/persistence";
|
||||
export * from "./common";
|
||||
export * from "./issued-invoices";
|
||||
export * from "./proformas";
|
||||
|
||||
@ -13,16 +13,17 @@ export interface IProformaPersistenceMappers {
|
||||
export const buildProformaPersistenceMappers = (
|
||||
catalogs: ICatalogs
|
||||
): IProformaPersistenceMappers => {
|
||||
const { taxCatalog } = catalogs;
|
||||
const { taxCatalog, paymentCatalog } = catalogs;
|
||||
|
||||
// Mappers para el repositorio
|
||||
const domainMapper = new SequelizeProformaDomainMapper({
|
||||
taxCatalog,
|
||||
paymentCatalog,
|
||||
});
|
||||
const listMapper = new SequelizeProformaSummaryMapper();
|
||||
|
||||
// Mappers el DTO a las props validadas (CustomerProps) y luego construir agregado
|
||||
const createMapper = new CreateProformaInputMapper({ taxCatalog });
|
||||
const createMapper = new CreateProformaInputMapper();
|
||||
|
||||
return {
|
||||
domainMapper,
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import type { JsonPaymentCatalogProvider } from "@erp/core";
|
||||
import { DiscountPercentage, type MapperParamsType, SequelizeDomainMapper } from "@erp/core/api";
|
||||
import {
|
||||
CurrencyCode,
|
||||
@ -11,11 +12,10 @@ import {
|
||||
maybeFromNullableResult,
|
||||
maybeToNullable,
|
||||
} from "@repo/rdx-ddd";
|
||||
import { Maybe, Result, isNullishOrEmpty } from "@repo/rdx-utils";
|
||||
import { Result } from "@repo/rdx-utils";
|
||||
|
||||
import {
|
||||
InvoiceNumber,
|
||||
InvoicePaymentMethod,
|
||||
InvoiceSerie,
|
||||
InvoiceStatus,
|
||||
Proforma,
|
||||
@ -40,9 +40,21 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
private _recipientMapper: SequelizeProformaRecipientDomainMapper;
|
||||
private _taxesMapper: SequelizeProformaTaxesDomainMapper;
|
||||
|
||||
private _paymentCatalog: JsonPaymentCatalogProvider;
|
||||
|
||||
constructor(params: MapperParamsType) {
|
||||
super();
|
||||
|
||||
const { paymentCatalog } = params as {
|
||||
paymentCatalog: JsonPaymentCatalogProvider;
|
||||
};
|
||||
|
||||
this._paymentCatalog = paymentCatalog;
|
||||
|
||||
if (!this._paymentCatalog) {
|
||||
throw new Error('paymentCatalog not defined ("SequelizeProformaDomainMapper")');
|
||||
}
|
||||
|
||||
this._itemsMapper = new SequelizeProformaItemDomainMapper(params);
|
||||
this._recipientMapper = new SequelizeProformaRecipientDomainMapper();
|
||||
this._taxesMapper = new SequelizeProformaTaxesDomainMapper(params);
|
||||
@ -118,7 +130,7 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
);
|
||||
|
||||
// Método de pago (VO opcional con id + descripción)
|
||||
let paymentMethod = Maybe.none<InvoicePaymentMethod>();
|
||||
/*let paymentMethod = Maybe.none<InvoicePaymentMethod>();
|
||||
|
||||
if (!isNullishOrEmpty(raw.payment_method_id)) {
|
||||
const paymentId = extractOrPushError(
|
||||
@ -127,19 +139,34 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
errors
|
||||
);
|
||||
|
||||
const paymentVO = extractOrPushError(
|
||||
InvoicePaymentMethod.create(
|
||||
{ paymentDescription: String(raw.payment_method_description ?? "") },
|
||||
paymentId ?? undefined
|
||||
),
|
||||
"payment_method_description",
|
||||
errors
|
||||
);
|
||||
if (paymentId) {
|
||||
const paymentOrNot = this._paymentCatalog.findById(paymentId.toString());
|
||||
|
||||
if (paymentVO) {
|
||||
paymentMethod = Maybe.some(paymentVO);
|
||||
if (paymentOrNot.isSome()) {
|
||||
const paymentCatalogItem = paymentOrNot.unwrap();
|
||||
|
||||
const paymentVO = extractOrPushError(
|
||||
InvoicePaymentMethod.create(
|
||||
{ paymentDescription: paymentCatalogItem.description ?? "" },
|
||||
paymentId
|
||||
),
|
||||
"paymentMethod",
|
||||
errors
|
||||
);
|
||||
|
||||
if (paymentVO) {
|
||||
paymentMethod = Maybe.some(paymentVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
// Método de pago (ID)
|
||||
const paymentMethodId = extractOrPushError(
|
||||
maybeFromNullableResult(raw.payment_method_id, (value) => UniqueID.create(String(value))),
|
||||
"payment_method_id",
|
||||
errors
|
||||
);
|
||||
|
||||
// % descuento global (VO)
|
||||
const globalDiscountPercentage = extractOrPushError(
|
||||
@ -170,7 +197,7 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
notes,
|
||||
languageCode,
|
||||
currencyCode,
|
||||
paymentMethod,
|
||||
paymentMethodId,
|
||||
|
||||
globalDiscountPercentage,
|
||||
linkedInvoiceId,
|
||||
@ -241,7 +268,7 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
|
||||
globalDiscountPercentage: attributes.globalDiscountPercentage!,
|
||||
|
||||
paymentMethod: attributes.paymentMethod!,
|
||||
paymentMethodId: attributes.paymentMethodId!,
|
||||
|
||||
linkedInvoiceId: attributes.linkedInvoiceId!, // El id de la factura emitida (linked_invoice) se asigna al hacer issue() desde la proforma, no viene en el modelo de persistencia.
|
||||
};
|
||||
@ -296,7 +323,27 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
...params,
|
||||
});
|
||||
|
||||
// 4) Si hubo errores de mapeo, devolvemos colección de validación
|
||||
// 4) Payment
|
||||
let payment: {
|
||||
id: string | null;
|
||||
description: string | null;
|
||||
} = { id: null, description: null };
|
||||
|
||||
if (source.hasPaymentMethod) {
|
||||
const paymentId = source.paymentMethodId.unwrap();
|
||||
const paymentOrNot = this._paymentCatalog.findById(paymentId.toString());
|
||||
|
||||
if (paymentOrNot.isSome()) {
|
||||
const paymentItem = paymentOrNot.unwrap();
|
||||
|
||||
payment = {
|
||||
id: paymentItem.id ?? null,
|
||||
description: paymentItem.description ?? null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 5) Si hubo errores de mapeo, devolvemos colección de validación
|
||||
if (errors.length > 0) {
|
||||
return Result.fail(
|
||||
new ValidationErrorCollection("Customer invoice mapping to persistence failed", errors)
|
||||
@ -329,14 +376,8 @@ export class SequelizeProformaDomainMapper extends SequelizeDomainMapper<
|
||||
description: maybeToNullable(source.description, (description) => description),
|
||||
notes: maybeToNullable(source.notes, (v) => v.toPrimitive()),
|
||||
|
||||
payment_method_id: maybeToNullable(
|
||||
source.paymentMethod,
|
||||
(payment) => payment.toObjectString().id
|
||||
),
|
||||
payment_method_description: maybeToNullable(
|
||||
source.paymentMethod,
|
||||
(payment) => payment.toObjectString().payment_description
|
||||
),
|
||||
payment_method_id: payment.id,
|
||||
payment_method_description: payment.description,
|
||||
|
||||
subtotal_amount_value: allAmounts.subtotalAmount.value,
|
||||
subtotal_amount_scale: allAmounts.subtotalAmount.scale,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/customers",
|
||||
"description": "Customers",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@erp/factuges",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,15 +1,22 @@
|
||||
import type { ICatalogs } from "@erp/core/api";
|
||||
import { CreateProformaFromFactugesInputMapper, ICreateProformaFromFactugesInputMapper } from '../mappers';
|
||||
|
||||
import {
|
||||
CreateProformaFromFactugesInputMapper,
|
||||
type ICreateProformaFromFactugesInputMapper,
|
||||
} from "../mappers";
|
||||
|
||||
export interface IFactugesInputMappers {
|
||||
createInputMapper: ICreateProformaFromFactugesInputMapper;
|
||||
}
|
||||
|
||||
export const buildFactugesInputMappers = (catalogs: ICatalogs): IFactugesInputMappers => {
|
||||
const { taxCatalog } = catalogs;
|
||||
const { taxCatalog, paymentCatalog } = catalogs;
|
||||
|
||||
// Mappers el DTO a las props validadas (FactugesProps) y luego construir agregado
|
||||
const createInputMapper = new CreateProformaFromFactugesInputMapper({ taxCatalog });
|
||||
const createInputMapper = new CreateProformaFromFactugesInputMapper({
|
||||
taxCatalog,
|
||||
paymentCatalog,
|
||||
});
|
||||
|
||||
return {
|
||||
createInputMapper,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import type { JsonTaxCatalogProvider } from "@erp/core";
|
||||
import type { JsonPaymentCatalogProvider, JsonTaxCatalogProvider } from "@erp/core";
|
||||
import { DiscountPercentage, Tax } from "@erp/core/api";
|
||||
import {
|
||||
InvoiceAmount,
|
||||
@ -103,6 +103,7 @@ export type ProformaDraft = {
|
||||
};
|
||||
|
||||
export type ProformaPaymentDraft = {
|
||||
payment_id: string;
|
||||
factuges_id: string;
|
||||
description: string;
|
||||
};
|
||||
@ -126,9 +127,14 @@ export class CreateProformaFromFactugesInputMapper
|
||||
implements ICreateProformaFromFactugesInputMapper
|
||||
{
|
||||
private readonly taxCatalog: JsonTaxCatalogProvider;
|
||||
private readonly paymentCatalog: JsonPaymentCatalogProvider;
|
||||
|
||||
constructor(params: { taxCatalog: JsonTaxCatalogProvider }) {
|
||||
constructor(params: {
|
||||
taxCatalog: JsonTaxCatalogProvider;
|
||||
paymentCatalog: JsonPaymentCatalogProvider;
|
||||
}) {
|
||||
this.taxCatalog = params.taxCatalog;
|
||||
this.paymentCatalog = params.paymentCatalog;
|
||||
}
|
||||
|
||||
public map(
|
||||
@ -190,9 +196,20 @@ export class CreateProformaFromFactugesInputMapper
|
||||
const errors: ValidationErrorDetail[] = [];
|
||||
const { companyId } = params;
|
||||
|
||||
const factuges_id = String(dto.payment_method_id);
|
||||
const paymentOrNot = this.paymentCatalog.findByFactuGESId(factuges_id);
|
||||
|
||||
if (paymentOrNot.isNone()) {
|
||||
errors.push({
|
||||
path: "payment_method_id",
|
||||
message: "Forma de pago no encontrada",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
factuges_id: String(dto.payment_method_id),
|
||||
description: String(dto.payment_method_description),
|
||||
payment_id: paymentOrNot.unwrap().id,
|
||||
factuges_id: paymentOrNot.unwrap().factuges_id,
|
||||
description: paymentOrNot.unwrap().description,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -340,6 +340,15 @@ export class CreateProformaFromFactugesUseCase {
|
||||
InvoicePaymentMethod.create({ paymentDescription: payment.description }, payment.id).data
|
||||
);
|
||||
|
||||
console.log({
|
||||
...proformaDraft,
|
||||
companyId,
|
||||
customerId,
|
||||
status: defaultStatus,
|
||||
paymentMethod,
|
||||
recipient,
|
||||
});
|
||||
|
||||
return Result.ok({
|
||||
...proformaDraft,
|
||||
companyId,
|
||||
|
||||
@ -3,18 +3,21 @@
|
||||
"id": "019c2834-a766-7787-a626-fa89cac3a8a1",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "6",
|
||||
"description": "TRANSFERENCIA"
|
||||
"description": "TRANSFERENCIA",
|
||||
"group": "General"
|
||||
},
|
||||
{
|
||||
"id": "57ed228f-88bd-431d-b5e6-0ed9cff01684",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "14",
|
||||
"description": "DOMICILIACION BANCARIA"
|
||||
"description": "DOMICILIACION BANCARIA",
|
||||
"group": "General"
|
||||
},
|
||||
{
|
||||
"id": "336e477f-9260-4cb7-b6fd-76f3b088a395",
|
||||
"company_id": "5e4dc5b3-96b9-4968-9490-14bd032fec5f",
|
||||
"factuges_id": "15",
|
||||
"description": "TRANSFERENCIA BANCARIA"
|
||||
"description": "TRANSFERENCIA BANCARIA",
|
||||
"group": "General"
|
||||
}
|
||||
]
|
||||
@ -1,6 +1,6 @@
|
||||
import { type SetupParams, buildCatalogs, buildTransactionManager } from "@erp/core/api";
|
||||
import type { ProformaPublicServices } from "@erp/customer-invoices/api";
|
||||
import type { CustomerPublicServices } from "@erp/customers/api";
|
||||
import type { IProformaPublicServices } from "@erp/customer-invoices/api";
|
||||
import type { ICustomerPublicServices } from "@erp/customers/api";
|
||||
|
||||
import {
|
||||
buildCreateProformaFromFactugesUseCase,
|
||||
@ -11,8 +11,8 @@ import type { CreateProformaFromFactugesUseCase } from "../../application/use-ca
|
||||
export type FactugesInternalDeps = {
|
||||
useCases: {
|
||||
createProforma: (publicServices: {
|
||||
customerServices: CustomerPublicServices;
|
||||
proformaServices: ProformaPublicServices;
|
||||
customerServices: ICustomerPublicServices;
|
||||
proformaServices: IProformaPublicServices;
|
||||
}) => CreateProformaFromFactugesUseCase;
|
||||
};
|
||||
};
|
||||
@ -31,8 +31,8 @@ export function buildFactugesDependencies(params: SetupParams): FactugesInternal
|
||||
return {
|
||||
useCases: {
|
||||
createProforma: (publicServices: {
|
||||
customerServices: CustomerPublicServices;
|
||||
proformaServices: ProformaPublicServices;
|
||||
customerServices: ICustomerPublicServices;
|
||||
proformaServices: IProformaPublicServices;
|
||||
}) =>
|
||||
buildCreateProformaFromFactugesUseCase({
|
||||
dtoMapper: inputMappers.createInputMapper,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/supplier-invoices",
|
||||
"description": "Supplier invoices",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@erp/suppliers",
|
||||
"description": "Suppliers",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
{
|
||||
"name": "uecko-erp-2025",
|
||||
"private": true,
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"workspaces": [
|
||||
"apps/*",
|
||||
"modules/*",
|
||||
"packages/*"
|
||||
],
|
||||
"scripts": {
|
||||
"lint": "turbo run lint",
|
||||
"build": "turbo build",
|
||||
"build:templates": "bash scripts/build-templates.sh",
|
||||
"build:api": "bash scripts/build-api.sh rodax --api",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-criteria",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-ddd",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-logger",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-ui",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@repo/rdx-utils",
|
||||
"version": "0.6.3",
|
||||
"version": "0.6.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"sideEffects": false,
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { AlertDialog as AlertDialogPrimitive } from "@base-ui/react/alert-dialog"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Avatar as AvatarPrimitive } from "@base-ui/react/avatar"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { mergeProps } from "@base-ui/react/merge-props"
|
||||
import { useRender } from "@base-ui/react/use-render"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
|
||||
@ -89,7 +89,7 @@ function Carousel({
|
||||
)
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!api || !setApi) return
|
||||
if (!(api && setApi)) return
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
|
||||
|
||||
@ -180,7 +180,7 @@ function ChartTooltipContent({
|
||||
labelKey,
|
||||
])
|
||||
|
||||
if (!active || !payload?.length) {
|
||||
if (!(active && payload?.length)) {
|
||||
return null
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ function ChartTooltipContent({
|
||||
className
|
||||
)}
|
||||
>
|
||||
{!nestLabel ? tooltipLabel : null}
|
||||
{nestLabel ? null : tooltipLabel}
|
||||
<div className="grid gap-1.5">
|
||||
{payload
|
||||
.filter((item) => item.type !== "none")
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Command as CommandPrimitive } from "cmdk"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { ContextMenu as ContextMenuPrimitive } from "@base-ui/react/context-menu"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Drawer as DrawerPrimitive } from "vaul"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Menu as MenuPrimitive } from "@base-ui/react/menu"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Input as InputPrimitive } from "@base-ui/react/input"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { mergeProps } from "@base-ui/react/merge-props"
|
||||
import { useRender } from "@base-ui/react/use-render"
|
||||
import { cva, type VariantProps } from "class-variance-authority"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Menu as MenuPrimitive } from "@base-ui/react/menu"
|
||||
import { Menubar as MenubarPrimitive } from "@base-ui/react/menubar"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
import { ChevronDownIcon } from "lucide-react"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
import { Button } from "@repo/shadcn-ui/components/button"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Popover as PopoverPrimitive } from "@base-ui/react/popover"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Select as SelectPrimitive } from "@base-ui/react/select"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
import { Dialog as SheetPrimitive } from "@base-ui/react/dialog"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
@ -518,7 +518,7 @@ function SidebarMenuButton({
|
||||
},
|
||||
props
|
||||
),
|
||||
render: !tooltip ? render : <TooltipTrigger render={render} />,
|
||||
render: tooltip ? <TooltipTrigger render={render} /> : render,
|
||||
state: {
|
||||
slot: "sidebar-menu-button",
|
||||
sidebar: "menu-button",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
"use client"
|
||||
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import * as React from "react"
|
||||
import type * as React from "react"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import * as React from "react"
|
||||
import { Toggle as TogglePrimitive } from "@base-ui/react/toggle"
|
||||
import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group"
|
||||
import { type VariantProps } from "class-variance-authority"
|
||||
import type { VariantProps } from "class-variance-authority"
|
||||
|
||||
import { cn } from "@repo/shadcn-ui/lib/utils"
|
||||
import { toggleVariants } from "@repo/shadcn-ui/components/toggle"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue
Block a user