Files
threadcount-community/app/(site)/roadmap/page.tsx
T
ThreadCount 344b1701dd ThreadCount Community edition
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
2026-09-13 08:54:35 +10:00

86 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import Link from "next/link";
import { Band, CtaBand, PageHead, SiteNav, h2, h3, kicker, small } from "@/components/site";
export const metadata = {
title: "Roadmap",
description: "Whats being built next for ThreadCount, and what has shipped since the list was written. No dates — the order is intent, and it came from linen rooms asking.",
alternates: { canonical: "/roadmap" },
};
// Still to come. No dates, because a date on a public page is a promise the room can't always keep.
const PLANNED = [
{ t: "Automatic reorder triggers at par level", b: "Set a par level per garment and size, and let the draft order raise itself when the shelf drops below it." },
{ t: "Offline mode for the linen room", b: "Keep issuing and counting when the wireless drops out, and sync when it returns." },
{ t: "Staff self-service issue kiosk", b: "A screen at the counter where staff identify themselves and collect what has been approved, without queueing for the coordinator." },
{ t: "Cost per staff member reporting", b: "Spend by individual as well as by ward, for the conversations about outliers." },
{ t: "Laundry contractor reconciliation", b: "Match what went out against what came back, and put a number on what the contract is losing." },
{ t: "Multi-site and group-wide rollout", b: "Several stores running independently — a hospitals linen rooms, an aged-care groups homes, a network of clinics — with combined reporting above them." },
];
/* Four things that were on this list have since been built, and leaving them tagged "Planned"
* made the page contradict /features and /faq — a reader could not tell which one to believe. They
* stay on the page rather than quietly disappearing from it, because a room that read the list
* three months ago should be able to see what happened to it, but they are out of the numbering
* of what is still to come. Size history was listed here as "size and fit history"; what shipped is
* the size half — the record knows the last size somebody was issued, not whether it fitted them —
* so the title says size only rather than promising a fit note nobody writes. The two apps are the
* one honest half-state: both are built, and the Play listings are in review, so the tag says
* exactly that until the listings are public. */
const DONE = [
{ t: "Barcode and QR scanning on phone", b: "Scanning for issuing, counting and receiving, using the supplier codes already on the garment. Chrome and Edge read a barcode from the camera; on an iPhone or iPad, and in Firefox, the code is typed or read with a USB scanner.", tag: "Shipped" },
{ t: "Size history per person", b: "Every staff member carries the size of the last one they were issued, garment by garment, so the counter opens on what they had rather than on a guess — on the coordinators desk and in the staff app both.", tag: "Shipped" },
{ t: "Bulk import from existing spreadsheets", b: "The staff register, catalogue, locations and opening stock come in from CSV, each with a template to fill.", tag: "Shipped" },
{ t: "Android app", b: "Two of them: the counter app for the linen room, and a staff app for the people who wear the uniform. Both are built and the Play listings are in review.", tag: "In review" },
];
function Row({ n, t, b, tag, accent }: { n: string; t: string; b: string; tag: string; accent?: boolean }) {
return (
<div className="tcm-rowgrid" style={{ display: "grid", gridTemplateColumns: "64px 1fr 150px", gap: 28, padding: "26px 0", borderBottom: "1px solid var(--color-divider)", alignItems: "start" }}>
<div style={{ fontFamily: "var(--font-heading)", fontWeight: 800, fontSize: 20, color: "var(--color-neutral-600)" }}>{n}</div>
<div>
<h2 style={{ ...h3, fontSize: "clamp(18px,1.9vw,23px)", margin: 0 }}>{t}</h2>
<p style={{ fontSize: 15, lineHeight: 1.65, color: "var(--color-neutral-800)", margin: "7px 0 0", maxWidth: "58ch" }}>{b}</p>
</div>
<div style={{ textAlign: "right" }}><span className={"tag " + (accent ? "tag-accent" : "tag-outline")}>{tag}</span></div>
</div>
);
}
export default function Roadmap() {
return (
<>
<SiteNav />
<PageHead
kicker="Roadmap"
title="Whats being built next."
tone="ink"
lede="No dates. The list below is in order of intent, and what has been built since it was written is at the foot of the page."
/>
<Band pad="0 40px 0">
{PLANNED.map((it, i) => <Row key={it.t} n={String(i + 1).padStart(2, "0")} t={it.t} b={it.b} tag="Planned" />)}
<div style={{ height: 22 }} />
</Band>
<Band>
<div style={kicker}>Since this list was written</div>
<div style={{ marginTop: 10 }}>
{DONE.map((it) => <Row key={it.t} n="—" t={it.t} b={it.b} tag={it.tag} accent={it.tag === "Shipped"} />)}
</div>
</Band>
<Band tone="surface">
<div className="tcm-split" style={{ display: "grid", gridTemplateColumns: "1fr auto", gap: 32, alignItems: "center" }}>
<div>
<h2 style={{ ...h2, fontSize: "clamp(22px,2.6vw,34px)" }}>Something you need that isn&rsquo;t on this list?</h2>
<div style={{ ...small, marginTop: 10 }}>The list came from real linen rooms asking. Yours can change the order of it.</div>
</div>
<Link href="/contact" className="btn btn-primary">Tell me what&rsquo;s missing</Link>
</div>
</Band>
<CtaBand />
</>
);
}