"use client"; import { useState } from "react"; import { useSnap } from "@/lib/client"; import { Field, LiveRegion } from "@/components/ui"; /* Settings › Plan. Admin only, and only once plans are live. * * Numbers and short labels, no selling: the plan's name, where it stands, the staff count against * the ceiling when there is one, what the hosted backups keep, and the billing contact. Two * things to do: ask for an invoice, which emails the owner and nothing more, and download the * backup, which is the same file Data offers and is here because a room deciding whether to pay * should have its way out beside the button. No card yet; that is a later phase. */ const STATE_WORDS: Record = { grandfathered: "Free · everything included, for good", free: "Free", trial: "Trial", active: "Paid", grace: "Ended · still writable", read_only: "Read-only", }; export default function PlanTab() { const { s, mutate } = useSnap(); const p = s.plan; const [email, setEmail] = useState(p.billingEmail); const [want, setWant] = useState<"hosted_facility" | "health_service">("hosted_facility"); const [msg, setMsg] = useState(""); const [busy, setBusy] = useState(""); const fmt = (iso: string | null) => iso ? new Date(iso).toLocaleDateString("en-AU", { day: "numeric", month: "short", year: "numeric" }) : "—"; const row = (k: string, v: React.ReactNode) => (
{k}
{v}
); async function run(op: "plan.billing" | "plan.invoice", payload: Record, done: string) { setBusy(op); setMsg(""); const r = await mutate(op, payload); setBusy(""); setMsg(r.ok ? done : r.error); } const ends = p.state === "trial" ? "Trial ends" : p.state === "active" ? "Paid until" : p.state === "grace" ? "Writable until" : null; const paidOrTrial = p.state === "active" || p.state === "trial"; return ( <>
Plan
{p.label}
{row("Status", {STATE_WORDS[p.state] || p.state}{p.state === "trial" && p.daysLeft !== null ? ` · ${p.daysLeft} days left` : ""}{p.state === "grace" && p.graceDaysLeft !== null ? ` · ${p.graceDaysLeft} days` : ""})} {row("Staff records", p.maxStaff === null ? String(p.staff) : `${p.staff} of ${p.maxStaff}`)} {row("Backups", `Nightly · ${p.backupDays} days`)} {ends && row(ends, fmt(p.state === "grace" ? p.graceEndsAt : p.endsAt))} {row("Billing contact", p.billingEmail || "—")}
{p.readOnly && (
Reports, exports and the backup still work. Writes start again when a payment is recorded.
)} {!p.grandfathered && ( <>
Invoice
{(c) => setEmail(e.target.value)} />} {(c) => ( )}
Download backup
{paidOrTrial &&
A renewal invoice is requested the same way.
} )} {p.grandfathered && (
Download backup
)} ); }