import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { api, errorMessage } from '../../services/apiClient.ts'; import type { Cycle, InitialBalanceResult } from '../../types/api.ts'; import { formatNumber } from '../../utils/format.ts'; import InitialBalanceComparison from './InitialBalanceComparison.tsx'; interface InitialBalanceCardProps { cycle: Cycle; onSaved: (result: InitialBalanceResult) => void; } const InitialBalanceCard: React.FC = ({ cycle, onSaved }) => { const savedBalanceDate = cycle.feed_initial_balance_date ?? cycle.start_date; const [balanceDate, setBalanceDate] = useState(savedBalanceDate); const [manualEntry, setManualEntry] = useState( cycle.feed_initial_balance > 0 ? String(cycle.feed_initial_balance) : '' ); const [saving, setSaving] = useState(false); const [comparing, setComparing] = useState(false); const [error, setError] = useState(null); const [comparison, setComparison] = useState(null); useEffect(() => { setBalanceDate(cycle.feed_initial_balance_date ?? cycle.start_date); setManualEntry(cycle.feed_initial_balance > 0 ? String(cycle.feed_initial_balance) : ''); setComparison(null); setError(null); }, [cycle.id, cycle.feed_initial_balance, cycle.feed_initial_balance_date, cycle.start_date]); const manualValue = manualEntry === '' ? null : Number(manualEntry); const canSave = useMemo( () => balanceDate !== '' && manualEntry !== '' && Number(manualEntry) >= 0 && !saving, [balanceDate, manualEntry, saving] ); const loadComparison = useCallback(async () => { if (balanceDate === '' || manualValue == null || Number.isNaN(manualValue) || manualValue < 0) { setComparison(null); return; } setComparing(true); try { const compared = await api.cycles.initialBalanceCompare(cycle.id, { date: balanceDate, manual: manualValue, }); setComparison(compared); } catch (err) { setComparison(null); setError(errorMessage(err)); } finally { setComparing(false); } }, [balanceDate, cycle.id, manualValue]); useEffect(() => { if (manualValue == null || manualValue < 0) { setComparison(null); return; } void loadComparison(); }, [loadComparison, manualValue]); const handleSave = async () => { if (!canSave) return; setSaving(true); setError(null); try { const saved = await api.cycles.initialBalance(cycle.id, { date: balanceDate, feed_in_manual: Number(manualEntry), }); setComparison(saved); onSaved(saved); } catch (err) { setError(errorMessage(err)); } finally { setSaving(false); } }; return (

Saldo Awal

Masukkan saldo awal karung pakan pada tanggal tertentu, lalu bandingkan dengan deteksi IoT.

setBalanceDate(event.target.value)} className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-sm" />
setManualEntry(event.target.value)} placeholder="Contoh: 120" className="w-full px-3 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-blue-500 focus:border-blue-500 text-sm" />
{error && (

{error}

)}
{cycle.feed_initial_balance > 0 && comparison == null && (

Saldo awal tersimpan:{' '} {formatNumber(cycle.feed_initial_balance)} karung

)}
{comparison && }
); }; export default InitialBalanceCard;