/* Yappari Dashboard — App root + role-based router */ const { useState: useStateApp, useEffect: useEffectApp } = React; function App() { const [route, setRoute] = useStateApp({ name: "overview" }); const [user, setUser] = useStateApp(() => { try { return JSON.parse(localStorage.getItem("yappari_user") || "null"); } catch { return null; } }); const [machines, setMachines] = useStateApp([]); const [users, setUsers] = useStateApp([]); const [invoices, setInvoices] = useStateApp([]); const [toastState, setToast] = useStateApp(null); const [loading, setLoading] = useStateApp(true); const [loadErr, setLoadErr] = useStateApp(null); // Initial load from Supabase useEffectApp(() => { loadInitialData() .then(({ users, machines, invoices }) => { setUsers([...users]); setMachines([...machines]); setInvoices([...invoices]); setLoading(false); }) .catch(err => { console.error("loadInitialData failed:", err); setLoadErr(err.message || String(err)); setLoading(false); }); }, []); useEffectApp(() => { if (user) localStorage.setItem("yappari_user", JSON.stringify(user)); else localStorage.removeItem("yappari_user"); }, [user]); const navigate = (r) => { setRoute(r); window.scrollTo({ top: 0, behavior: "instant" }); }; const toast = (msg, tone = "info") => setToast({ msg, tone }); const login = (u) => { setUser(u); navigate({ name: "overview" }); toast(`Selamat datang, ${u.name.split(" ")[0]}!`, "success"); }; const logout = () => { setUser(null); navigate({ name: "overview" }); }; // client sees only their machines const clientMachines = user?.role === "client" ? machines.filter(m => m.clientId === user.id) : machines; const ctx = { user, isAdmin: user?.role === "admin", machines: clientMachines, allMachines: machines, setMachines, users, setUsers, invoices, setInvoices, route, navigate, login, logout, toast, }; if (loading) return (
Memuat data...
読み込み中
); if (loadErr) return (
Gagal Memuat Data
{loadErr}
Pastikan migration SQL sudah di-run di Supabase SQL Editor. File: migrations/001_initial_schema.sql
); if (!user) return ( setToast(null)} /> ); return (
{/* ── Shared ── */} {route.name === "overview" && } {route.name === "profile" && } {/* ── Client ── */} {route.name === "machines" && } {route.name === "machine-detail" && } {route.name === "machine-renew" && } {route.name === "payment-success" && } {route.name === "payment-failed" && } {/* ── Admin ── */} {route.name === "admin-clients" && } {route.name === "admin-machines" && } {route.name === "admin-billing" && } {route.name === "admin-invoices" && } {route.name === "admin-telemetron" && } {route.name === "admin-settings" && }
© 2026 Yappari! Vending Machine · PT. INDIE KREASI GROUP Bantuan: 0897 604 6500
setToast(null)} />
); } ReactDOM.createRoot(document.getElementById("root")).render();