commit
32a36cceff
444 files changed
+67186
No files matched your search
@@ -0,0 +1,226 @@
|
||||
import React, { useState, useEffect, useMemo } from 'react';
|
||||
import { FeedingEvent } from '../../types';
|
||||
import { useAppContext } from '../../context/AppContext.tsx';
|
||||
|
||||
interface FeedScheduleFormModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
onSave: (eventData: Omit<FeedingEvent, 'id' | 'status'>, id?: string) => void;
|
||||
eventToEdit: FeedingEvent | null;
|
||||
initialDate: Date;
|
||||
}
|
||||
|
||||
const FeedScheduleFormModal: React.FC<FeedScheduleFormModalProps> = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
onSave,
|
||||
eventToEdit,
|
||||
initialDate,
|
||||
}) => {
|
||||
const { users, roles } = useAppContext();
|
||||
|
||||
const operators = useMemo(() => {
|
||||
const operatorRoleId = roles.find((r) => r.name === 'Operator')?.id;
|
||||
if (!operatorRoleId) return [];
|
||||
return users.filter((u) => u.roleId === operatorRoleId);
|
||||
}, [users, roles]);
|
||||
|
||||
const [time, setTime] = useState('08:00');
|
||||
const [type, setType] = useState<'AI Recommended' | 'Manual'>('Manual');
|
||||
const [operatorId, setOperatorId] = useState(operators[0]?.id || '');
|
||||
const [feedType, setFeedType] = useState('CP 511 Bravo');
|
||||
const [quantityKg, setQuantityKg] = useState('250');
|
||||
|
||||
useEffect(() => {
|
||||
if (eventToEdit) {
|
||||
const eventTime = eventToEdit.time;
|
||||
setTime(
|
||||
`${String(eventTime.getHours()).padStart(2, '0')}:${String(eventTime.getMinutes()).padStart(2, '0')}`
|
||||
);
|
||||
if (eventToEdit.type === 'AI Recommended' || eventToEdit.type === 'Manual') {
|
||||
setType(eventToEdit.type);
|
||||
}
|
||||
setOperatorId(eventToEdit.operatorId);
|
||||
setFeedType(eventToEdit.feedType);
|
||||
setQuantityKg(String(eventToEdit.quantityKg));
|
||||
} else {
|
||||
setTime('08:00');
|
||||
setType('Manual');
|
||||
setOperatorId(operators[0]?.id || '');
|
||||
setFeedType('CP 511 Bravo');
|
||||
setQuantityKg('250');
|
||||
}
|
||||
}, [eventToEdit, operators]);
|
||||
|
||||
const handleSubmit = (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
const [hours, minutes] = time.split(':').map(Number);
|
||||
const eventDate = eventToEdit ? new Date(eventToEdit.time) : new Date(initialDate);
|
||||
eventDate.setHours(hours, minutes, 0, 0);
|
||||
|
||||
const operator = operators.find((o) => o.id === operatorId);
|
||||
if (!operator) return;
|
||||
|
||||
const kg = parseInt(quantityKg, 10);
|
||||
|
||||
onSave(
|
||||
{
|
||||
time: eventDate,
|
||||
type,
|
||||
operatorId,
|
||||
operatorName: operator.name,
|
||||
feedType,
|
||||
quantityKg: kg,
|
||||
quantitySacks: Math.round(kg / 50),
|
||||
},
|
||||
eventToEdit?.id
|
||||
);
|
||||
};
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="fixed inset-0 bg-black bg-opacity-60 flex justify-center items-center z-50 p-4"
|
||||
onClick={onClose}
|
||||
>
|
||||
<div
|
||||
className="bg-white rounded-xl shadow-2xl w-full max-w-lg"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="p-6">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h2 className="text-2xl font-bold text-gray-800">
|
||||
{eventToEdit ? 'Edit Jadwal Pakan' : 'Tambah Jadwal Pakan'}
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="text-gray-400 hover:text-gray-600 text-2xl"
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 mb-1">Tanggal</label>
|
||||
<input
|
||||
type="text"
|
||||
readOnly
|
||||
value={(eventToEdit ? eventToEdit.time : initialDate).toLocaleDateString(
|
||||
'id-ID',
|
||||
{ weekday: 'long', day: 'numeric', month: 'long' }
|
||||
)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-100"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="operatorId"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Petugas
|
||||
</label>
|
||||
<select
|
||||
id="operatorId"
|
||||
value={operatorId}
|
||||
onChange={(e) => setOperatorId(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-white"
|
||||
required
|
||||
>
|
||||
{operators.map((o) => (
|
||||
<option key={o.id} value={o.id}>
|
||||
{o.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label htmlFor="time" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Waktu
|
||||
</label>
|
||||
<input
|
||||
type="time"
|
||||
id="time"
|
||||
value={time}
|
||||
onChange={(e) => setTime(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label htmlFor="type" className="block text-sm font-medium text-gray-700 mb-1">
|
||||
Tipe
|
||||
</label>
|
||||
<select
|
||||
id="type"
|
||||
value={type}
|
||||
onChange={(e) => setType(e.target.value as 'AI Recommended' | 'Manual')}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md bg-white"
|
||||
>
|
||||
<option value="Manual">Manual</option>
|
||||
<option value="AI Recommended">AI Recommended</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<label
|
||||
htmlFor="feedType"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Jenis Pakan
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
id="feedType"
|
||||
value={feedType}
|
||||
onChange={(e) => setFeedType(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label
|
||||
htmlFor="quantityKg"
|
||||
className="block text-sm font-medium text-gray-700 mb-1"
|
||||
>
|
||||
Jumlah (Kg)
|
||||
</label>
|
||||
<input
|
||||
type="number"
|
||||
id="quantityKg"
|
||||
value={quantityKg}
|
||||
onChange={(e) => setQuantityKg(e.target.value)}
|
||||
className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm"
|
||||
required
|
||||
min="1"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bg-gray-50 px-6 py-4 rounded-b-xl flex justify-end space-x-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="bg-gray-200 text-gray-700 px-4 py-2 rounded-lg hover:bg-gray-300 font-medium"
|
||||
>
|
||||
Batal
|
||||
</button>
|
||||
<button
|
||||
type="submit"
|
||||
className="bg-red-600 text-white px-4 py-2 rounded-lg hover:bg-red-700 font-medium shadow-sm"
|
||||
>
|
||||
Simpan Jadwal
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default FeedScheduleFormModal;
|
||||
Reference in new issue
Block a user