/* ============================================================ TernakPro — versi tanpa build (langsung jalan di browser) React, ReactDOM, dan Babel dimuat dari CDN pada index.html. Helper API & hook usePersistentState digabung di bagian atas file ini. ============================================================ */ const { useState, useEffect, useCallback, useRef } = React; /* ============================================================ LAPISAN DATA — helper API + hook penyimpanan (digabung di sini agar hanya ada SATU script Babel, mencegah deklarasi ganda). ============================================================ */ const API_BASE = "api/"; // lokasi backend PHP, relatif terhadap halaman ini async function apiList(table) { const res = await fetch(`${API_BASE}?table=${encodeURIComponent(table)}`); if (!res.ok) throw new Error(`GET ${table} gagal (${res.status})`); return res.json(); } async function apiBulkSave(table, rows) { const res = await fetch(`${API_BASE}?table=${encodeURIComponent(table)}`, { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify(rows), }); if (!res.ok) throw new Error(`PUT ${table} gagal (${res.status})`); return res.json(); } // Pengganti useState yang otomatis tersimpan ke MySQL: // 1) mount -> ambil data server; jika kosong -> seed dari data bawaan. // 2) setiap berubah -> kirim seluruh array ke server (debounce 700ms). function usePersistentState(table, initial) { const [data, setData] = useState(initial); const [loaded, setLoaded] = useState(false); const skipNextSave = useRef(true); const timer = useRef(null); useEffect(() => { let alive = true; (async () => { try { const rows = await apiList(table); if (!alive) return; if (Array.isArray(rows) && rows.length > 0) { skipNextSave.current = true; setData(rows); } else { await apiBulkSave(table, initial); // seed run pertama skipNextSave.current = true; setData(initial); } } catch (e) { console.error(`Gagal memuat '${table}':`, e.message); // offline: pakai initial } finally { if (alive) setLoaded(true); } })(); return () => { alive = false; }; }, []); useEffect(() => { if (skipNextSave.current) { skipNextSave.current = false; return; } if (timer.current) clearTimeout(timer.current); timer.current = setTimeout(() => { apiBulkSave(table, data).catch((e) => console.error(`Gagal menyimpan '${table}':`, e.message)); }, 700); return () => { if (timer.current) clearTimeout(timer.current); }; }, [data]); return [data, setData, loaded]; } /* ================================================================ ERROR BOUNDARY — Cegah app crash total karena 1 komponen error ================================================================ */ class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false, error: null }; } static getDerivedStateFromError(error) { return { hasError: true, error }; } componentDidCatch(error, info) { console.error("TernakPro Error:", error, info); } render() { if (this.state.hasError) { return (
⚠️
Terjadi Error
{String(this.state.error?.message || this.state.error || "Unknown error")}
); } return this.props.children; } } /* ===== WARNA TEMA ===== */ const C = { bg: "#07090e", sidebar: "#0a0c16", card: "#0f1118", border: "#1c1e2b", border2: "#252535", text: "#e2e4f0", muted: "#9097a8", dim: "#555a6a", subtle: "#1a1d28", sapi: "#f5c842", domba: "#a3e635", sell: "#22c55e", buy: "#f59e0b", health: "#ec4899", breed: "#a855f7", expense: "#ef4444", report: "#8b5cf6", info: "#3b82f6", }; /* ================================================================ DATA RAS SAPI — Karakteristik, Asal, Keunggulan ================================================================ */ const RAS_SAPI = { // ── SAPI IMPOR / PERSILANGAN ── "Simental": { asal:"Swiss (Swiss-Simmental)", tipe:"Potong & Perah Dwi Guna", warna:"Kuning-Keemasan dengan bercak putih", bbDewasa:{jantan:"800–1.100 kg",betina:"600–750 kg"}, adg:"0.8–1.5 kg/hari (feedlot intensif)", keunggulan:["Pertumbuhan sangat cepat — ADG tertinggi di antara ras impor","Karkas besar, rendemen 52–58%","Adaptasi baik di dataran tinggi Jawa","Populasi terbesar sapi impor di Indonesia"], kekurangan:["Sensitif panas — perlu ventilasi kandang baik","Kebutuhan pakan tinggi — FCR 6–7","Harga bibit mahal"], harga:"Rp 20–45 juta/ekor bakalan (2025)", popularitas:"⭐⭐⭐⭐⭐ — Paling populer feedlot Indonesia", catatan:"SimPO (Simental × PO) = ras persilangan paling banyak di Jawa. Adaptasi lebih baik dari Simental murni", }, "Limousin": { asal:"Prancis (Limousin)", tipe:"Sapi Potong Premium", warna:"Merah-Coklat Keemasan", bbDewasa:{jantan:"900–1.100 kg",betina:"600–700 kg"}, adg:"0.9–1.4 kg/hari", keunggulan:["Kualitas daging premium — lemak marbling rendah","Rendemen karkas tinggi 55–60%","Masa hidup panjang","Frame besar — bobot potong ideal 500–600 kg"], kekurangan:["Pertumbuhan sedikit lebih lambat dari Simental","Kurang toleran suhu panas ekstrem","Harga bibit mahal"], harga:"Rp 22–50 juta/ekor (2025)", popularitas:"⭐⭐⭐⭐⭐ — Runner-up setelah Simental", catatan:"LimPO (Limousin × PO) populer di Jabar & Jateng. Daging Limousin diekspor ke Malaysia & Timur Tengah", }, "Angus": { asal:"Skotlandia (Aberdeen Angus)", tipe:"Sapi Potong Premium Dunia", warna:"Hitam pekat (Black Angus) atau Merah (Red Angus)", bbDewasa:{jantan:"750–1.000 kg",betina:"500–600 kg"}, adg:"0.8–1.2 kg/hari", keunggulan:["Marbling (lemak intramuskular) terbaik dunia — steak grade A","Temperamen jinak","Fertilitas betina tinggi","Tahan berbagai iklim"], kekurangan:["Kurang populer di Indonesia — lebih banyak di Australia/NZ","Harga bibit sangat mahal (import)","Adaptasi tropis perlu waktu"], harga:"Rp 35–80 juta/ekor impor (2025)", popularitas:"⭐⭐⭐ — Premium, belum umum peternak rakyat", catatan:"Wagyu × Angus = Japanese premium beef. Dipakai Santori & GGL untuk produk beef premium Indonesia", }, "Brahman": { asal:"India → Amerika Serikat (Bos indicus)", tipe:"Sapi Potong Tropis", warna:"Abu-Abu atau Merah, punuk besar", bbDewasa:{jantan:"700–900 kg",betina:"450–550 kg"}, adg:"0.6–1.1 kg/hari", keunggulan:["Tahan panas & caplak — ideal daerah tropis","Efisien pakan kualitas rendah","Daya tahan parasit sangat baik","Banyak dipakai di peternakan ekstensif Sumatra & Kalimantan"], kekurangan:["Kualitas daging di bawah Simental/Limousin","ADG lebih rendah di kandang intensif"], harga:"Rp 15–30 juta/ekor (2025)", popularitas:"⭐⭐⭐⭐ — Sangat populer dataran rendah tropis", catatan:"BrahmanCross (Brahman × sapi lokal) banyak diternakkan di Sumatra, Kalimantan, Sulawesi", }, "Wagyu (Kobe)": { asal:"Jepang (Wa = Jepang, Gyu = Sapi)", tipe:"Sapi Beef Premium Tertinggi Dunia", warna:"Hitam (Japanese Black — paling umum)", bbDewasa:{jantan:"700–900 kg",betina:"450–550 kg"}, adg:"0.5–0.8 kg/hari (sengaja lambat untuk marbling)", keunggulan:["Marbling lemak intramuskular tertinggi — BMS (Beef Marbling Score) 5–12","Harga jual daging Rp 500.000–3.000.000/kg","Program feedlot khusus 300–600 hari","Pasar ekspor sangat premium"], kekurangan:["Sangat mahal — bibit F1 Rp 50–150 juta","Butuh pakan khusus (jagung + jerami jepang)","Masa pemeliharaan 2–3 tahun","Pasar lokal masih kecil"], harga:"Rp 50–150 juta/ekor F1 Wagyu (2025)", popularitas:"⭐⭐ — Niche premium, bukan untuk peternak rakyat", catatan:"Santori (Japfa) & beberapa farm premium sudah mulai Wagyu di Indonesia. Potensial untuk HORECA hotel bintang 5", }, // ── SAPI LOKAL INDONESIA ── "Sapi Bali": { asal:"Bali, Indonesia (Bos sondaicus/javanicus)", tipe:"Sapi Potong Lokal Unggul", warna:"Merah bata (betina) / Hitam (jantan dewasa), ada garis hitam di punggung", bbDewasa:{jantan:"300–450 kg",betina:"200–300 kg"}, adg:"0.3–0.6 kg/hari", keunggulan:["Adaptasi sangat baik di semua wilayah Indonesia","Tahan penyakit & parasit lokal","Fertilitas tinggi — beranak tiap 12–14 bulan","Kualitas daging baik — serat halus, rendemen 52–56%","Pakan hijauan lokal cukup tanpa konsentrat mahal"], kekurangan:["Bobot kecil — tidak cocok feedlot intensif","Sensitif Penyakit Jembrana (endemik Bali)","Pertumbuhan lambat vs sapi impor"], harga:"Rp 8–18 juta/ekor (2025)", popularitas:"⭐⭐⭐⭐⭐ — Populasi terbesar sapi lokal Indonesia", catatan:"Tersebar luas di Bali, NTB, NTT, Sulawesi. Ekspor hidup ke Malaysia, Brunei. Sapi nasional yang dilindungi pemerintah", }, "Sapi Madura": { asal:"Pulau Madura, Jawa Timur (Bos indicus × Bos javanicus)", tipe:"Sapi Potong & Kerapan", warna:"Merah-Coklat, punuk kecil, tanduk melengkung khas", bbDewasa:{jantan:"250–350 kg",betina:"150–250 kg"}, adg:"0.2–0.5 kg/hari", keunggulan:["Tahan kekeringan & pakan miskin","Nilai budaya tinggi — sapi kerapan (karapan sapi)","Adaptasi sempurna iklim Madura yang panas","Fertilitas cukup baik"], kekurangan:["Bobot sangat kecil — tidak ekonomis untuk feedlot","Pertumbuhan sangat lambat","Populasi menurun karena tergeser sapi impor"], harga:"Rp 6–15 juta/ekor (kerapan berkualitas bisa ratusan juta)", popularitas:"⭐⭐⭐ — Khas Madura, nilainya budaya & ekonomi", catatan:"Sapi Kerapan = simbol budaya Madura. Kontes Karapan Sapi April–Oktober, pemenang senilai Rp 100 juta+. Dilindungi Perda Madura", }, "PO (Peranakan Ongole)": { asal:"India → Jawa (persilangan Ongole × Jawa)", tipe:"Sapi Potong Lokal Dominan Jawa", warna:"Putih keabu-abuan, punuk besar, telinga lebar menggantung", bbDewasa:{jantan:"400–600 kg",betina:"280–400 kg"}, adg:"0.4–0.8 kg/hari", keunggulan:["Populasi terbesar di Jawa Tengah & Jawa Timur","Adaptasi sangat baik iklim Jawa","Sering disilangkan dengan Simental (SimPO) & Limousin (LimPO)","Tenaga kerja — dahulu sebagai sapi pekerja sawah","Tahan panas & penyakit lokal"], kekurangan:["Bobot sedang — kalah jauh dari Simental/Limousin","ADG rendah tanpa konsentrat intensif"], harga:"Rp 10–22 juta/ekor (2025)", popularitas:"⭐⭐⭐⭐⭐ — Paling banyak di Jawa", catatan:"SimPO & LimPO = sapi persilangan paling populer Indonesia. Rumpun PO murni mulai langka — dilindungi sebagai plasma nutfah nasional", }, "Sapi Pasundan": { asal:"Jawa Barat (plasma nutfah asli Jabar)", tipe:"Sapi Potong Lokal Jabar", warna:"Coklat Kehitaman, ada garis hitam di punggung (mirip Bali)", bbDewasa:{jantan:"250–380 kg",betina:"170–270 kg"}, adg:"0.25–0.5 kg/hari", keunggulan:["Adaptasi sempurna iklim pegunungan Jabar","Tahan pakan kasar & miskin","Fertilitas baik","Cita rasa daging lezat — serat halus khas"], kekurangan:["Bobot kecil","Populasi sangat sedikit — hampir punah","Kurang dikenal peternak komersial"], harga:"Rp 8–16 juta/ekor", popularitas:"⭐⭐ — Langka, dilindungi pemerintah Jabar", catatan:"SK Mentan 2014 — Sapi Pasundan ditetapkan sebagai Rumpun Sapi Lokal Indonesia. Konservasi di BPTU HPT Ciamis & Tasikmalaya", }, "Sapi Aceh": { asal:"Aceh (Bos indicus, keturunan sapi India kuno)", tipe:"Sapi Potong & Kerja Lokal Aceh", warna:"Hitam atau Coklat kehitaman, bertubuh kecil-sedang", bbDewasa:{jantan:"200–350 kg",betina:"150–250 kg"}, adg:"0.2–0.5 kg/hari", keunggulan:["Adaptasi sempurna kondisi Aceh — tropis basah","Tahan penyakit lokal","Populasi >400.000 ekor — terbesar di Sumatera","Menjadi sapi kurban unggulan di Aceh & Sumatera"], kekurangan:["Bobot kecil","Pertumbuhan lambat","Kurang tepat untuk feedlot intensif"], harga:"Rp 8–20 juta/ekor", popularitas:"⭐⭐⭐⭐ — Dominan di Aceh", catatan:"SK Mentan 2011 — Rumpun Sapi Aceh ditetapkan sebagai rumpun lokal. Penting untuk ketahanan pangan Aceh & ekspor ke Malaysia", }, "Sapi Pesisir (Sumbar)": { asal:"Sumatera Barat — pantai barat Sumatera", tipe:"Sapi Mini Lokal Sumbar", warna:"Coklat Kehitaman, sangat kecil", bbDewasa:{jantan:"150–200 kg",betina:"100–150 kg"}, adg:"0.15–0.35 kg/hari", keunggulan:["Terkecil di Indonesia — unik dan langka","Adaptasi sempurna padang alang-alang","Tahan panas ekstrem pantai","Niche market — kolektor & konservasi"], kekurangan:["Bobot sangat kecil — tidak ekonomis produksi daging","Pertumbuhan sangat lambat","Populasi sangat terbatas"], harga:"Rp 3–8 juta/ekor", popularitas:"⭐⭐ — Langka, nilai konservasi tinggi", catatan:"Terancam punah — < 5.000 ekor tersisa. SK Mentan 2011. Penelitian di Universitas Andalas Padang", }, "Sapi Jabres (Jateng)": { asal:"Jawa Tengah (Bantarbolang-Brebes)", tipe:"Sapi Potong Lokal Jateng", warna:"Kuning Kecoklatan, ada varian putih", bbDewasa:{jantan:"300–450 kg",betina:"200–300 kg"}, adg:"0.3–0.6 kg/hari", keunggulan:["Adaptasi sangat baik dataran rendah Jateng","Tahan pakan lokal","Fertilitas baik","Lebih besar dari Bali — potensial untuk penggemukan lokal"], kekurangan:["Kurang dikenal di luar Jawa Tengah","Harga lebih murah dari sapi impor"], harga:"Rp 9–18 juta/ekor", popularitas:"⭐⭐⭐ — Lokal Jateng", catatan:"Jabres = Jawa-Brebes. Pengembangan oleh Dinas Peternakan Jateng & Universitas Jenderal Soedirman", }, "FH Afkir": { asal:"Frisien Holland → Belanda (Bos taurus)", tipe:"Sapi Perah Afkir untuk Potong", warna:"Hitam-Putih khas (Holstein)", bbDewasa:{jantan:"700–900 kg",betina:"500–700 kg"}, adg:"0.5–0.9 kg/hari (penggemukan afkir)", keunggulan:["Bobot besar — karkas > sapi lokal","Murah — harga afkir Rp 15–25 juta","Cocok untuk disembelih setelah masa produktif habis","Populasi banyak di sentra susu (Lembang, Batu, Boyolali)"], kekurangan:["Kualitas daging kurang premium — lebih banyak lemak","Perlu adaptasi pakan untuk penggemukan","Bukan sapi potong murni"], harga:"Rp 15–28 juta/ekor afkir", popularitas:"⭐⭐⭐⭐ — Sumber daging sapi perah yang ekonomis", catatan:"FH Afkir banyak dipotong di RPH Jabar & Jateng dari peternakan susu Lembang & Batu. Daging umumnya untuk bakso & olahan", }, "Sapi Perah FH": { asal:"Frisien Holland — Belanda", tipe:"Sapi Perah Unggulan Dunia", warna:"Hitam-Putih Holstein khas", bbDewasa:{jantan:"800–1.000 kg",betina:"550–700 kg"}, produksiSusu:"15–35 liter/hari (puncak laktasi)", keunggulan:["Produksi susu tertinggi","Laktasi 305 hari/tahun","Adaptasi baik di dataran tinggi Jabar (Lembang, Pangalengan)","Harga susu Rp 5.500–7.500/liter dari Greenfields/Indolakto"], kekurangan:["Tidak tahan panas — butuh kandang sejuk","Kebutuhan pakan konsentrat sangat tinggi","Investasi awal besar","Sensitif penyakit (mastitis, ketosis)"], harga:"Rp 25–60 juta/ekor (2025)", popularitas:"⭐⭐⭐⭐ — Dominan di peternakan susu Jabar", catatan:"KPBS Pangalengan, KUD Cikaret, Greenfields Malang = sentra sapi perah FH Indonesia. Susu FH = 95% pasokan susu segar nasional", }, }; const JADWAL_VAKSIN_BROILER = [ {hari:1, vaksin:"ND Clone 45 + IB H120", cara:"Tetes mata", dosis:"1 tetes/ekor", catatan:"Segera saat chick-in"}, {hari:10, vaksin:"Gumboro", cara:"Air minum", dosis:"1 ampul/1000", catatan:"Berikan pagi hari sebelum makan"}, {hari:18, vaksin:"ND Lasota", cara:"Spray/tetes", dosis:"1 tetes/ekor", catatan:"Booster ND — penting!"}, {hari:21, vaksin:"IB Booster", cara:"Air minum", dosis:"1 ampul/1000", catatan:"Opsional jika serangan IB tinggi"}, ]; const JADWAL_VAKSIN_LAYER = [ {minggu:1, vaksin:"ND+IB Primer", cara:"Tetes mata", dosis:"1 tetes", catatan:"Hari pertama"}, {minggu:2, vaksin:"Gumboro", cara:"Air minum", dosis:"", catatan:""}, {minggu:4, vaksin:"ND Lasota Booster", cara:"Spray", dosis:"", catatan:""}, {minggu:8, vaksin:"ND+IB+AI H5N1", cara:"Injeksi IM", dosis:"0.5ml/ekor", catatan:"AI WAJIB untuk layer komersial"}, {minggu:12, vaksin:"EDS + ND Oil", cara:"Injeksi SC", dosis:"0.5ml/ekor", catatan:"Sebelum puncak produksi"}, {minggu:16, vaksin:"AI H5N1 Booster", cara:"Injeksi IM", dosis:"0.5ml/ekor", catatan:"4 minggu sebelum lay"}, {minggu:44, vaksin:"ND+IB+AI Booster", cara:"Injeksi", dosis:"0.5ml/ekor", catatan:"Mid-lay booster"}, ]; const JADWAL_VAKSIN_SAPI = [ {bulan:0, vaksin:"Anthrax (daerah enzootik)", cara:"Subkutan", dosis:"1ml/ekor", catatan:"Wajib daerah tertentu"}, {bulan:1, vaksin:"SE (Septicemia Epizootic)", cara:"Subkutan", dosis:"2ml/ekor", catatan:"Sapi impor/feedlot"}, {bulan:6, vaksin:"PMK (wajib pemerintah)", cara:"Subkutan", dosis:"2ml/ekor", catatan:"Program nasional — gratis dari Dinas"}, {bulan:12, vaksin:"Brucellosis (betina <8bln)", cara:"Oral/IM", dosis:"1 dosis", catatan:"Khusus betina muda"}, ]; /* ===== DATA AWAL ===== */ const initialCattle = [ { id:"S001",name:"Simental-01",type:"sapi",breed:"Simental",gender:"Jantan",age:24,weightBuy:280,weightCurrent:340,priceBuy:17500000,status:"Penggemukan",buyDate:"2026-02-10",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Bandar H. Rahman",kandang:"A1",vaksin:"Lengkap",notes:"" }, { id:"S002",name:"Limosin-02",type:"sapi",breed:"Limousin",gender:"Jantan",age:30,weightBuy:320,weightCurrent:392,priceBuy:19000000,status:"Siap Jual",buyDate:"2026-01-15",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Pasar Ciawi",kandang:"A2",vaksin:"Lengkap",notes:"" }, { id:"S003",name:"PO-Betina-03",type:"sapi",breed:"PO",gender:"Betina",age:60,weightBuy:250,weightCurrent:290,priceBuy:11000000,status:"Breeding",buyDate:"2025-12-01",health:"Sehat",feedType:"Hijauan",supplier:"Peternak Garut",kandang:"B1",vaksin:"Lengkap",notes:"" }, { id:"S004",name:"Simental-04",type:"sapi",breed:"Simental",gender:"Jantan",age:18,weightBuy:220,weightCurrent:270,priceBuy:14000000,status:"Penggemukan",buyDate:"2026-03-05",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Bandar H. Rahman",kandang:"A3",vaksin:"Lengkap",notes:"" }, { id:"S005",name:"FH-Afkir-05",type:"sapi",breed:"FH Afkir",gender:"Betina",age:84,weightBuy:300,weightCurrent:346,priceBuy:10500000,status:"Siap Jual",buyDate:"2026-02-20",health:"Sehat",feedType:"Konsentrat",supplier:"Lembang Farm",kandang:"B2",vaksin:"Lengkap",notes:"" }, { id:"S006",name:"PO-Sakit-06",type:"sapi",breed:"PO",gender:"Jantan",age:22,weightBuy:240,weightCurrent:254,priceBuy:13500000,status:"Sakit",buyDate:"2026-03-10",health:"Sakit",feedType:"Hijauan",supplier:"Pasar Singaparna",kandang:"C1",vaksin:"Belum",notes:"Demam 3 hari" }, { id:"S007",name:"Bali-07",type:"sapi",breed:"Bali",gender:"Jantan",age:20,weightBuy:200,weightCurrent:242,priceBuy:12000000,status:"Penggemukan",buyDate:"2026-03-15",health:"Sehat",feedType:"Hijauan",supplier:"NTB Supplier",kandang:"A4",vaksin:"Lengkap",notes:"" }, ]; const initialSheep = [ { id:"D001",name:"Garut-J-01",type:"domba",breed:"Domba Garut",gender:"Jantan",age:18,weightBuy:28,weightCurrent:38,priceBuy:2500000,status:"Penggemukan",buyDate:"2026-02-15",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Pasar Wanaraja",kandang:"D1",vaksin:"Lengkap",notes:"" }, { id:"D002",name:"Garut-J-02",type:"domba",breed:"Domba Garut",gender:"Jantan",age:24,weightBuy:35,weightCurrent:46,priceBuy:3200000,status:"Siap Jual",buyDate:"2026-01-20",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Pasar Wanaraja",kandang:"D2",vaksin:"Lengkap",notes:"" }, { id:"D003",name:"Garut-B-03",type:"domba",breed:"Domba Garut",gender:"Betina",age:30,weightBuy:25,weightCurrent:30,priceBuy:1800000,status:"Breeding",buyDate:"2025-11-10",health:"Sehat",feedType:"Hijauan",supplier:"Peternak Bayongbong",kandang:"E1",vaksin:"Lengkap",notes:"" }, { id:"D004",name:"Lokal-J-04",type:"domba",breed:"Domba Lokal",gender:"Jantan",age:14,weightBuy:20,weightCurrent:27,priceBuy:900000,status:"Penggemukan",buyDate:"2026-03-01",health:"Sehat",feedType:"Hijauan",supplier:"Pasar Cigembor",kandang:"D3",vaksin:"Belum",notes:"" }, { id:"D005",name:"Garut-Muda-05",type:"domba",breed:"Domba Garut",gender:"Jantan",age:12,weightBuy:15,weightCurrent:19,priceBuy:1200000,status:"Penggemukan",buyDate:"2026-04-01",health:"Sehat",feedType:"Konsentrat+Hijauan",supplier:"Peternak Rancakalong",kandang:"D4",vaksin:"Belum",notes:"Lepas sapih" }, { id:"D006",name:"Merino-B-06",type:"domba",breed:"Domba Merino",gender:"Betina",age:20,weightBuy:30,weightCurrent:35,priceBuy:2200000,status:"Breeding",buyDate:"2026-02-01",health:"Sehat",feedType:"Hijauan",supplier:"Import",kandang:"E2",vaksin:"Lengkap",notes:"" }, { id:"D007",name:"Garut-Sakit-07",type:"domba",breed:"Domba Garut",gender:"Jantan",age:16,weightBuy:22,weightCurrent:23,priceBuy:1500000,status:"Sakit",buyDate:"2026-03-20",health:"Sakit",feedType:"Hijauan",supplier:"Pasar Tanjungsari",kandang:"D5",vaksin:"Belum",notes:"Cacingan" }, { id:"D008",name:"Garut-B-08",type:"domba",breed:"Domba Garut",gender:"Betina",age:28,weightBuy:27,weightCurrent:32,priceBuy:1900000,status:"Breeding",buyDate:"2026-01-10",health:"Sehat",feedType:"Hijauan",supplier:"Pasar Wanaraja",kandang:"E3",vaksin:"Lengkap",notes:"" }, ]; const initialPurchases = [ { id:"BL001",animalId:"S001",animalName:"Simental-01",animalType:"sapi",supplier:"Bandar H. Rahman",supplierPhone:"081320000",date:"2026-02-10",weight:280,pricePerKg:62500,totalPrice:17500000,payMethod:"Tunai",notes:"Pasar Ciawi" }, { id:"BL002",animalId:"D001",animalName:"Garut-J-01",animalType:"domba",supplier:"Pasar Wanaraja",supplierPhone:"081398888",date:"2026-02-15",weight:28,pricePerKg:89286,totalPrice:2500000,payMethod:"Transfer",notes:"" }, { id:"BL003",animalId:"S002",animalName:"Limosin-02",animalType:"sapi",supplier:"Pasar Ciawi",supplierPhone:"081345555",date:"2026-01-15",weight:320,pricePerKg:59375,totalPrice:19000000,payMethod:"Tunai",notes:"Dari bandar langsung" }, { id:"BL004",animalId:"BR001",animalName:"DOC Cobb 500 - 2000 ekor",animalType:"broiler",supplier:"PT Japfa Comfeed",supplierPhone:"02145678901",date:"2026-05-08",weight:0,pricePerKg:0,totalPrice:15000000,payMethod:"Transfer",notes:"Harga DOC Rp7500/ekor, chick-in OK" }, { id:"BL005",animalId:"BR002",animalName:"DOC Ross 308 - 1900 ekor",animalType:"broiler",supplier:"PT Malindo Feedmill",supplierPhone:"02198765432",date:"2026-04-30",weight:0,pricePerKg:0,totalPrice:14820000,payMethod:"Transfer",notes:"Rp7800/ekor, mortalitas 2 ekor saat tiba" }, { id:"BL006",animalId:"PT001",animalName:"DOC Layer Lohmann Brown - 500 ekor",animalType:"petelur",supplier:"PT Sierad Produce",supplierPhone:"02156789012",date:"2025-08-01",weight:0,pricePerKg:0,totalPrice:7500000,payMethod:"Transfer",notes:"Rp15000/ekor pullet umur 1 hari" }, { id:"BL007",animalId:"PT002",animalName:"DOC Layer ISA Brown - 700 ekor",animalType:"petelur",supplier:"PT Malindo Feedmill",supplierPhone:"02198765432",date:"2025-07-15",weight:0,pricePerKg:0,totalPrice:11200000,payMethod:"Transfer",notes:"Rp16000/ekor, kualitas A" }, { id:"BL008",animalId:"",animalName:"Pakan Broiler Starter 2 ton",animalType:"broiler",supplier:"PT Charoen Pokhpand",supplierPhone:"02187654321",date:"2026-05-08",weight:2000,pricePerKg:8500,totalPrice:17000000,payMethod:"Transfer",notes:"Untuk Kandang D periode 12" }, { id:"BL009",animalId:"",animalName:"Pakan Layer Mash 1.5 ton",animalType:"petelur",supplier:"PT Japfa Comfeed",supplierPhone:"02145678901",date:"2026-05-10",weight:1500,pricePerKg:7800,totalPrice:11700000,payMethod:"Transfer",notes:"Kandang A+B, stok 30 hari" }, { id:"BL010",animalId:"",animalName:"Vaksin ND + Gumboro paket",animalType:"broiler",supplier:"PT Medion",supplierPhone:"022765432",date:"2026-05-09",weight:0,pricePerKg:0,totalPrice:850000,payMethod:"Tunai",notes:"Untuk 2000 ekor Kandang D" }, ]; const initialHealth = [ { id:"KS001",animalId:"S006",animalName:"PO-Sakit-06",animalType:"sapi",date:"2026-03-15",type:"Sakit",diagnosis:"Demam & Batuk",treatment:"Antibiotik Enrofloxacin + Vit B",cost:185000,vet:"drh. Hasan",status:"Dalam Perawatan",notes:"Cek ulang 3 hari lagi" }, { id:"KS002",animalId:"D007",animalName:"Garut-Sakit-07",animalType:"domba",date:"2026-04-02",type:"Sakit",diagnosis:"Cacingan Berat",treatment:"Albendazole 3ml + Vitamin",cost:75000,vet:"Mantri Dede",status:"Dalam Perawatan",notes:"Isolasi dari kandang lain" }, { id:"KS003",animalId:"S001",animalName:"Simental-01",animalType:"sapi",date:"2026-03-01",type:"Vaksin",diagnosis:"-",treatment:"Vaksin Anthrax + Jembrana",cost:120000,vet:"drh. Hasan",status:"Selesai",notes:"Rutin 6 bulanan" }, { id:"KS004",animalId:"D002",animalName:"Garut-J-02",animalType:"domba",date:"2026-03-10",type:"Vaksin",diagnosis:"-",treatment:"Vaksin Scabies",cost:45000,vet:"Mantri Dede",status:"Selesai",notes:"" }, { id:"KS005",animalId:"S004",animalName:"Simental-04",animalType:"sapi",date:"2026-04-15",type:"Rutin",diagnosis:"-",treatment:"Ivermectin obat cacing",cost:90000,vet:"drh. Hasan",status:"Selesai",notes:"Rutin 3 bulan" }, { id:"KS006",animalId:"BR001",animalName:"Kandang D Cobb 500 (2000 ekor)",animalType:"broiler",date:"2026-05-09",type:"Vaksin",diagnosis:"-",treatment:"Vaksin ND (Newcastle Disease) tetes mata",cost:320000,vet:"Mantri Agus",status:"Selesai",notes:"Umur 4 hari, vaksin pertama" }, { id:"KS007",animalId:"BR001",animalName:"Kandang D Cobb 500 (2000 ekor)",animalType:"broiler",date:"2026-05-15",type:"Vaksin",diagnosis:"-",treatment:"Vaksin Gumboro IBD tetes air minum",cost:280000,vet:"Mantri Agus",status:"Selesai",notes:"Umur 10 hari" }, { id:"KS008",animalId:"BR002",animalName:"Kandang E Ross 308 (1900 ekor)",animalType:"broiler",date:"2026-05-06",type:"Sakit",diagnosis:"CRD (Chronic Respiratory Disease)",treatment:"Tylosin + Vitamin C air minum 5 hari",cost:450000,vet:"drh. Sinta",status:"Selesai",notes:"Mortalitas 12 ekor selama sakit" }, { id:"KS009",animalId:"PT001",animalName:"Kandang A Lohmann Brown (500 ekor)",animalType:"petelur",date:"2026-04-20",type:"Vaksin",diagnosis:"-",treatment:"Vaksin AI (Avian Influenza) H5N1",cost:375000,vet:"drh. Hasan",status:"Selesai",notes:"Vaksin 6 bulanan, wajib" }, { id:"KS010",animalId:"PT002",animalName:"Kandang B ISA Brown (700 ekor)",animalType:"petelur",date:"2026-05-05",type:"Rutin",diagnosis:"-",treatment:"Pemberian Vitamin AD3E + obat cacing Piperazine",cost:210000,vet:"Mantri Agus",status:"Selesai",notes:"Produksi menurun 3%, recovery 1 minggu" }, { id:"KS011",animalId:"PT003",animalName:"Kandang C Layer Afkir (200 ekor)",animalType:"petelur",date:"2026-05-20",type:"Sakit",diagnosis:"Egg Drop Syndrome (EDS)",treatment:"Supportif Vitamin + Elektrolit",cost:150000,vet:"Mantri Agus",status:"Dalam Perawatan",notes:"Produksi telur drop 30%, kandang perlu desinfeksi" }, { id:"KS012",animalId:"BR002",animalName:"Kandang E Ross 308 (1850 ekor)",animalType:"broiler",date:"2026-06-01",type:"Vaksin",diagnosis:"-",treatment:"Vaksin ND IB (Infectious Bronchitis) spray",cost:340000,vet:"drh. Sinta",status:"Selesai",notes:"Umur 14 hari, booster" }, ]; const initialFeed = [ { id:"PK001",type:"Konsentrat Sapi",brand:"Charoen CP",unit:"Kg",stock:500,pricePerUnit:4500,usagePerDay:25,forAnimal:"sapi",date:"2026-05-01",supplier:"Toko Pertanian Tasik" }, { id:"PK002",type:"Hijauan Segar",brand:"Lokal",unit:"Kg",stock:1200,pricePerUnit:500,usagePerDay:120,forAnimal:"semua",date:"2026-05-01",supplier:"Petani Sekitar" }, { id:"PK003",type:"Dedak Padi",brand:"Lokal",unit:"Kg",stock:300,pricePerUnit:3000,usagePerDay:15,forAnimal:"semua",date:"2026-05-05",supplier:"Penggilingan Padi" }, { id:"PK004",type:"Ampas Tahu",brand:"Lokal",unit:"Kg",stock:200,pricePerUnit:1500,usagePerDay:20,forAnimal:"semua",date:"2026-05-08",supplier:"Pabrik Tahu Singaparna" }, { id:"PK005",type:"Molases",brand:"Rajawali",unit:"Liter",stock:50,pricePerUnit:8000,usagePerDay:3,forAnimal:"sapi",date:"2026-05-10",supplier:"Distributor Molases" }, { id:"PK006",type:"Konsentrat Domba",brand:"Wonosari",unit:"Kg",stock:80,pricePerUnit:5000,usagePerDay:8,forAnimal:"domba",date:"2026-05-12",supplier:"Toko Ternak Garut" }, { id:"PK007",type:"Obat Cacing",brand:"Wormectin",unit:"Botol",stock:5,pricePerUnit:45000,usagePerDay:0.1,forAnimal:"domba",date:"2026-05-01",supplier:"Apotek Hewan" }, { id:"PK008",type:"Mineral Block",brand:"Medion",unit:"Blok",stock:10,pricePerUnit:35000,usagePerDay:0.3,forAnimal:"semua",date:"2026-05-03",supplier:"Apotek Hewan" }, { id:"PK009",type:"Broiler Starter",brand:"Charoen CP-511",unit:"Kg",stock:1850,pricePerUnit:8500,usagePerDay:56,forAnimal:"broiler",date:"2026-05-08",supplier:"PT Charoen Pokhpand" }, { id:"PK010",type:"Broiler Grower",brand:"Charoen CP-512",unit:"Kg",stock:620,pricePerUnit:8200,usagePerDay:112,forAnimal:"broiler",date:"2026-05-15",supplier:"PT Charoen Pokhpand" }, { id:"PK011",type:"Broiler Finisher",brand:"Japfa BR-2",unit:"Kg",stock:2100,pricePerUnit:7900,usagePerDay:280,forAnimal:"broiler",date:"2026-05-20",supplier:"PT Japfa Comfeed" }, { id:"PK012",type:"Layer Mash Pre-layer",brand:"Malindo Layer-1",unit:"Kg",stock:480,pricePerUnit:8000,usagePerDay:30,forAnimal:"petelur",date:"2026-05-10",supplier:"PT Malindo Feedmill" }, { id:"PK013",type:"Layer Mash Peak",brand:"Malindo Layer-2",unit:"Kg",stock:1250,pricePerUnit:7800,usagePerDay:120,forAnimal:"petelur",date:"2026-05-10",supplier:"PT Malindo Feedmill" }, { id:"PK014",type:"Limestone (Kapur)",brand:"Lokal",unit:"Kg",stock:150,pricePerUnit:1200,usagePerDay:6,forAnimal:"petelur",date:"2026-05-05",supplier:"Toko Bahan Bangunan" }, { id:"PK015",type:"Premix Vitamin Ayam",brand:"Vitachick",unit:"Kg",stock:18,pricePerUnit:65000,usagePerDay:0.5,forAnimal:"broiler",date:"2026-05-08",supplier:"Apotek Hewan" }, { id:"PK016",type:"Probiotik EM4 Ternak",brand:"EM4",unit:"Liter",stock:12,pricePerUnit:35000,usagePerDay:0.2,forAnimal:"semua",date:"2026-05-12",supplier:"Toko Pertanian" }, { id:"PK017",type:"Grit/Kerikil Kasar",brand:"Lokal",unit:"Kg",stock:40,pricePerUnit:2500,usagePerDay:1,forAnimal:"petelur",date:"2026-05-15",supplier:"Toko Pertanian" }, ]; const initialBreeding = [ { id:"BR001",indukId:"S003",indukName:"PO-Betina-03",animalType:"sapi",pejantan:"Simental (IB)",method:"IB",date:"2026-03-15",status:"Bunting",estimasiLahir:"2026-12-20",anakLahir:0,notes:"Bunting konfirmasi bulan ke-2" }, { id:"BR002",indukId:"D003",indukName:"Garut-B-03",animalType:"domba",pejantan:"Garut Super",method:"Kawin Alam",date:"2026-03-01",status:"Bunting",estimasiLahir:"2026-08-01",anakLahir:0,notes:"Estimasi kembar 2 ekor" }, { id:"BR003",indukId:"D006",indukName:"Merino-B-06",animalType:"domba",pejantan:"Garut (IB)",method:"IB",date:"2026-04-10",status:"Menunggu",estimasiLahir:"2026-09-10",anakLahir:0,notes:"Baru diinseminasi" }, { id:"BR004",indukId:"D008",indukName:"Garut-B-08",animalType:"domba",pejantan:"Garut Lokal",method:"Kawin Alam",date:"2026-02-10",status:"Melahirkan",estimasiLahir:"2026-07-10",anakLahir:2,notes:"Lahir 2 ekor jantan, sehat" }, { id:"BR005",indukId:"PT001",indukName:"Kandang A Lohmann Brown (500 ekor)",animalType:"petelur",pejantan:"—",method:"Tetasan",date:"2026-04-01",status:"Menetas",estimasiLahir:"2026-04-22",anakLahir:210,telurDitetaskan:250,fertilitasPct:92,daya_tetas_pct:84,notes:"Batch penetasan pertama, HE (Hatching Egg) dari induk terbaik" }, { id:"BR006",indukId:"PT002",indukName:"Kandang B ISA Brown (700 ekor)",animalType:"petelur",pejantan:"—",method:"Tetasan",date:"2026-05-01",status:"Menetas",estimasiLahir:"2026-05-22",anakLahir:318,telurDitetaskan:380,fertilitasPct:90,daya_tetas_pct:84,notes:"DOC betina dikembangkan, jantan dijual" }, { id:"BR007",indukId:"BR001",indukName:"Kandang D Cobb 500 (2000 ekor)",animalType:"broiler",pejantan:"Cobb 500 Rooster",method:"Kawin Alam (Kandang)",date:"2026-05-08",status:"Bertelur",estimasiLahir:"2026-06-15",anakLahir:0,telurDitetaskan:0,fertilitasPct:88,daya_tetas_pct:0,notes:"Parent stock — telur fertile untuk hatchery mitra" }, { id:"BR008",indukId:"",indukName:"Penetasan DOC Layer Batch 3",animalType:"petelur",pejantan:"—",method:"Mesin Tetas",date:"2026-05-15",status:"Inkubasi",estimasiLahir:"2026-06-05",anakLahir:0,telurDitetaskan:450,fertilitasPct:91,daya_tetas_pct:0,notes:"Inkubator 450 butir HE, suhu 37.8°C, kelembaban 60%" }, ]; const initialExpenses = [ { id:"OP001",category:"Pakan",description:"Konsentrat Sapi 500kg",amount:2250000,date:"2026-05-01",animalType:"sapi",notes:"" }, { id:"OP002",category:"Kesehatan",description:"Obat & Vaksin rutin",amount:415000,date:"2026-05-03",animalType:"semua",notes:"" }, { id:"OP003",category:"Tenaga Kerja",description:"Gaji kandang 2 orang",amount:4000000,date:"2026-05-01",animalType:"semua",notes:"Bulanan" }, { id:"OP004",category:"Transportasi",description:"Angkut sapi dari Ciawi",amount:500000,date:"2026-04-15",animalType:"sapi",notes:"" }, { id:"OP005",category:"Pakan",description:"Hijauan 1200kg",amount:600000,date:"2026-05-01",animalType:"semua",notes:"" }, { id:"OP006",category:"Kandang",description:"Perbaikan atap kandang B",amount:750000,date:"2026-04-20",animalType:"semua",notes:"" }, { id:"OP007",category:"Pakan",description:"Konsentrat Domba 80kg",amount:400000,date:"2026-05-12",animalType:"domba",notes:"" }, { id:"OP008",category:"Pakan",description:"Broiler Starter CP-511 2ton Kandang D",amount:17000000,date:"2026-05-08",animalType:"broiler",notes:"Untuk 2000 ekor 14 hari pertama" }, { id:"OP009",category:"Pakan",description:"Layer Mash Malindo 1.5ton Kandang A+B",amount:11700000,date:"2026-05-10",animalType:"petelur",notes:"Stok 30 hari" }, { id:"OP010",category:"Kesehatan",description:"Vaksin ND+Gumboro+AI paket Kandang D",amount:850000,date:"2026-05-09",animalType:"broiler",notes:"Termasuk jasa vaksinasi" }, { id:"OP011",category:"Kesehatan",description:"Obat CRD Tylosin+VitC Kandang E",amount:450000,date:"2026-05-06",animalType:"broiler",notes:"" }, { id:"OP012",category:"DOC",description:"DOC Cobb 500 2000 ekor Kandang D",amount:15000000,date:"2026-05-08",animalType:"broiler",notes:"Rp7500/ekor PT Japfa" }, { id:"OP013",category:"Listrik",description:"Listrik pemanas brooder+blower Mei",amount:1850000,date:"2026-05-31",animalType:"broiler",notes:"2 kandang aktif" }, { id:"OP014",category:"Listrik",description:"Listrik ventilasi+lampu kandang layer Mei",amount:980000,date:"2026-05-31",animalType:"petelur",notes:"3 kandang layer" }, { id:"OP015",category:"Kandang",description:"Disinfektan+sekam baru persiapan Kandang G",amount:620000,date:"2026-05-25",animalType:"broiler",notes:"Washing+desinfeksi sebelum chick-in" }, { id:"OP016",category:"Tenaga Kerja",description:"Bonus panen Kandang F - FCR bagus",amount:500000,date:"2026-05-15",animalType:"broiler",notes:"Insentif FCR ≤1.70" }, { id:"OP017",category:"Pakan",description:"Premix Vitachick 20kg",amount:1300000,date:"2026-05-08",animalType:"broiler",notes:"Suplemen 2000 ekor" }, { id:"OP018",category:"Pakan",description:"Limestone 150kg + Grit layer",amount:555000,date:"2026-05-15",animalType:"petelur",notes:"Kalsium cangkang telur" }, ]; const HARGA_KG = { "Simental":62000,"Limousin":60000,"PO":50000,"FH Afkir":42000,"Bali":48000,"Brahman":52000, "Domba Garut":90000,"Domba Lokal":75000,"Domba Merino":85000,"Domba Ekor Gemuk":80000,"Kambing PE":70000,"Kambing Lokal":65000, }; /* ===== HELPERS ===== */ const rp = n => "Rp " + new Intl.NumberFormat("id-ID").format(Math.round(Number(n) || 0)); const adg = (wC, wB, tgl) => { if(!wC||!wB||!tgl) return 0; const d = Math.floor((Date.now() - new Date(tgl)) / 86400000); return d > 0 ? ((wC - wB) / d).toFixed(2) : "0.00"; }; const nilaiEst = a => (a&&a.weightCurrent ? a.weightCurrent * (HARGA_KG[a.breed] || (a.type === "domba" ? 80000 : 50000)) : 0); const todayStr = () => new Date().toISOString().split("T")[0]; const newId = (prefix, list) => { const mx = list.reduce((m, x) => { const n = parseInt(x.id.replace(prefix, "")) || 0; return n > m ? n : m; }, 0); return prefix + String(mx + 1).padStart(3, "0"); }; /* ===== ICONS ===== */ const SVG = ({ d, size = 16, color = "currentColor", fill = "none", sw = "2" }) => ( {typeof d === "string" ? : d} ); const Ico = ({ n, size = 16, color = "currentColor" }) => { const map = { dash: "M3 3h7v7H3zM14 3h7v7h-7zM3 14h7v7H3zM14 14h7v7h-7z", sapi: <> , domba: <> , beli: <> , jual: "M12 2v20M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6", pakan: <> , sehat: "M22 12h-4l-3 9L9 3l-3 9H2", kawin: "M20.84 4.61a5.5 5.5 0 00-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 00-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 000-7.78z", biaya: "M12 1v22M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H7", laporan: <> , chart: <> , warn: <> , plus: <> , x: <> , edit: <> , del: <> , srch: <> , eye: <> , chev_l: "M15 18l-6-6 6-6", chev_r: "M9 18l6-6-6-6", rph: "M14.5 3.5a1 1 0 00-1-1h-7a1 1 0 00-1 1V20a1 1 0 001 1h11a1 1 0 001-1V9.5m-5-6L20 9.5m-5.5-6H20", petelur: "M12 2a6 6 0 016 6c0 4-3 7-6 10C9 15 6 12 6 8a6 6 0 016-6zM8 20h8M10 23h4", broiler: "M12 3C8 3 5 6 5 10c0 2 1 4 2 5l-1 4h12l-1-4c1-1 2-3 2-5 0-4-3-7-7-7z", }; const d = map[n]; if (!d) return null; return ( {typeof d === "string" ? : d} ); }; /* ===== BASE UI ===== */ const S = { row: { display: "flex", alignItems: "center", gap: 8 }, col: { display: "flex", flexDirection: "column", gap: 8 }, grid2: { display: "grid", gridTemplateColumns: "1fr 1fr", gap: 14 }, input: { background: "#13161f", border: `1px solid ${C.border2}`, borderRadius: 9, padding: "9px 12px", color: C.text, fontSize: 13, outline: "none", width: "100%", boxSizing: "border-box" }, select: { background: "#13161f", border: `1px solid ${C.border2}`, borderRadius: 9, padding: "9px 12px", color: C.text, fontSize: 13, outline: "none", width: "100%", boxSizing: "border-box" }, label: { fontSize: 10, color: C.dim, textTransform: "uppercase", letterSpacing: 1.2, fontWeight: 700, display: "block", marginBottom: 5 }, th: { padding: "10px 12px", textAlign: "left", fontSize: 10, fontWeight: 800, textTransform: "uppercase", letterSpacing: 0.8, whiteSpace: "nowrap" }, td: { padding: "10px 12px", fontSize: 12 }, }; const KartuStat = ({ label, value, sub, color, icon }) => (
{label}
{value}
{sub &&
{sub}
}
); const Badge = ({ text }) => { const t = String(text || ""); const map = { "Sehat": "#22c55e", "Sakit": "#ef4444", "Pemulihan": "#f59e0b", "Penggemukan": "#f5c842", "Siap Jual": "#3b82f6", "Breeding": "#a855f7", "Bunting": "#a855f7", "Melahirkan": "#22c55e", "Menunggu": "#f59e0b", "Gagal": "#ef4444", "Jantan": "#60a5fa", "Betina": "#f472b6", "sapi": "#f5c842", "domba": "#a3e635", "Pasar": "#3b82f6", "Jagal": "#ef4444", "Kurban": "#f59e0b", "Perusahaan": "#22c55e", "BAZNAS": "#a855f7", "Aqiqah": "#ec4899", "Online": "#60a5fa", "Lengkap": "#22c55e", "Belum": "#ef4444", "Sebagian": "#f59e0b", "Selesai": "#22c55e", "Dalam Perawatan": "#f59e0b", "Vaksin": "#3b82f6", "Rutin": "#9097a8", "Operasi": "#a855f7", "Cedera": "#f59e0b", "IB": "#a855f7", "Kawin Alam": "#22c55e", "ET": "#3b82f6", "Tunai": "#22c55e", "Transfer": "#3b82f6", "DP+Pelunasan": "#f59e0b", "Kredit": "#ef4444", "semua": "#9097a8", }; const c = map[t] || "#666"; return {t || "-"}; }; const Modal = ({ title, onClose, children, wide }) => (

{title}

{children}
); const Inp = ({ label, value, onChange, type = "text", options, span, placeholder, required }) => (
{options ? ( ) : ( onChange(e.target.value)} placeholder={placeholder || ""} style={S.input} /> )}
); const Textarea = ({ label, value, onChange, span }) => (