feat: refactor proforma creation components and remove unused empty lines card

This commit is contained in:
David Arranz 2026-08-18 12:39:46 +02:00
parent 4411b8f07e
commit cf5a797532
5 changed files with 106 additions and 126 deletions

View File

@ -1,6 +1,5 @@
export * from "./proforma-create-auto-applied-info";
export * from "./proforma-create-customer-field";
export * from "./proforma-create-empty-lines-card";
export * from "./proforma-create-form";
export * from "./proforma-create-header";
export * from "./proforma-create-initial-info-card";

View File

@ -1,80 +1,97 @@
import {
AlertCircleIcon,
BanknoteIcon,
CheckCircle2Icon,
CalculatorIcon,
CircleDollarSignIcon,
ReceiptTextIcon,
CreditCardIcon,
InfoIcon,
ShieldCheckIcon,
SparklesIcon,
} from "lucide-react";
export const ProformaCreateAutoAppliedInfo = () => {
return (
<section className="rounded-xl border border-blue-200 bg-blue-50/60 p-6 text-slate-800">
<div className="flex items-start gap-3">
<AlertCircleIcon className="mt-0.5 size-5 text-blue-600" />
<div className="space-y-2">
<div>
<h2 className="text-lg font-semibold">Se preparará automáticamente</h2>
<p className="text-sm text-slate-600">
<section className="rounded-2xl border border-primary/15 bg-primary/5 p-5 md:p-6">
<div className="space-y-5">
<div className="flex items-start gap-3">
<div className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-background text-primary shadow-xs">
<SparklesIcon className="size-5" />
</div>
<div className="min-w-0 space-y-1.5">
<h2 className="text-lg font-semibold text-foreground">Se preparará automáticamente</h2>
<p className="max-w-3xl text-sm leading-6 text-muted-foreground">
Estos valores iniciales se tomarán del cliente o de la configuración de empresa.
Podrás revisarlos y modificarlos después en la edición.
Podrás revisarlos y modificarlos después.
</p>
</div>
</div>
<div className="rounded-lg border border-blue-200/80 bg-white/60 p-4">
<p className="text-sm font-medium text-slate-900">Datos que se guardarán al crear</p>
<p className="mt-1 text-sm text-slate-600">
Fecha, cliente y serie de proforma para numerar el documento inicial.
</p>
<div className="grid gap-3 md:grid-cols-2 xl:grid-cols-3">
<div className="rounded-xl border border-border/60 bg-background/80 p-4 shadow-xs">
<div className="mb-3 flex size-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
<CircleDollarSignIcon className="size-4.5" />
</div>
<p className="text-sm font-medium text-foreground">Moneda</p>
<p className="mt-1 text-sm text-muted-foreground">EUR</p>
</div>
<div className="grid gap-4 border-y border-blue-200/80 py-4 md:grid-cols-3">
<div className="flex items-start gap-3">
<CircleDollarSignIcon className="mt-0.5 size-5 text-blue-600" />
<div>
<p className="font-medium">Moneda</p>
<p className="text-sm text-slate-600">EUR</p>
</div>
</div>
<div className="flex items-start gap-3">
<BanknoteIcon className="mt-0.5 size-5 text-blue-600" />
<div>
<p className="font-medium">Método de pago</p>
<p className="text-sm text-slate-600">Según cliente</p>
</div>
</div>
<div className="flex items-start gap-3">
<ReceiptTextIcon className="mt-0.5 size-5 text-blue-600" />
<div>
<p className="font-medium">Condiciones de pago</p>
<p className="text-sm text-slate-600">Según cliente</p>
</div>
<div className="rounded-xl border border-border/60 bg-background/80 p-4 shadow-xs">
<div className="mb-3 flex size-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
<CreditCardIcon className="size-4.5" />
</div>
<p className="text-sm font-medium text-foreground">Método de pago</p>
<p className="mt-1 text-sm text-muted-foreground">Según cliente</p>
</div>
<div className="flex items-start gap-3 pt-1">
<AlertCircleIcon className="mt-0.5 size-5 text-blue-600" />
<div>
<p className="font-medium">Configuración fiscal inicial</p>
<p className="text-sm text-slate-600">
<div className="rounded-xl border border-border/60 bg-background/80 p-4 shadow-xs md:col-span-2 xl:col-span-1">
<div className="mb-3 flex size-9 items-center justify-center rounded-lg bg-primary/10 text-primary">
<BanknoteIcon className="size-4.5" />
</div>
<p className="text-sm font-medium text-foreground">Condiciones de pago</p>
<p className="mt-1 text-sm text-muted-foreground">Según cliente</p>
</div>
</div>
<div className="grid gap-4 lg:grid-cols-2">
<div className="flex items-start gap-3 rounded-xl border border-border/50 bg-background/50 p-4">
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<ShieldCheckIcon className="size-4.5" />
</div>
<div className="min-w-0 space-y-1">
<p className="text-sm font-medium text-foreground">Configuración fiscal inicial</p>
<p className="text-sm leading-6 text-muted-foreground">
Se tomará del cliente o de la configuración de empresa. Los impuestos y totales se
calcularán cuando añadas líneas a la proforma.
calcularán al añadir líneas.
</p>
</div>
</div>
<div className="flex items-start gap-3 rounded-lg bg-white/60 p-4">
<CheckCircle2Icon className="mt-0.5 size-5 text-blue-600" />
<div>
<p className="font-medium">Cálculo pendiente</p>
<p className="text-sm text-slate-600">
Al crear sin líneas se guarda la cabecera. El desglose fiscal real se materializa
en la edición, cuando existan líneas valoradas.
<div className="flex items-start gap-3 rounded-xl border border-border/50 bg-background/50 p-4">
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<CalculatorIcon className="size-4.5" />
</div>
<div className="min-w-0 space-y-1">
<p className="text-sm font-medium text-foreground">Cálculo pendiente</p>
<p className="text-sm leading-6 text-muted-foreground">
Los impuestos y totales se calcularán cuando añadas líneas a la proforma.
</p>
</div>
</div>
</div>
<div className="flex items-start gap-3 rounded-xl border border-primary/10 bg-background/70 p-4">
<div className="flex size-9 shrink-0 items-center justify-center rounded-lg bg-primary/10 text-primary">
<InfoIcon className="size-4.5" />
</div>
<div className="min-w-0 space-y-1">
<p className="text-sm font-medium text-foreground">
Las líneas de detalle se añadirán en la siguiente pantalla
</p>
<p className="text-sm leading-6 text-muted-foreground">
La proforma se creará sin líneas. Podrás añadir productos o servicios tras crear el
borrador.
</p>
</div>
</div>
</div>
</section>
);

View File

@ -1,31 +0,0 @@
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@repo/shadcn-ui/components";
import { ListIcon } from "lucide-react";
export const ProformaCreateEmptyLinesCard = () => {
return (
<Card>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-xl">
<ListIcon className="size-5 text-primary" />
Líneas de detalle
</CardTitle>
<CardDescription className="text-base">
La proforma se creará sin líneas. Podrás añadir productos o servicios en la siguiente
pantalla.
</CardDescription>
</CardHeader>
<CardContent className="flex min-h-64 flex-col items-center justify-center gap-4 text-center">
<div className="flex size-20 items-center justify-center rounded-full bg-muted text-muted-foreground">
<ListIcon className="size-9" />
</div>
<div className="space-y-1">
<p className="text-2xl font-semibold tracking-tight">Sin líneas de detalle</p>
<p className="text-muted-foreground">
Añade productos o servicios después de crear el borrador.
</p>
</div>
</CardContent>
</Card>
);
};

View File

@ -2,7 +2,6 @@ import type { CustomerSelectionOption } from "@erp/customers";
import { preventEnterKeySubmitForm } from "@repo/rdx-ui/helpers";
import { ProformaCreateAutoAppliedInfo } from "./proforma-create-auto-applied-info";
import { ProformaCreateEmptyLinesCard } from "./proforma-create-empty-lines-card";
import { ProformaCreateInitialInfoCard } from "./proforma-create-initial-info-card";
interface ProformaCreateFormProps {
@ -54,8 +53,6 @@ export const ProformaCreateForm = ({
/>
<ProformaCreateAutoAppliedInfo />
<ProformaCreateEmptyLinesCard />
</div>
</form>
);

View File

@ -32,46 +32,44 @@ export const ProformaCreatePage = () => {
<div className="flex-1 overflow-y-auto bg-muted/20">
<RdxEditorPageLayout complexity="simple">
<div className="rounded-2xl border border-border/60 bg-background px-4 py-4 shadow-xs md:px-6 md:py-6">
<div className="flex min-w-0 flex-col gap-6">
{createCtrl.isCreateError && (
<ErrorAlert
message={
createCtrl.createError instanceof Error
? createCtrl.createError.message
: "Revisa los datos e inténtalo de nuevo."
}
title="No se pudo crear la proforma"
/>
)}
{createCtrl.isSeriesLoadError && (
<ErrorAlert
message={
createCtrl.seriesLoadError instanceof Error
? createCtrl.seriesLoadError.message
: "Inténtalo de nuevo más tarde."
}
title="No se pudieron cargar las series de facturación"
/>
)}
<ProformaCreateForm
formId={createCtrl.formId}
isPaymentTermsLoading={createCtrl.isPaymentTermsLoading}
isProformaSeriesLoading={createCtrl.isProformaSeriesLoading}
isSubmitting={createCtrl.isCreating}
isTargetInvoiceSeriesLoading={createCtrl.isTargetInvoiceSeriesLoading}
onClearCustomer={createCtrl.clearCustomer}
onPaymentTermChange={createCtrl.handlePaymentTermChange}
onSelectCustomer={selectCustomerCtrl.selectCtrl.openDialog}
onSubmit={createCtrl.onSubmit}
paymentTermOptions={createCtrl.paymentTermOptions}
proformaSeriesOptions={createCtrl.proformaSeriesOptions}
selectedCustomer={createCtrl.selectedCustomer}
targetInvoiceSeriesOptions={createCtrl.targetInvoiceSeriesOptions}
<div className="flex min-w-0 flex-col gap-6">
{createCtrl.isCreateError && (
<ErrorAlert
message={
createCtrl.createError instanceof Error
? createCtrl.createError.message
: "Revisa los datos e inténtalo de nuevo."
}
title="No se pudo crear la proforma"
/>
</div>
)}
{createCtrl.isSeriesLoadError && (
<ErrorAlert
message={
createCtrl.seriesLoadError instanceof Error
? createCtrl.seriesLoadError.message
: "Inténtalo de nuevo más tarde."
}
title="No se pudieron cargar las series de facturación"
/>
)}
<ProformaCreateForm
formId={createCtrl.formId}
isPaymentTermsLoading={createCtrl.isPaymentTermsLoading}
isProformaSeriesLoading={createCtrl.isProformaSeriesLoading}
isSubmitting={createCtrl.isCreating}
isTargetInvoiceSeriesLoading={createCtrl.isTargetInvoiceSeriesLoading}
onClearCustomer={createCtrl.clearCustomer}
onPaymentTermChange={createCtrl.handlePaymentTermChange}
onSelectCustomer={selectCustomerCtrl.selectCtrl.openDialog}
onSubmit={createCtrl.onSubmit}
paymentTermOptions={createCtrl.paymentTermOptions}
proformaSeriesOptions={createCtrl.proformaSeriesOptions}
selectedCustomer={createCtrl.selectedCustomer}
targetInvoiceSeriesOptions={createCtrl.targetInvoiceSeriesOptions}
/>
</div>
</RdxEditorPageLayout>
</div>