115 lines
4.0 KiB
TypeScript
115 lines
4.0 KiB
TypeScript
|
|
import { Description, FieldGroup, Fieldset, Legend } from "@repo/rdx-ui/components";
|
||
|
|
import { Input, Label, Separator } from "@repo/shadcn-ui/components";
|
||
|
|
import { CalculatorIcon } from "lucide-react";
|
||
|
|
import { useState } from "react";
|
||
|
|
import { useFormContext } from "react-hook-form";
|
||
|
|
import { useTranslation } from "../../i18n";
|
||
|
|
import { CustomerInvoiceFormData } from "../../schemas";
|
||
|
|
|
||
|
|
export const InvoiceTotals = () => {
|
||
|
|
const { t } = useTranslation();
|
||
|
|
const { control } = useFormContext<CustomerInvoiceFormData>();
|
||
|
|
|
||
|
|
//const invoiceFormData = useWatch({ control });
|
||
|
|
|
||
|
|
const [invoice, setInvoice] = useState({
|
||
|
|
items: [],
|
||
|
|
subtotal_amount: 0,
|
||
|
|
discount_percentage: 0,
|
||
|
|
discount_amount: 0,
|
||
|
|
taxable_amount: 0,
|
||
|
|
taxes_amount: 0,
|
||
|
|
total_amount: 0,
|
||
|
|
});
|
||
|
|
|
||
|
|
const updateDiscount = (value: number) => {
|
||
|
|
const subtotal = invoice.items.reduce(
|
||
|
|
(sum: number, item: any) => sum + item.subtotal_amount,
|
||
|
|
0
|
||
|
|
);
|
||
|
|
const discountAmount = (subtotal * value) / 100;
|
||
|
|
const taxableAmount = subtotal - discountAmount;
|
||
|
|
const taxesAmount = taxableAmount * 0.21; // Mock calculation
|
||
|
|
const totalAmount = taxableAmount + taxesAmount;
|
||
|
|
|
||
|
|
setInvoice({
|
||
|
|
...invoice,
|
||
|
|
subtotal_amount: subtotal,
|
||
|
|
discount_percentage: value,
|
||
|
|
discount_amount: discountAmount,
|
||
|
|
taxable_amount: taxableAmount,
|
||
|
|
taxes_amount: taxesAmount,
|
||
|
|
total_amount: totalAmount,
|
||
|
|
});
|
||
|
|
};
|
||
|
|
|
||
|
|
const formatCurrency = (amount: number) => {
|
||
|
|
return new Intl.NumberFormat("es-ES", {
|
||
|
|
style: "currency",
|
||
|
|
currency: "EUR",
|
||
|
|
minimumFractionDigits: 2,
|
||
|
|
maximumFractionDigits: 2,
|
||
|
|
}).format(amount);
|
||
|
|
};
|
||
|
|
|
||
|
|
return (
|
||
|
|
<Fieldset>
|
||
|
|
<Legend className='flex items-center gap-2 text-foreground'>
|
||
|
|
<CalculatorIcon className='h-5 w-5' /> {t("form_groups.totals.title")}
|
||
|
|
</Legend>
|
||
|
|
|
||
|
|
<Description>{t("form_groups.totals.description")}</Description>
|
||
|
|
<FieldGroup className='grid grid-cols-1'>
|
||
|
|
<div className='space-y-3'>
|
||
|
|
<div className='flex justify-between items-center'>
|
||
|
|
<Label className='text-sm text-muted-foreground'>Subtotal</Label>
|
||
|
|
<span className='font-medium'>{formatCurrency(invoice.subtotal_amount)}</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className='flex justify-between items-center gap-4'>
|
||
|
|
<Label className='text-sm text-muted-foreground'>Descuento Global</Label>
|
||
|
|
<div className='flex items-center gap-2'>
|
||
|
|
<Input
|
||
|
|
type='number'
|
||
|
|
step='0.01'
|
||
|
|
value={invoice.discount_percentage}
|
||
|
|
onChange={(e) => updateDiscount(Number.parseFloat(e.target.value) || 0)}
|
||
|
|
className='w-20 text-right'
|
||
|
|
/>
|
||
|
|
<span className='text-sm text-muted-foreground'>%</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className='flex justify-between items-center'>
|
||
|
|
<Label className='text-sm text-muted-foreground'>Importe Descuento</Label>
|
||
|
|
<span className='font-medium text-destructive'>
|
||
|
|
-{formatCurrency(invoice.discount_amount)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Separator />
|
||
|
|
|
||
|
|
<div className='flex justify-between items-center'>
|
||
|
|
<Label className='text-sm text-muted-foreground'>Base Imponible</Label>
|
||
|
|
<span className='font-medium'>{formatCurrency(invoice.taxable_amount)}</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div className='flex justify-between items-center'>
|
||
|
|
<Label className='text-sm text-muted-foreground'>Total Impuestos</Label>
|
||
|
|
<span className='font-medium'>{formatCurrency(invoice.taxes_amount)}</span>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<Separator />
|
||
|
|
|
||
|
|
<div className='flex justify-between items-center'>
|
||
|
|
<Label className='text-lg font-semibold'>Total Factura</Label>
|
||
|
|
<span className='text-xl font-bold text-primary'>
|
||
|
|
{formatCurrency(invoice.total_amount)}
|
||
|
|
</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</FieldGroup>
|
||
|
|
</Fieldset>
|
||
|
|
);
|
||
|
|
};
|