fix initial balance logic and add edit for cycle data

This commit is contained in:
Alberto-Audrix committed 2026-09-01 14:59:47 +07:00
1 parent 7a9d600aa6
commit 697feb206c
15 files changed
+402 -93

No files matched your search

+106 -33
View File
@@ -2,12 +2,27 @@ import React, { useState } from 'react';
import { api, errorMessage } from '../services/apiClient.ts';
import { useAuth } from '../context/AuthContext.tsx';
import { useFarm } from '../context/FarmContext.tsx';
import type { Cycle } from '../types/api.ts';
import { Banner, PageHeader } from './ui/Feedback.tsx';
import { addDaysIso, formatDateId, inclusiveDayCount, todayIso } from '../utils/format.ts';
import { addDaysIso, formatDateId, inclusiveDayCount, resolveCycleStatus, todayIso } from '../utils/format.ts';
const inputClass =
'border border-gray-300 rounded-md px-3 py-2 text-sm w-full focus:ring-red-500 focus:border-red-500';
const defaultCycleForm = () => ({
startDate: todayIso(),
endDate: addDaysIso(todayIso(), 34),
docInCount: 20000,
chickInWeight: 35,
});
const cycleToForm = (cycle: Cycle) => ({
startDate: cycle.start_date,
endDate: cycle.end_date,
docInCount: cycle.doc_in_count,
chickInWeight: cycle.chick_in_weight,
});
const SettingsPage: React.FC = () => {
const { user } = useAuth();
const {
@@ -28,10 +43,39 @@ const SettingsPage: React.FC = () => {
const [siteName, setSiteName] = useState('');
const [kandangName, setKandangName] = useState('');
const [flockName, setFlockName] = useState('');
const [startDate, setStartDate] = useState(todayIso());
const [endDate, setEndDate] = useState(() => addDaysIso(todayIso(), 34));
const [docInCount, setDocInCount] = useState(20000);
const [chickInWeight, setChickInWeight] = useState(35);
const [editingCycleId, setEditingCycleId] = useState<number | null>(null);
const [startDate, setStartDate] = useState(defaultCycleForm().startDate);
const [endDate, setEndDate] = useState(defaultCycleForm().endDate);
const [docInCount, setDocInCount] = useState(defaultCycleForm().docInCount);
const [chickInWeight, setChickInWeight] = useState(defaultCycleForm().chickInWeight);
const resetCycleForm = () => {
const defaults = defaultCycleForm();
setEditingCycleId(null);
setStartDate(defaults.startDate);
setEndDate(defaults.endDate);
setDocInCount(defaults.docInCount);
setChickInWeight(defaults.chickInWeight);
};
const beginCycleEdit = (cycle: Cycle) => {
const form = cycleToForm(cycle);
setEditingCycleId(cycle.id);
setStartDate(form.startDate);
setEndDate(form.endDate);
setDocInCount(form.docInCount);
setChickInWeight(form.chickInWeight);
setSelectedCycleId(cycle.id);
};
const buildCyclePayload = () => ({
kandang: selectedKandangId!,
total_days: inclusiveDayCount(startDate, endDate),
start_date: startDate,
end_date: endDate,
chick_in_weight: chickInWeight,
doc_in_count: docInCount,
});
const flash = (msg: string) => {
setNotice(msg);
@@ -262,19 +306,24 @@ const SettingsPage: React.FC = () => {
e.preventDefault();
if (!selectedKandangId) return;
void wrap(async () => {
await api.cycles.create({
kandang: selectedKandangId,
total_days: inclusiveDayCount(startDate, endDate),
current_day: 1,
start_date: startDate,
end_date: endDate,
chick_in_weight: chickInWeight,
doc_in_count: docInCount,
});
flash('Siklus dibuat.');
const payload = buildCyclePayload();
if (editingCycleId) {
await api.cycles.update(editingCycleId, payload);
flash('Siklus diperbarui.');
resetCycleForm();
} else {
await api.cycles.create({ ...payload, current_day: 1 });
flash('Siklus dibuat.');
resetCycleForm();
}
});
}}
>
{editingCycleId && (
<p className="text-xs font-medium text-blue-700 bg-blue-50 border border-blue-100 rounded-md px-3 py-2">
Mengedit siklus {formatDateId(startDate)} – {formatDateId(endDate)}
</p>
)}
<label className="block text-sm">
Mulai
<input
@@ -322,12 +371,24 @@ const SettingsPage: React.FC = () => {
}}
/>
</label>
<button
className="bg-red-600 text-white px-3 py-2 rounded-lg text-sm font-semibold"
disabled={saving}
>
Tambah siklus
</button>
<div className="flex gap-2">
<button
className="bg-red-600 text-white px-3 py-2 rounded-lg text-sm font-semibold"
disabled={saving}
>
{editingCycleId ? 'Simpan perubahan' : 'Tambah siklus'}
</button>
{editingCycleId && (
<button
type="button"
className="border border-gray-300 text-gray-700 px-3 py-2 rounded-lg text-sm font-semibold hover:bg-gray-50"
disabled={saving}
onClick={resetCycleForm}
>
Batal
</button>
)}
</div>
</form>
<ul className="divide-y">
{cycles.map((cycle) => (
@@ -335,19 +396,31 @@ const SettingsPage: React.FC = () => {
<div className="flex justify-between gap-2">
<button className="text-left" onClick={() => setSelectedCycleId(cycle.id)}>
{formatDateId(cycle.start_date)} – {formatDateId(cycle.end_date)}
<span className="block text-xs text-gray-400">{cycle.status}</span>
</button>
<button
className="text-xs text-red-500 hover:underline"
onClick={() =>
void wrap(async () => {
await api.cycles.remove(cycle.id);
flash('Siklus dihapus.');
})
}
>
Hapus
<span className="block text-xs text-gray-400">
{resolveCycleStatus(cycle) === 'active' ? 'Aktif' : 'Selesai'} ·{' '}
{cycle.doc_in_count} ekor · {cycle.chick_in_weight} g
</span>
</button>
<div className="flex flex-col items-end gap-1">
<button
className="text-xs text-blue-600 hover:underline"
onClick={() => beginCycleEdit(cycle)}
>
Ubah
</button>
<button
className="text-xs text-red-500 hover:underline"
onClick={() =>
void wrap(async () => {
if (editingCycleId === cycle.id) resetCycleForm();
await api.cycles.remove(cycle.id);
flash('Siklus dihapus.');
})
}
>
Hapus
</button>
</div>
</div>
</li>
))}