import { zodResolver } from "@hookform/resolvers/zod"; import { useFieldArray, useForm } from "react-hook-form"; import * as z from "zod"; import { ClientSelector } from "@erp/customers/components"; import { DevTool } from "@hookform/devtools"; import { DatePickerInputField, TextAreaField, TextField } from "@repo/rdx-ui/components"; import { Button, Calendar, Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, Form, FormControl, FormField, FormItem, FormLabel, FormMessage, Input, Label, Popover, PopoverContent, PopoverTrigger, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Separator, Textarea, } from "@repo/shadcn-ui/components"; import { format } from "date-fns"; import { es } from "date-fns/locale"; import { CalendarIcon, PlusIcon, Save, Trash2Icon, X } from "lucide-react"; import { CustomerInvoicePricesCard } from "../../components"; import { CustomerInvoiceItemsCardEditor } from "../../components/items"; import { useTranslation } from "../../i18n"; import { CustomerInvoiceData } from "./customer-invoice.schema"; import { formatCurrency } from "./utils"; const invoiceFormSchema = z.object({ id: z.string(), invoice_status: z.string(), invoice_number: z.string().min(1, "Número de factura requerido"), invoice_series: z.string().min(1, "Serie requerida"), issue_date: z.string(), operation_date: z.string(), language_code: z.string(), currency: z.string(), customer_id: z.string().min(1, "ID de cliente requerido"), items: z .array( z.object({ description: z.string().optional(), quantity: z .object({ amount: z.number().nullable(), scale: z.number(), }) .optional(), unit_price: z .object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }) .optional(), subtotal_price: z .object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }) .optional(), discount: z .object({ amount: z.number().min(0).max(100).nullable(), scale: z.number(), }) .optional(), discount_price: z .object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }) .optional(), total_price: z .object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }) .optional(), }) ) .min(1, "Al menos un item es requerido"), subtotal_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), discount: z.object({ amount: z.number().nullable(), scale: z.number(), }), discount_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), before_tax_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), tax: z.object({ amount: z.number().nullable(), scale: z.number(), }), tax_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), total_price: z.object({ amount: z.number().nullable(), scale: z.number(), currency_code: z.string(), }), metadata: z.object({ entity: z.string(), }), }); const defaultInvoiceData = { id: "34ae34af-1ffc-4de5-b0a8-c2cf203ef011", invoice_status: "draft", invoice_number: "1", invoice_series: "A", issue_date: "2025-04-30T00:00:00.000Z", operation_date: "2025-04-30T00:00:00.000Z", description: "", language_code: "ES", currency: "EUR", customer_id: "5e4dc5b3-96b9-4968-9490-14bd032fec5f", items: [ { description: "", quantity: { amount: 100, scale: 2, }, unit_price: { amount: 100, scale: 2, currency_code: "EUR", }, subtotal_price: { amount: 100, scale: 2, currency_code: "EUR", }, discount: { amount: 0, scale: 2, }, discount_price: { amount: 0, scale: 2, currency_code: "EUR", }, total_price: { amount: 100, scale: 2, currency_code: "EUR", }, }, ], subtotal_price: { amount: 0, scale: 2, currency_code: "EUR", }, discount: { amount: 0, scale: 0, }, discount_price: { amount: 0, scale: 0, currency_code: "EUR", }, before_tax_price: { amount: 0, scale: 2, currency_code: "EUR", }, tax: { amount: 2100, scale: 2, }, tax_price: { amount: 0, scale: 2, currency_code: "EUR", }, total_price: { amount: 0, scale: 2, currency_code: "EUR", }, }; interface InvoiceFormProps { initialData?: CustomerInvoiceData; isPending?: boolean; /** * Callback function to handle form submission. * @param data - The invoice data submitted by the form. */ onSubmit?: (data: CustomerInvoiceData) => void; } export const CustomerInvoiceEditForm = ({ initialData = defaultInvoiceData, onSubmit, isPending, }: InvoiceFormProps) => { const { t } = useTranslation(); const form = useForm({ resolver: zodResolver(invoiceFormSchema), defaultValues: initialData, }); const { fields, append, remove } = useFieldArray({ control: form.control, name: "items", }); const watchedItems = form.watch("items"); const watchedTaxRate = form.watch("tax.amount"); const addItem = () => { append({ id_article: "", description: "", quantity: { amount: 100, scale: 2 }, unit_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, subtotal_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, discount: { amount: 0, scale: 2 }, discount_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, total_price: { amount: 0, scale: 2, currency_code: form.getValues("currency") }, }); }; const handleSubmit = (data: CustomerInvoiceData) => { console.log("Datos del formulario:", data); onSubmit?.(data); }; const handleError = (errors: any) => { console.error("Errores en el formulario:", errors); // Aquí puedes manejar los errores, por ejemplo, mostrar un mensaje al usuario }; const handleCancel = () => { form.reset(initialData); }; return (
Cliente Description {" "} {/* Información básica */} Información Básica Detalles generales de la factura
); return (
Cliente Description

Radix Primitives

An open-source UI component library.

Blog
Docs
Source
{" "}
{/* Información básica */} Información Básica Detalles generales de la factura
{/* Cliente */} Cliente {/*Items */} {/* Items */}
Artículos Lista de productos o servicios facturados
{fields.map((field, index) => (

Item {index + 1}

{fields.length > 1 && ( )}
( Código Artículo )} /> ( Descripción