update sync data from site dashboard and testing closing cycles

This commit is contained in:
Alberto-Audrix committed 2026-09-15 16:52:41 +07:00
1 parent 36639d8c38
commit f49e72592c
42 files changed
+1966 -688

No files matched your search

@@ -51,9 +51,7 @@ const DataManagementPage: React.FC<{ onSettings: () => void }> = ({ onSettings }
const [manualRows, setManualRows] = useState<ManualInput[]>([]);
const [insights, setInsights] = useState<AIInsight[]>([]);
const [loading, setLoading] = useState(false);
const [syncing, setSyncing] = useState(false);
const [error, setError] = useState<string | null>(null);
const [notice, setNotice] = useState<string | null>(null);
const [searchDay, setSearchDay] = useState<string>('');
const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('asc');
@@ -91,22 +89,6 @@ const DataManagementPage: React.FC<{ onSettings: () => void }> = ({ onSettings }
void loadData(selectedCycle.id);
}, [selectedCycle, loadData]);
const handleSync = useCallback(async () => {
if (!selectedCycle) return;
setSyncing(true);
setError(null);
setNotice(null);
try {
await api.countings.sync({ cycle_id: selectedCycle.id });
setNotice('Sinkron chicken counting edge berhasil.');
await loadData(selectedCycle.id);
} catch (err) {
setError(errorMessage(err));
} finally {
setSyncing(false);
}
}, [selectedCycle, loadData]);
// Build daily rows through calendar today (not publish-gated current_day).
const rows = useMemo<Row[]>(() => {
if (!selectedCycle) return [];
@@ -281,26 +263,6 @@ const DataManagementPage: React.FC<{ onSettings: () => void }> = ({ onSettings }
title="Hitung Ayam"
icon={<i className="fa-solid fa-calculator" />}
subtitle={`Lihat data deplesi harian untuk siklus produksi · ${selectedSite?.site_name ?? ''} · ${selectedKandang?.kandang_name ?? ''} · Siklus ${formatDateRange(selectedCycle.start_date, selectedCycle.end_date)}`}
actions={
<button
type="button"
onClick={handleSync}
disabled={syncing || isClosedCycle}
className="bg-red-600 text-white px-4 py-2 rounded-lg text-sm font-semibold disabled:opacity-60 hover:bg-red-700 transition-colors"
>
{syncing ? (
<>
<i className="fa-solid fa-spinner fa-spin mr-2"></i>
Sync...
</>
) : (
<>
<i className="fa-solid fa-arrows-rotate mr-2"></i>
Sync
</>
)}
</button>
}
/>
{countingAccuracyWarning && (
@@ -351,11 +313,6 @@ const DataManagementPage: React.FC<{ onSettings: () => void }> = ({ onSettings }
<Banner kind="error">{error}</Banner>
</div>
)}
{notice && (
<div className="mb-4">
<Banner kind="success">{notice}</Banner>
</div>
)}
{/* Statistics Cards */}
<div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-5 gap-4 mb-6">
@@ -1,4 +1,4 @@
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
import { render, screen, within } from '@testing-library/react';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import DataManagementPage from '../DataManagementPage.tsx';
import { api } from '../../../services/apiClient.ts';
@@ -12,7 +12,6 @@ vi.mock('../../../services/apiClient.ts', () => ({
list: vi.fn().mockResolvedValue([]),
create: vi.fn(),
update: vi.fn(),
sync: vi.fn().mockResolvedValue({ upserted: 2, dates: ['2026-09-02', '2026-09-03'] }),
},
manualInputs: {
list: vi.fn().mockResolvedValue([
@@ -78,10 +77,6 @@ describe('DataManagementPage', () => {
beforeEach(() => {
vi.mocked(api.kpis.list).mockResolvedValue([]);
vi.mocked(api.countings.list).mockResolvedValue([]);
vi.mocked(api.countings.sync).mockResolvedValue({
upserted: 2,
dates: ['2026-09-02', '2026-09-03'],
});
});
it('renders the Hitung Ayam dashboard view with stats and daily rows', async () => {
@@ -114,17 +109,6 @@ describe('DataManagementPage', () => {
expect(screen.getAllByText('0.0%').length).toBeGreaterThan(0);
});
it('calls chicken counting sync when Sync is clicked', async () => {
render(<DataManagementPage onSettings={() => undefined} />);
await screen.findByRole('heading', { name: 'Hitung Ayam' });
fireEvent.click(screen.getByRole('button', { name: /Sync/i }));
await waitFor(() => {
expect(api.countings.sync).toHaveBeenCalledWith({ cycle_id: 1 });
});
});
it('shows under-count IoT accuracy warning for the latest IoT day', async () => {
vi.mocked(api.kpis.list).mockResolvedValue([
{