ThreadCount Community edition

Uniform stock management for healthcare linen rooms: the coordinator app, the phone counter and the staff app, for your own server. Built from 38e16eb on 2026-09-15. Licensed under the Functional Source License (FSL-1.1-ALv2).
This commit is contained in:
ThreadCount
2026-09-16 07:57:54 +10:00
commit 0910bc32c1
457 changed files with 55952 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { useSnap } from "@/lib/client";
import { Panel, QueueRow } from "@/components/portal";
import { useSetupSteps } from "@/components/Checklist";
/* The first-run checklist, as the first queue group until it is done or dismissed. Which steps are
done and when it shows come from Checklist's hook, so the rules live in one place. */
export default function SetupGroup() {
const { isAdmin } = useSnap();
const { steps, done, finished, visible, dismiss } = useSetupSteps();
const [welcome, setWelcome] = useState(false);
useEffect(() => { if (new URLSearchParams(window.location.search).get("welcome") === "1") setWelcome(true); }, []);
if (!visible) return null;
return (
<Panel
id="setup"
icon="doc"
title={welcome ? "Welcome to ThreadCount" : "Getting set up"}
count={steps.length - done}
foot={(isAdmin || welcome) ? <button type="button" className="btn btn-ghost" onClick={() => dismiss()}>{finished ? "Done" : "Dismiss"}</button> : undefined}
>
{steps.map((st) => (
<QueueRow
key={st.label}
age={<span aria-hidden="true">{st.done ? "✓" : "○"}</span>}
ageLabel={st.done ? "done" : "to do"}
title={<span style={st.done ? { textDecoration: "line-through", color: "var(--color-neutral-700)", fontWeight: 500 } : undefined}>{st.label}</span>}
meta={null}
actions={st.done ? undefined : <Link href={st.href} className="btn btn-secondary" aria-label={`${st.label}: ${st.cta}`}>{st.cta}</Link>}
/>
))}
</Panel>
);
}