ThreadCount Community edition

Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
This commit is contained in:
ThreadCount
2026-09-13 08:54:35 +10:00
commit 344b1701dd
505 changed files with 56231 additions and 0 deletions
+32
View File
@@ -0,0 +1,32 @@
"use client";
import { PRICES } from "@/lib/plan";
/* The one question sign-up asks about plans, once they are live: the free room or the trial.
* Two radio cards, numbers and short labels. The prices come from lib/plan.ts so they cannot drift
* from the pricing page. Health Service is not offered here — it starts as a conversation. */
export type SignupPlan = "hosted_small" | "hosted_facility";
const OPTS: { v: SignupPlan; name: string; price: string; note: string }[] = [
{ v: "hosted_small", name: "Hosted Small", price: "Free", note: `Up to ${PRICES.freeStaff} staff records.` },
{ v: "hosted_facility", name: "Hosted Facility", price: "60-day trial", note: `Then $${PRICES.hostedAnnual.toLocaleString("en-AU")} a year. No card now.` },
];
export default function PlanChoice({ value, onChange }: { value: SignupPlan; onChange: (v: SignupPlan) => void }) {
return (
<div style={{ display: "grid", gap: 8 }}>
{OPTS.map((o) => {
const on = value === o.v;
return (
<label key={o.v} style={{ display: "grid", gridTemplateColumns: "22px 1fr auto", gap: 12, alignItems: "center", padding: "12px 14px", border: `2px solid ${on ? "var(--color-text)" : "var(--color-divider)"}`, cursor: "pointer", background: on ? "var(--color-surface)" : "transparent" }}>
<input type="radio" name="plan" value={o.v} checked={on} onChange={() => onChange(o.v)} style={{ width: 18, height: 18, margin: 0, accentColor: "var(--color-accent)" }} />
<span>
<span style={{ display: "block", fontWeight: 800, fontSize: 14 }}>{o.name}</span>
<span style={{ display: "block", fontSize: 12.5, color: "var(--color-neutral-700)", marginTop: 2 }}>{o.note}</span>
</span>
<span style={{ fontWeight: 800, fontSize: 13, fontVariantNumeric: "tabular-nums", whiteSpace: "nowrap" }}>{o.price}</span>
</label>
);
})}
</div>
);
}