351 lines
18 KiB
TypeScript

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 { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { useForm } from '@inertiajs/react';
import AppLayout from '@/layouts/app-layout';
import { Head } from '@inertiajs/react';
import { type BreadcrumbItem } from '@/types';
import InputError from '@/components/input-error';
import { format } from 'date-fns';
import { CalendarIcon } from 'lucide-react';
import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover';
import { cn } from '@/lib/utils';
import { Textarea } from '@/components/ui/textarea';
interface PatientFormProps {
mode: 'create' | 'edit';
patient?: {
id?: string;
medical_record_number: string;
name: string;
gender: string;
nik?: string;
birth_date: string;
birth_place?: string;
address?: string;
phone_number?: string;
email?: string;
blood_type?: string;
religion?: string;
marital_status?: string;
emergency_contact_name?: string;
emergency_contact_phone?: string;
emergency_contact_relation?: string;
is_active: boolean;
};
}
const breadcrumbs: BreadcrumbItem[] = [
{ title: 'Dashboard', href: '/dashboard' },
{ title: 'Patients', href: '/patients' },
{ title: 'Form', href: '#' },
];
const toLocalISOString = (date: Date) => {
const offset = date.getTimezoneOffset();
const localDate = new Date(date.getTime() - (offset * 60 * 1000));
return localDate.toISOString().split('T')[0];
};
export default function PatientForm({ mode, patient }: PatientFormProps) {
const { data, setData, post, put, processing, errors, reset } = useForm({
// Patient fields
medical_record_number: patient?.medical_record_number || '',
name: patient?.name || '',
gender: patient?.gender || 'laki-laki',
nik: patient?.nik || '',
birth_date: patient?.birth_date || '',
birth_place: patient?.birth_place || '',
address: patient?.address || '',
phone_number: patient?.phone_number || '',
email: patient?.email || '',
blood_type: patient?.blood_type || 'unknown',
religion: patient?.religion || '',
marital_status: patient?.marital_status || '',
emergency_contact_name: patient?.emergency_contact_name || '',
emergency_contact_phone: patient?.emergency_contact_phone || '',
emergency_contact_relation: patient?.emergency_contact_relation || '',
is_active: patient?.is_active ?? true,
});
const onSubmit = (e: React.FormEvent) => {
e.preventDefault();
if (mode === 'create') {
post(route('patients.store'), {
onSuccess: () => reset(),
});
} else {
put(route('patients.update', patient?.id), {
preserveScroll: true,
});
}
};
return (
<AppLayout breadcrumbs={breadcrumbs}>
<Head title={`${mode === 'create' ? 'Tambah' : 'Edit'} Pasien`} />
<div className="flex h-full flex-1 flex-col gap-4 rounded-xl p-4">
<div className="flex items-center justify-between">
<h1 className="text-2xl font-bold">
{mode === 'create' ? 'Tambah Pasien Baru' : 'Edit Data Pasien'}
</h1>
{mode === 'edit' && (
<span className="text-xl">
No. Pasien {data.medical_record_number}
</span>
)}
</div>
<div>
<form onSubmit={onSubmit} className="space-y-6">
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
{/* Informasi Utama */}
<div className="space-y-2">
<Label htmlFor="name">Nama Lengkap *</Label>
<Input
id="name"
value={data.name}
onChange={(e) => setData('name', e.target.value)}
placeholder="Nama pasien"
/>
<InputError message={errors.name} />
</div>
<div className="space-y-2">
<Label>Jenis Kelamin *</Label>
<RadioGroup
value={data.gender}
onValueChange={(value) => setData('gender', value)}
className="flex gap-4 mt-4"
>
<div className="flex items-center space-x-2">
<RadioGroupItem value="laki-laki" id="male" />
<Label htmlFor="male">Laki-laki</Label>
</div>
<div className="flex items-center space-x-2">
<RadioGroupItem value="perempuan" id="female" />
<Label htmlFor="female">Perempuan</Label>
</div>
</RadioGroup>
<InputError message={errors.gender} />
</div>
<div className="space-y-2">
<Label htmlFor="nik">NIK</Label>
<Input
id="nik"
value={data.nik}
onChange={(e) => setData('nik', e.target.value)}
placeholder="16-digit NIK"
maxLength={16}
/>
<InputError message={errors.nik} />
</div>
<div className="space-y-2">
<Label htmlFor="birth_date">Tanggal Lahir *</Label>
<Popover>
<PopoverTrigger asChild>
<Button
variant={"outline"}
className={cn(
"w-full justify-start text-left font-normal",
!data.birth_date && "text-muted-foreground"
)}
>
<CalendarIcon className="mr-2 h-4 w-4" />
{data.birth_date ? (
format(new Date(data.birth_date), "dd/MM/yyyy")
) : (
<span>Pilih tanggal</span>
)}
</Button>
</PopoverTrigger>
<PopoverContent className="w-auto p-0">
<Calendar
mode="single"
selected={data.birth_date ? new Date(data.birth_date) : undefined}
onSelect={(date) => date && setData('birth_date', toLocalISOString(date))}
initialFocus
/>
</PopoverContent>
</Popover>
<InputError message={errors.birth_date} />
</div>
<div className="space-y-2">
<Label htmlFor="birth_place">Tempat Lahir</Label>
<Input
id="birth_place"
value={data.birth_place}
onChange={(e) => setData('birth_place', e.target.value)}
placeholder="Kota kelahiran"
/>
<InputError message={errors.birth_place} />
</div>
{/* Kontak & Informasi Tambahan */}
<div className="space-y-2">
<Label htmlFor="phone_number">Nomor Telepon</Label>
<Input
id="phone_number"
value={data.phone_number}
onChange={(e) => setData('phone_number', e.target.value)}
placeholder="08123456789"
/>
<InputError message={errors.phone_number} />
</div>
<div className="space-y-2">
<Label htmlFor="email">Email</Label>
<Input
id="email"
type="email"
value={data.email}
onChange={(e) => setData('email', e.target.value)}
placeholder="joko_susanto@example.com"
/>
<InputError message={errors.email} />
</div>
<div className="space-y-2">
<Label htmlFor="blood_type">Golongan Darah</Label>
<Select
value={data.blood_type}
onValueChange={(value) => setData('blood_type', value)}
>
<SelectTrigger>
<SelectValue placeholder="Pilih golongan darah" />
</SelectTrigger>
<SelectContent>
<SelectItem value="unknown">Tidak Tahu</SelectItem>
<SelectItem value="A">A</SelectItem>
<SelectItem value="B">B</SelectItem>
<SelectItem value="AB">AB</SelectItem>
<SelectItem value="O">O</SelectItem>
</SelectContent>
</Select>
<InputError message={errors.blood_type} />
</div>
<div className="space-y-2">
<Label htmlFor="religion">Agama</Label>
<Select
value={data.religion}
onValueChange={(value) => setData('religion', value)}
>
<SelectTrigger>
<SelectValue placeholder="Pilih agama" />
</SelectTrigger>
<SelectContent>
<SelectItem value="islam">Islam</SelectItem>
<SelectItem value="kristen">Kristen</SelectItem>
<SelectItem value="katolik">Katolik</SelectItem>
<SelectItem value="hindu">Hindu</SelectItem>
<SelectItem value="budha">Budha</SelectItem>
<SelectItem value="konghucu">Konghucu</SelectItem>
<SelectItem value="other">Lainnya</SelectItem>
</SelectContent>
</Select>
<InputError message={errors.religion} />
</div>
<div className="space-y-2">
<Label htmlFor="marital_status">Status Pernikahan</Label>
<Select
value={data.marital_status}
onValueChange={(value) => setData('marital_status', value)}
>
<SelectTrigger>
<SelectValue placeholder="Pilih status" />
</SelectTrigger>
<SelectContent>
<SelectItem value="lajang">Lajang</SelectItem>
<SelectItem value="menikah">Menikah</SelectItem>
<SelectItem value="cerai">Cerai</SelectItem>
<SelectItem value="duda/janda">Duda/Janda</SelectItem>
</SelectContent>
</Select>
<InputError message={errors.marital_status} />
</div>
<div className="space-y-2 col-span-full">
<Label htmlFor="address">Alamat</Label>
<Textarea
id="address"
value={data.address}
onChange={(e) => setData('address', e.target.value)}
placeholder="Alamat lengkap"
/>
<InputError message={errors.address} />
</div>
{/* Kontak Darurat */}
<div className="space-y-2">
<Label htmlFor="emergency_contact_name">Nama Kontak Darurat</Label>
<Input
id="emergency_contact_name"
value={data.emergency_contact_name}
onChange={(e) => setData('emergency_contact_name', e.target.value)}
placeholder="Nama kontak darurat"
/>
<InputError message={errors.emergency_contact_name} />
</div>
<div className="space-y-2">
<Label htmlFor="emergency_contact_phone">Telepon Darurat</Label>
<Input
id="emergency_contact_phone"
value={data.emergency_contact_phone}
onChange={(e) => setData('emergency_contact_phone', e.target.value)}
placeholder="Nomor telepon darurat"
/>
<InputError message={errors.emergency_contact_phone} />
</div>
<div className="space-y-2">
<Label htmlFor="emergency_contact_relation">Hubungan</Label>
<Input
id="emergency_contact_relation"
value={data.emergency_contact_relation}
onChange={(e) => setData('emergency_contact_relation', e.target.value)}
placeholder="Hubungan dengan pasien"
/>
<InputError message={errors.emergency_contact_relation} />
</div>
{mode === 'edit' && (
<div className="flex items-center space-x-2">
<input
type="checkbox"
id="is_active"
checked={data.is_active}
onChange={(e) => setData('is_active', e.target.checked)}
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
/>
<Label htmlFor="is_active">Pasien Aktif</Label>
</div>
)}
</div>
<div className="flex justify-end gap-2">
<Button variant="outline" type="button" onClick={() => window.history.back()}>
Batal
</Button>
<Button type="submit" disabled={processing}>
{mode === 'create' ? 'Simpan' : 'Perbarui'} Pasien
</Button>
</div>
</form>
</div>
</div>
</AppLayout>
);
}