267 lines
12 KiB
TypeScript
267 lines
12 KiB
TypeScript
import { Button } from '@/components/ui/button';
|
|
import { Input } from '@/components/ui/input';
|
|
import { Label } from '@/components/ui/label';
|
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
import { Textarea } from '@/components/ui/textarea';
|
|
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 { useEffect } from 'react';
|
|
|
|
interface ServiceRoomFormProps {
|
|
mode: 'create' | 'edit';
|
|
room?: {
|
|
id?: string;
|
|
code: string;
|
|
name: string;
|
|
type: string;
|
|
class: string;
|
|
floor?: string;
|
|
building?: string;
|
|
wing?: string;
|
|
capacity: number;
|
|
price_per_day?: number;
|
|
facilities?: string;
|
|
is_available: boolean;
|
|
is_active: boolean;
|
|
};
|
|
roomTypes: string[];
|
|
roomClasses: Record<string, string>;
|
|
}
|
|
|
|
const breadcrumbs: BreadcrumbItem[] = [
|
|
{ title: 'Dashboard', href: '/dashboard' },
|
|
{ title: 'Manajemen Ruangan', href: '/room-services' },
|
|
{ title: 'Form Ruangan', href: '#' },
|
|
];
|
|
|
|
export default function ServiceRoomForm({ mode, room, roomTypes, roomClasses }: ServiceRoomFormProps) {
|
|
const { data, setData, post, put, processing, errors, reset } = useForm({
|
|
code: room?.code || '',
|
|
name: room?.name || '',
|
|
type: room?.type || 'Rawat Inap',
|
|
class: room?.class || 'standard',
|
|
floor: room?.floor || '',
|
|
building: room?.building || '',
|
|
wing: room?.wing || '',
|
|
capacity: room?.capacity || 1,
|
|
price_per_day: room?.price_per_day || undefined,
|
|
facilities: room?.facilities || '',
|
|
is_available: room?.is_available ?? true,
|
|
is_active: room?.is_active ?? true,
|
|
});
|
|
|
|
const onSubmit = (e: React.FormEvent) => {
|
|
e.preventDefault();
|
|
if (mode === 'create') {
|
|
post(route('service-rooms.store'), {
|
|
onSuccess: () => reset(),
|
|
});
|
|
} else {
|
|
put(route('service-rooms.update', room?.id), {
|
|
preserveScroll: true,
|
|
});
|
|
}
|
|
};
|
|
|
|
// Format price for display
|
|
const formatPrice = (value: string) => {
|
|
const num = parseFloat(value.replace(/\D/g, '')) || 0;
|
|
return isNaN(num) ? '' : num.toLocaleString('id-ID');
|
|
};
|
|
|
|
return (
|
|
<AppLayout breadcrumbs={breadcrumbs}>
|
|
<Head title={`${mode === 'create' ? 'Tambah' : 'Edit'} Ruangan`} />
|
|
|
|
<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 Ruangan Baru' : 'Edit Data Ruangan'}
|
|
</h1>
|
|
</div>
|
|
|
|
<div>
|
|
<form onSubmit={onSubmit} className="space-y-6">
|
|
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
|
|
{/* Informasi Dasar */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="code">Kode Ruangan*</Label>
|
|
<Input
|
|
id="code"
|
|
value={data.code}
|
|
onChange={(e) => setData('code', e.target.value)}
|
|
placeholder="RJ-101, RI-201"
|
|
/>
|
|
<InputError message={errors.code} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="name">Nama Ruangan*</Label>
|
|
<Input
|
|
id="name"
|
|
value={data.name}
|
|
onChange={(e) => setData('name', e.target.value)}
|
|
placeholder="Ruang Bedah 1, Kamar VIP 2"
|
|
/>
|
|
<InputError message={errors.name} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="type">Jenis Ruangan*</Label>
|
|
<Select
|
|
value={data.type}
|
|
onValueChange={(value) => setData('type', value)}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Pilih jenis ruangan" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{roomTypes.map((type) => (
|
|
<SelectItem key={type} value={type}>
|
|
{type}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
<InputError message={errors.type} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="class">Kelas Ruangan*</Label>
|
|
<Select
|
|
value={data.class}
|
|
onValueChange={(value) => setData('class', value)}
|
|
>
|
|
<SelectTrigger>
|
|
<SelectValue placeholder="Pilih kelas ruangan" />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
{Object.entries(roomClasses).map(([value, label]) => (
|
|
<SelectItem key={value} value={value}>
|
|
{label}
|
|
</SelectItem>
|
|
))}
|
|
</SelectContent>
|
|
</Select>
|
|
<InputError message={errors.class} />
|
|
</div>
|
|
|
|
{/* Lokasi */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="floor">Lantai</Label>
|
|
<Input
|
|
id="floor"
|
|
value={data.floor}
|
|
onChange={(e) => setData('floor', e.target.value)}
|
|
placeholder="1, 2, 3, ..."
|
|
/>
|
|
<InputError message={errors.floor} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="building">Gedung</Label>
|
|
<Input
|
|
id="building"
|
|
value={data.building}
|
|
onChange={(e) => setData('building', e.target.value)}
|
|
placeholder="Gedung A, Utama, ..."
|
|
/>
|
|
<InputError message={errors.building} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="wing">Sayap</Label>
|
|
<Input
|
|
id="wing"
|
|
value={data.wing}
|
|
onChange={(e) => setData('wing', e.target.value)}
|
|
placeholder="Timur, Barat, ..."
|
|
/>
|
|
<InputError message={errors.wing} />
|
|
</div>
|
|
|
|
{/* Kapasitas & Harga */}
|
|
<div className="space-y-2">
|
|
<Label htmlFor="capacity">Kapasitas*</Label>
|
|
<Input
|
|
id="capacity"
|
|
type="number"
|
|
min="1"
|
|
value={data.capacity}
|
|
onChange={(e) => setData('capacity', parseInt(e.target.value) || 0)}
|
|
/>
|
|
<InputError message={errors.capacity} />
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label htmlFor="price_per_day">Harga per Hari (Rp)</Label>
|
|
<Input
|
|
id="price_per_day"
|
|
value={data.price_per_day ? data.price_per_day.toLocaleString('id-ID') : ''}
|
|
onChange={(e) => {
|
|
const value = e.target.value;
|
|
const num = parseFloat(value.replace(/\D/g, '')) || 0;
|
|
setData('price_per_day', isNaN(num) ? undefined : num);
|
|
}}
|
|
placeholder="500.000"
|
|
/>
|
|
<InputError message={errors.price_per_day} />
|
|
</div>
|
|
|
|
{/* Fasilitas */}
|
|
<div className="space-y-2 col-span-full">
|
|
<Label htmlFor="facilities">Fasilitas</Label>
|
|
<Textarea
|
|
id="facilities"
|
|
value={data.facilities}
|
|
onChange={(e) => setData('facilities', e.target.value)}
|
|
placeholder="AC, TV, Kamar Mandi Dalam, ..."
|
|
rows={3}
|
|
/>
|
|
<InputError message={errors.facilities} />
|
|
</div>
|
|
|
|
{/* Status */}
|
|
<div className="flex items-center space-x-2">
|
|
<input
|
|
type="checkbox"
|
|
id="is_available"
|
|
checked={data.is_available}
|
|
onChange={(e) => setData('is_available', e.target.checked)}
|
|
className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-500"
|
|
/>
|
|
<Label htmlFor="is_available">Tersedia</Label>
|
|
</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">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'} Ruangan
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|
|
);
|
|
}
|