Files
dashboard/components/FeedSchedulingPage.tsx
T
Alberto-Audrix 32a36cceff
CI / lint-and-test (push) Canceled after 0s
first commit
2026-07-28 08:55:05 +07:00

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;