import InputError from '@/components/input-error'; import { Button } from '@/components/ui/button'; import { Calendar } from '@/components/ui/calendar'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select'; import { Textarea } from '@/components/ui/textarea'; import AppLayout from '@/layouts/app-layout'; import { cn } from '@/lib/utils'; import { type BreadcrumbItem } from '@/types'; import { Head, useForm } from '@inertiajs/react'; import { format } from 'date-fns'; import { CalendarIcon } from 'lucide-react'; import { useEffect, useState } from 'react'; interface TransactionFormProps { mode: 'create' | 'edit'; patients: Array<{ id: string; name: string }>; registrations: Array<{ id: string; registration_number: string; patient_name: string }>; insurances: Array<{ id: string; name: string }>; procedures: Array<{ id: string; code: string; name: string; base_price?: number; tax_percentage?: number; is_taxable?: boolean; }>; employees: Array<{ id: string; name: string }>; paymentMethods: Record; statusOptions: Record; transaction?: { id?: string; invoice_number: string; registration_id: string; patient_id: string; insurance_id?: string; procedure_id?: string; employee_id?: string; service_name: string; transaction_datetime: string; payment_datetime?: string; due_date?: string; subtotal: number; tax_amount: number; discount_amount: number; grand_total: number; paid_amount: number; insurance_covered_amount: number; patient_responsibility: number; payment_method: string; payment_reference?: string; status: string; notes?: string; }; } const breadcrumbs: BreadcrumbItem[] = [ { title: 'Dashboard', href: '/dashboard' }, { title: 'Transaksi', href: '/transactions' }, { title: 'Form', href: '#' }, ]; const toLocalISOString = (date: Date) => { const offset = date.getTimezoneOffset(); const localDate = new Date(date.getTime() - offset * 60 * 1000); return localDate.toISOString().slice(0, 16); }; export default function TransactionForm({ mode, patients, registrations, insurances, procedures, employees, paymentMethods, statusOptions, transaction, }: TransactionFormProps) { const { data, setData, post, put, processing, errors, reset } = useForm({ registration_id: transaction?.registration_id || '', patient_id: transaction?.patient_id || '', insurance_id: transaction?.insurance_id || '', procedure_id: transaction?.procedure_id || '', employee_id: transaction?.employee_id || '', service_name: transaction?.service_name || '', transaction_datetime: transaction?.transaction_datetime || toLocalISOString(new Date()), payment_datetime: transaction?.payment_datetime || '', due_date: transaction?.due_date || '', subtotal: transaction?.subtotal || 0, tax_amount: transaction?.tax_amount || 0, discount_amount: transaction?.discount_amount || 0, grand_total: transaction?.grand_total || 0, paid_amount: transaction?.paid_amount || 0, insurance_covered_amount: transaction?.insurance_covered_amount || 0, patient_responsibility: transaction?.patient_responsibility || 0, payment_method: transaction?.payment_method || 'cash', payment_reference: transaction?.payment_reference || '', status: transaction?.status || 'pending', notes: transaction?.notes || '', }); const [registrationSelected, setRegistrationSelected] = useState(false); // update pasien ketika memilih register useEffect(() => { if (data.registration_id && data.registration_id !== 'none') { const selectedRegistration = registrations.find((r) => r.id === data.registration_id); if (selectedRegistration) { setRegistrationSelected(true); const patient = patients.find((p) => p.name === selectedRegistration.patient_name); if (patient) { setData('patient_id', patient.id); } } } else { setRegistrationSelected(false); } }, [data.registration_id, registrations, patients]); // Update ruangan, subtotal dan pajak ketika prosedur di select useEffect(() => { if (data.procedure_id && data.procedure_id !== 'manual') { const selectedProcedure = procedures.find((p) => p.id === data.procedure_id); if (selectedProcedure) { const basePrice = selectedProcedure.base_price || 0; const taxAmount = selectedProcedure.is_taxable && selectedProcedure.tax_percentage ? basePrice * (selectedProcedure.tax_percentage / 100) : 0; setData({ ...data, service_name: selectedProcedure.name, subtotal: basePrice, tax_amount: taxAmount, }); } } }, [data.procedure_id, procedures]); useEffect(() => { // Pastikan semua nilai numerik valid (gunakan 0 jika NaN) const subtotal = Number(data.subtotal) || 0; const taxAmount = Number(data.tax_amount) || 0; const discountAmount = Number(data.discount_amount) || 0; const calculatedGrandTotal = subtotal + taxAmount - discountAmount; let insuranceCovered = 0; if (data.payment_method === 'insurance' && data.insurance_id) { // Pastikan insurance covered tidak melebihi grand total insuranceCovered = Math.min(calculatedGrandTotal, calculatedGrandTotal * 0.8); } const patientResponsibility = calculatedGrandTotal - insuranceCovered; setData({ ...data, subtotal, tax_amount: taxAmount, discount_amount: discountAmount, grand_total: calculatedGrandTotal, insurance_covered_amount: insuranceCovered, patient_responsibility: patientResponsibility, // Update paid_amount hanya jika belum diisi atau jika nilainya tidak valid paid_amount: Number(data.paid_amount) || patientResponsibility, }); }, [data.subtotal, data.tax_amount, data.discount_amount, data.payment_method, data.insurance_id]); // Calculate grand_total, insurance_covered_amount and patient_responsibility useEffect(() => { const calculatedGrandTotal = data.subtotal + data.tax_amount - data.discount_amount; let insuranceCovered = 0; if (data.payment_method === 'insurance' && data.insurance_id) { // Example: insurance covers 80% of the total insuranceCovered = calculatedGrandTotal * 0.8; } const patientResponsibility = calculatedGrandTotal - insuranceCovered; setData({ ...data, grand_total: calculatedGrandTotal, insurance_covered_amount: insuranceCovered, patient_responsibility: patientResponsibility, // Default paid amount to what patient is responsible for paid_amount: data.paid_amount || patientResponsibility, }); }, [data.subtotal, data.tax_amount, data.discount_amount, data.payment_method, data.insurance_id]); const onSubmit = (e: React.FormEvent) => { e.preventDefault(); if (mode === 'create') { post(route('transactions.store'), { onSuccess: () => reset(), }); } else { put(route('transactions.update', transaction?.id), { preserveScroll: true, }); } }; const formatCurrency = (value: number) => { return new Intl.NumberFormat('id-ID', { style: 'currency', currency: 'IDR', minimumFractionDigits: 0, }).format(value); }; return (

{mode === 'create' ? 'Tambah Transaksi Baru' : 'Edit Data Transaksi'}

{mode === 'edit' && transaction?.invoice_number && No. Invoice: {transaction.invoice_number}}
{/* Registration Section */}
{/* Procedure Section */}
setData('service_name', e.target.value)} placeholder="Nama layanan" />
date && setData('transaction_datetime', toLocalISOString(date))} initialFocus />
{ const date = data.transaction_datetime?.split('T')[0] || toLocalISOString(new Date()).split('T')[0]; setData('transaction_datetime', `${date}T${e.target.value}`); }} />
{/* Financial Section */}
{ const value = parseFloat(e.target.value); setData('subtotal', isNaN(value) ? 0 : value); }} placeholder="Subtotal" />
setData('tax_amount', Math.max(0, parseFloat(e.target.value) || 0))} placeholder="Jumlah pajak" />
setData('discount_amount', Math.max(0, parseFloat(e.target.value) || 0))} placeholder="Jumlah diskon" />
{formatCurrency(isNaN(data.grand_total) ? 0 : data.grand_total)}
{data.payment_method === 'insurance' && ( <>
{ const insuranceCovered = Math.max(0, parseFloat(e.target.value) || 0); setData({ ...data, insurance_covered_amount: insuranceCovered, patient_responsibility: data.grand_total - insuranceCovered, }); }} placeholder="Jumlah dibayar asuransi" />
)}
{formatCurrency(data.patient_responsibility)}
{ const paidAmount = Math.max(0, parseFloat(e.target.value) || 0); setData('paid_amount', paidAmount); }} placeholder="Jumlah pembayaran" />
setData('payment_reference', e.target.value)} placeholder="No. Kartu/No. Referensi/dll" />
date && setData('payment_datetime', toLocalISOString(date))} initialFocus />
{ const date = data.payment_datetime?.split('T')[0] || toLocalISOString(new Date()).split('T')[0]; setData('payment_datetime', `${date}T${e.target.value}`); }} />