remove wagtail and admin website, remove edit option, from hitung ayam, add create flock to settings
This commit is contained in:
1 parent
74dd3faf60
commit
30a736641f
39 files changed
+634
-819
No files matched your search
+78
-15
@@ -1,6 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { api, errorMessage } from '../services/apiClient.ts';
|
||||
import type { CycleStatus } from '../types/api.ts';
|
||||
import { useAuth } from '../context/AuthContext.tsx';
|
||||
import { useFarm } from '../context/FarmContext.tsx';
|
||||
import { Banner, PageHeader } from './ui/Feedback.tsx';
|
||||
@@ -14,6 +13,7 @@ const SettingsPage: React.FC = () => {
|
||||
const {
|
||||
sites,
|
||||
kandangs,
|
||||
flocks,
|
||||
cycles,
|
||||
selectedSiteId,
|
||||
selectedKandangId,
|
||||
@@ -27,11 +27,11 @@ const SettingsPage: React.FC = () => {
|
||||
const [saving, setSaving] = useState(false);
|
||||
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(45);
|
||||
const [cycleStatus, setCycleStatus] = useState<CycleStatus>('active');
|
||||
const [chickInWeight, setChickInWeight] = useState(35);
|
||||
|
||||
const flash = (msg: string) => {
|
||||
setNotice(msg);
|
||||
@@ -55,7 +55,10 @@ const SettingsPage: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader title="Pengaturan" subtitle="Site, kandang, dan siklus produksi" />
|
||||
<PageHeader
|
||||
title="Pengaturan"
|
||||
subtitle="Site, kandang, flock (IoT), dan siklus produksi"
|
||||
/>
|
||||
{error && (
|
||||
<div className="mb-4">
|
||||
<Banner kind="error">{error}</Banner>
|
||||
@@ -66,7 +69,7 @@ const SettingsPage: React.FC = () => {
|
||||
<Banner kind="success">{notice}</Banner>
|
||||
</div>
|
||||
)}
|
||||
<div className="grid grid-cols-1 xl:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 xl:grid-cols-2 2xl:grid-cols-4 gap-6">
|
||||
<section className="bg-white rounded-xl shadow-sm p-5">
|
||||
<h2 className="font-semibold text-gray-800 mb-3">Sites</h2>
|
||||
{isSuperAdmin ? (
|
||||
@@ -188,6 +191,69 @@ const SettingsPage: React.FC = () => {
|
||||
))}
|
||||
</ul>
|
||||
</section>
|
||||
<section className="bg-white rounded-xl shadow-sm p-5">
|
||||
<h2 className="font-semibold text-gray-800 mb-3">Flock</h2>
|
||||
<p className="mb-3 text-xs text-gray-500">
|
||||
Flock tetap untuk kandang ini (dipakai Panel IoT). Tidak terikat ke siklus.
|
||||
</p>
|
||||
{isSuperAdmin ? (
|
||||
<form
|
||||
className="space-y-2 mb-4"
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
if (!selectedKandangId) return;
|
||||
void wrap(async () => {
|
||||
const created = await api.flocks.create({
|
||||
flock_name: flockName,
|
||||
kandang: selectedKandangId,
|
||||
});
|
||||
setFlockName('');
|
||||
flash(`Flock ${created.flock_name} dibuat.`);
|
||||
});
|
||||
}}
|
||||
>
|
||||
<input
|
||||
className={inputClass}
|
||||
placeholder="Nama flock"
|
||||
value={flockName}
|
||||
onChange={(e) => setFlockName(e.target.value)}
|
||||
required
|
||||
/>
|
||||
<button
|
||||
className="bg-red-600 text-white px-3 py-2 rounded-lg text-sm font-semibold"
|
||||
disabled={saving || !selectedKandangId}
|
||||
>
|
||||
Tambah flock
|
||||
</button>
|
||||
</form>
|
||||
) : (
|
||||
<p className="mb-4 text-xs text-gray-500">Hanya admin yang dapat membuat flock.</p>
|
||||
)}
|
||||
{!selectedKandangId ? (
|
||||
<p className="text-xs text-gray-500">Pilih kandang terlebih dahulu.</p>
|
||||
) : (
|
||||
<ul className="divide-y">
|
||||
{flocks.map((flock) => (
|
||||
<li key={flock.id} className="py-2 flex items-center justify-between gap-2">
|
||||
<span className="text-sm text-gray-700">{flock.flock_name}</span>
|
||||
{isSuperAdmin && (
|
||||
<button
|
||||
className="text-xs text-red-500 hover:underline"
|
||||
onClick={() =>
|
||||
void wrap(async () => {
|
||||
await api.flocks.remove(flock.id);
|
||||
flash('Flock dihapus.');
|
||||
})
|
||||
}
|
||||
>
|
||||
Hapus
|
||||
</button>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
)}
|
||||
</section>
|
||||
<section className="bg-white rounded-xl shadow-sm p-5">
|
||||
<h2 className="font-semibold text-gray-800 mb-3">Siklus</h2>
|
||||
<form
|
||||
@@ -204,7 +270,6 @@ const SettingsPage: React.FC = () => {
|
||||
end_date: endDate,
|
||||
chick_in_weight: chickInWeight,
|
||||
doc_in_count: docInCount,
|
||||
status: cycleStatus,
|
||||
});
|
||||
flash('Siklus dibuat.');
|
||||
});
|
||||
@@ -247,18 +312,16 @@ const SettingsPage: React.FC = () => {
|
||||
<input
|
||||
type="number"
|
||||
className={`${inputClass} mt-1`}
|
||||
min={35}
|
||||
max={51}
|
||||
value={chickInWeight}
|
||||
onChange={(e) => setChickInWeight(Number(e.target.value))}
|
||||
onChange={(e) => {
|
||||
const value = Number(e.target.value);
|
||||
if (Number.isNaN(value)) return;
|
||||
setChickInWeight(Math.min(51, Math.max(35, value)));
|
||||
}}
|
||||
/>
|
||||
</label>
|
||||
<select
|
||||
className={inputClass}
|
||||
value={cycleStatus}
|
||||
onChange={(e) => setCycleStatus(e.target.value as CycleStatus)}
|
||||
>
|
||||
<option value="active">active</option>
|
||||
<option value="closed">closed</option>
|
||||
</select>
|
||||
<button
|
||||
className="bg-red-600 text-white px-3 py-2 rounded-lg text-sm font-semibold"
|
||||
disabled={saving}
|
||||
|
||||
Reference in new issue
Block a user