/* App shell — top bar, tabs, login screen, README, and main coordination */ function Login({ onSignIn }) { const [username, setUsername] = useState(""); const [password, setPassword] = useState(""); const [error, setError] = useState(""); const [loading, setLoading] = useState(false); const submit = async (e) => { e.preventDefault(); if (!username || !password) return; setLoading(true); setError(""); try { await onSignIn(username, password); } catch (err) { setError(err.message || "Invalid credentials"); } finally { setLoading(false); } }; return (

Kisongi Farm Tracker

Robusta coffee · Uganda

{error &&
{error}
}
setUsername(e.target.value)} className="mt-1" icon={}/>
setPassword(e.target.value)} className="mt-1"/>

Read-only access? Ask the admin for viewer credentials.

); } /* ---------------- README tab ---------------- */ function ReadmeTab() { return (
Usage notes

How to use this tracker

A quick guide to logging expenses and income for the Kisongi farm. All figures are in Ugandan Shillings (UGX).

    {[ ["Log every expense as it happens", "Open the Expenses tab, tap “Add expense”, fill in the date, amount, what it was for, and pick a category. Notes are optional but useful for receipts and counts."], ["Use Income for everything that comes in", "Tree sales during land opening, future coffee sales, seedling sales, rental, grants. Pick the right Source so the Summary stays accurate."], ["Filter to slice your view", "Date range and category filters live in the URL — share a link to a specific filtered view with your accountant."], ["Read the Summary tab regularly", "Three KPIs (Income, Expenses, Net Position) plus charts and breakdown tables. The Net Position turns red if expenses exceed income."], ["Roles", "Admin can add, edit, delete. Viewer (accountant, partner, agronomist) is read-only — they can browse, filter and see the same Summary."], ].map(([t, body], i) => (
  1. {i + 1}
    {t}

    {body}

  2. ))}
Categories in use
{window.CATEGORIES.map(c => ( {c} ))}
Tip: keep receipts
Snap a photo of every receipt and reference it in the Notes field (e.g. “receipt #042”). Makes audits and reconciliation painless.
); } /* ---------------- Top bar ---------------- */ function TopBar({ role, email, onLogout }) { const [menu, setMenu] = useState(false); const ref = useRef(null); useEffect(() => { const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setMenu(false); }; document.addEventListener("mousedown", onDoc); return () => document.removeEventListener("mousedown", onDoc); }, []); return (
Kisongi Farm
Tracker · Robusta
{role === "admin" ? "Admin" : "Viewer"}
{menu && (
{email}
Signed in as {role}
)}
); } /* ---------------- Tabs ---------------- */ function SubNav({ tab, setTab }) { const tabs = [ { id: "expenses", label: "Expenses", icon: }, { id: "income", label: "Income", icon: }, { id: "summary", label: "Summary", icon: }, { id: "readme", label: "README", icon: }, ]; return ( ); } function BottomNav({ tab, setTab }) { const tabs = [ { id: "expenses", label: "Expenses", icon: }, { id: "income", label: "Income", icon: }, { id: "summary", label: "Summary", icon: }, { id: "readme", label: "Guide", icon: }, ]; return ( ); } Object.assign(window, { Login, ReadmeTab, TopBar, SubNav, BottomNav });