import React, { useMemo, useRef, useState } from 'react'; import type { Karung, ManualInput } from '../../types/api.ts'; import { formatNumber } from '../../utils/format.ts'; type SortOrder = 'asc' | 'desc'; interface FeedDailySummaryTableProps { rows: Karung[]; manualRows: ManualInput[]; cycleStartDate: string; currentDay: number; } const accuracyOf = (manual: number, iot: number): string => { if (manual === 0 && iot === 0) return '100.0%'; if (manual === 0 || iot === 0) return '0.0%'; const smaller = Math.min(manual, iot); const larger = Math.max(manual, iot); return `${((smaller / larger) * 100).toFixed(1)}%`; }; const accuracyClass = (manual: number, iot: number): string => { if (manual === 0 && iot === 0) return 'text-green-600'; if (manual === 0 || iot === 0) return 'text-red-600'; const percentage = (Math.min(manual, iot) / Math.max(manual, iot)) * 100; if (percentage >= 95) return 'text-green-600'; if (percentage >= 80) return 'text-yellow-600'; return 'text-red-600'; }; const FeedDailySummaryTable: React.FC = ({ rows, manualRows, cycleStartDate, currentDay, }) => { const [sortOrder, setSortOrder] = useState('desc'); const masukRef = useRef(null); const tuangRef = useRef(null); const keluarRef = useRef(null); const scrollToSection = (ref: React.RefObject) => { ref.current?.scrollIntoView({ behavior: 'smooth', block: 'start' }); }; const aggregatedData = useMemo(() => { const cycleStart = new Date(`${cycleStartDate}T00:00:00`); const iotByDate = new Map(); for (const row of rows) iotByDate.set(row.date, row); const manualByDate = new Map(); for (const row of manualRows) manualByDate.set(row.date, row); const result: { day: number; date: Date; dateFormatted: string; iot: Karung | null; manual: ManualInput | null; }[] = []; for (let d = 0; d <= currentDay; d++) { const date = new Date(cycleStart); date.setDate(cycleStart.getDate() + d); const key = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String( date.getDate() ).padStart(2, '0')}`; result.push({ day: d, date, dateFormatted: date.toLocaleDateString('id-ID', { day: 'numeric', month: 'short', year: 'numeric', }), iot: iotByDate.get(key) ?? null, manual: manualByDate.get(key) ?? null, }); } return result; }, [rows, manualRows, cycleStartDate, currentDay]); const sortedData = useMemo(() => { const sorted = [...aggregatedData].sort((a, b) => a.day - b.day); return sortOrder === 'desc' ? sorted.reverse() : sorted; }, [aggregatedData, sortOrder]); if (aggregatedData.length === 0 || (rows.length === 0 && manualRows.length === 0)) { return (

Rincian Harian Karung IOT

Tidak ada data

Belum ada data karung IOT untuk siklus ini. Sinkronkan lewat tombol Sync hari ini.

); } const renderBox = ( title: string, emoji: string, headerColor: string, manualGetter: (row: ManualInput) => number, iotGetter: (row: Karung) => number, totalGetter: (row: Karung) => number, ref: React.RefObject ) => (
{/* Header */}
{emoji} {title}
{/* Table container with scroll */}
{sortedData.map((summary) => { const manualValue = summary.manual ? manualGetter(summary.manual) : 0; const iotValue = summary.iot ? iotGetter(summary.iot) : 0; const total = summary.iot ? totalGetter(summary.iot) : null; return ( ); })}
Hari Tanggal Manual IOT Akurasi Total
{summary.day} {summary.dateFormatted} {formatNumber(manualValue)} {formatNumber(iotValue)} {accuracyOf(manualValue, iotValue)} {total == null ? '-' : formatNumber(total)}
); return (
{/* Header */}

Rincian Harian Karung IOT

{/* Sticky Quick Navigation Bar (Excel-style freeze) */}
{/* Three separate boxes */} {renderBox( 'KARUNG MASUK', '🟢', '#86efac', (row) => row.feed_in_manual, (row) => row.in_today, (row) => row.in_total, masukRef )} {renderBox( 'KARUNG TUANG', '🟠', '#fdba74', (row) => row.feed_use_manual, (row) => row.feed_use_today, (row) => row.feed_use_total, tuangRef )} {renderBox( 'KARUNG KELUAR', '🔴', '#fca5a5', (row) => row.feed_out_manual, (row) => row.out_today, (row) => row.out_total, keluarRef )}
); }; export default FeedDailySummaryTable;