133 lines
4.5 KiB
TypeScript
133 lines
4.5 KiB
TypeScript
import React, { useState, useMemo } from 'react';
|
|
import { useAppContext } from '../context/AppContext.tsx';
|
|
import { CalendarCheckIcon, CalendarPlusIcon } from './icons/Icons.tsx';
|
|
import ScheduleOverview from './scheduling/ScheduleOverview.tsx';
|
|
import ConsumptionPatternChart from './scheduling/ConsumptionPatternChart.tsx';
|
|
import InfluencingFactors from './scheduling/InfluencingFactors.tsx';
|
|
import CalendarView from './shared/CalendarView.tsx';
|
|
import DailyEventsList from './scheduling/DailyEventsList.tsx';
|
|
import FeedScheduleFormModal from './scheduling/FeedScheduleFormModal.tsx';
|
|
import { FeedingEvent } from '../types.ts';
|
|
import AiInsightCard from './shared/AiInsightCard.tsx';
|
|
|
|
const FeedSchedulingPage: React.FC = () => {
|
|
const {
|
|
feedSchedule,
|
|
feedingEvents,
|
|
consumptionPattern,
|
|
scheduleFactors,
|
|
onAddFeedingEvent,
|
|
onUpdateFeedingEvent,
|
|
apiMode,
|
|
} = useAppContext();
|
|
|
|
const [selectedDate, setSelectedDate] = useState<Date>(new Date());
|
|
const [isModalOpen, setIsModalOpen] = useState(false);
|
|
const [editingEvent, setEditingEvent] = useState<FeedingEvent | null>(null);
|
|
|
|
const calendarEvents = useMemo(
|
|
() =>
|
|
feedingEvents.map((event) => ({
|
|
id: event.id,
|
|
date: event.time,
|
|
text: event.type,
|
|
color: event.type === 'AI Recommended' ? 'bg-purple-500' : 'bg-blue-500',
|
|
})),
|
|
[feedingEvents]
|
|
);
|
|
|
|
const handleAddEvent = () => {
|
|
setEditingEvent(null);
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
const handleEditEvent = (event: FeedingEvent) => {
|
|
setEditingEvent(event);
|
|
setIsModalOpen(true);
|
|
};
|
|
|
|
const handleSaveEvent = (eventData: Omit<FeedingEvent, 'id' | 'status'>, id?: string) => {
|
|
if (id) {
|
|
// This is a simplified update, a real app would need more logic
|
|
onUpdateFeedingEvent({ ...eventData, id, status: 'upcoming' });
|
|
} else {
|
|
onAddFeedingEvent(eventData);
|
|
}
|
|
setIsModalOpen(false);
|
|
};
|
|
|
|
return (
|
|
<main className="px-4 sm:px-6 lg:px-8 pb-8">
|
|
<div className="flex items-center mb-6">
|
|
<CalendarCheckIcon className="text-3xl text-red-600 mr-4" />
|
|
<div>
|
|
<h1 className="text-3xl font-bold text-gray-800">Dashboard Penjadwalan Pakan</h1>
|
|
<p className="mt-1 text-gray-600">
|
|
Optimalkan jadwal pemberian pakan berdasarkan data real-time dan prediksi AI.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="space-y-8">
|
|
{apiMode === 'DEMO' && (
|
|
<AiInsightCard title="AI Insight: Penyesuaian Dinamis">
|
|
<p>
|
|
Rekomendasi jadwal dimundurkan untuk menghindari stres panas akibat suhu tinggi pada
|
|
siang hari. Ini diprediksi dapat meningkatkan konsumsi pakan sebesar{' '}
|
|
<strong>3-5%</strong>.
|
|
</p>
|
|
</AiInsightCard>
|
|
)}
|
|
<ScheduleOverview recommendation={feedSchedule} />
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-5 gap-8">
|
|
<div className="lg:col-span-3 bg-white p-4 sm:p-6 rounded-xl shadow-sm">
|
|
<div className="flex justify-between items-center mb-4">
|
|
<h2 className="text-xl font-bold">Kalender Jadwal Pakan</h2>
|
|
<button
|
|
onClick={handleAddEvent}
|
|
className="flex items-center space-x-2 bg-red-50 text-red-600 px-3 py-2 rounded-lg hover:bg-red-100 transition duration-300 shadow-sm font-semibold text-sm"
|
|
>
|
|
<CalendarPlusIcon />
|
|
<span>Jadwal Baru</span>
|
|
</button>
|
|
</div>
|
|
<CalendarView
|
|
events={calendarEvents}
|
|
onDateSelect={(date) => setSelectedDate(date)}
|
|
selectedDate={selectedDate}
|
|
/>
|
|
</div>
|
|
<div className="lg:col-span-2 space-y-8">
|
|
<DailyEventsList
|
|
selectedDate={selectedDate}
|
|
events={feedingEvents}
|
|
onEditEvent={handleEditEvent}
|
|
/>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="grid grid-cols-1 lg:grid-cols-3 gap-8">
|
|
<div className="lg:col-span-2">
|
|
<ConsumptionPatternChart data={consumptionPattern} />
|
|
</div>
|
|
<div>
|
|
<InfluencingFactors factors={scheduleFactors} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{isModalOpen && (
|
|
<FeedScheduleFormModal
|
|
isOpen={isModalOpen}
|
|
onClose={() => setIsModalOpen(false)}
|
|
onSave={handleSaveEvent}
|
|
eventToEdit={editingEvent}
|
|
initialDate={selectedDate}
|
|
/>
|
|
)}
|
|
</main>
|
|
);
|
|
};
|
|
|
|
export default FeedSchedulingPage;
|