import { useState, useEffect } from "react"; import { useTranslate, useNotify, useDataProvider, Form } from "ra-core"; import { Save } from "lucide-react"; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from "@/components/ds/ui/dialog"; import { Button } from "@/components/ds/ui/button"; import { TextInput } from "@/components/ds/admin/text-input"; import type { InvoiceTemplate } from "../types"; import { InvoiceItemsInput } from "./InvoiceItemsInput"; interface TemplateEditDialogProps { open: boolean; onClose: () => void; template?: InvoiceTemplate | null; onSuccess: () => void; } export const TemplateEditDialog = ({ open, onClose, template, onSuccess, }: TemplateEditDialogProps) => { const translate = useTranslate(); const notify = useNotify(); const dataProvider = useDataProvider(); const [isSaving, setIsSaving] = useState(false); const [initialValues, setInitialValues] = useState(null); const [isLoading, setIsLoading] = useState(false); useEffect(() => { if (open) { if (template) { setIsLoading(true); dataProvider .getList("invoice_template_items", { filter: { template_id: template.id }, pagination: { page: 1, perPage: 100 }, sort: { field: "sort_order", order: "ASC" }, }) .then(({ data }) => { setInitialValues({ name: template.name, description: template.description, default_payment_terms: template.default_payment_terms, default_terms_and_conditions: template.default_terms_and_conditions, default_due_days: template.default_due_days || 30, items: data || [], discount: 0, discount_type: "fixed", }); setIsLoading(false); }) .catch((error) => { console.error(error); notify("Error loading template items", { type: "error" }); setIsLoading(false); }); } else { setInitialValues({ name: "", description: "", default_payment_terms: "", default_terms_and_conditions: "", default_due_days: 30, items: [], discount: 0, discount_type: "fixed", }); } } else { setInitialValues(null); } }, [open, template, dataProvider, notify]); const handleSave = async (values: any) => { if (!values.name) { notify("Template name is required", { type: "warning" }); return; } setIsSaving(true); try { let templateId: number; const templateData = { name: values.name, description: values.description, default_payment_terms: values.default_payment_terms, default_terms_and_conditions: values.default_terms_and_conditions, default_due_days: Math.max( 0, values.default_due_days ? parseInt(values.default_due_days) : 30, ), }; if (template) { // Update existing template await dataProvider.update("invoice_templates", { id: template.id, data: templateData, previousData: template, }); templateId = template.id; notify(translate("resources.invoice_templates.notification.updated"), { type: "success", }); } else { // Create new template const { data: newTemplate } = await dataProvider.create( "invoice_templates", { data: templateData, }, ); templateId = newTemplate.id; notify(translate("resources.invoice_templates.notification.created"), { type: "success", }); } // Handle items (Delete existing & Re-create) if (template) { const { data: existingItems } = await dataProvider.getList( "invoice_template_items", { filter: { template_id: templateId }, pagination: { page: 1, perPage: 100 }, sort: { field: "id", order: "ASC" }, }, ); // Delete all old items in parallel await Promise.all( existingItems.map((item) => dataProvider.delete("invoice_template_items", { id: item.id, previousData: item, }), ), ); } // Create new items in parallel const items = values.items || []; await Promise.all( items.map((item: any, i: number) => dataProvider.create("invoice_template_items", { data: { template_id: templateId, description: item.description, item_description: item.item_description, quantity: item.quantity, unit_price: item.unit_price, tax_rate: item.tax_rate || 0, discount_amount: item.discount_amount || 0, discount_type: item.discount_type || "percentage", sort_order: i, }, }), ), ); onSuccess(); } catch (error: any) { notify(error.message || "Error saving template", { type: "error" }); } finally { setIsSaving(false); } }; return ( {template ? "Edit Template" : translate("resources.invoice_templates.action.create")} Create a reusable template for common invoice configurations {isLoading || !initialValues ? (
{translate("ra.action.loading")}
) : (
(value ? undefined : "Required")} />
)}
); };