344b1701dd
Uniform stock management for healthcare linen rooms. Licensed under the GNU AGPL v3.
86 lines
5.4 KiB
TypeScript
86 lines
5.4 KiB
TypeScript
import Link from "next/link";
|
||
import { Band, CtaBand, PageHead, SiteNav, h2, h3, kicker, small } from "@/components/site";
|
||
|
||
export const metadata = {
|
||
title: "Roadmap",
|
||
description: "What’s 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 hospital’s linen rooms, an aged-care group’s 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 coordinator’s 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="What’s 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’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’s missing</Link>
|
||
</div>
|
||
</Band>
|
||
|
||
<CtaBand />
|
||
</>
|
||
);
|
||
}
|