"use client";
/* 1J — Account.
*
* What a wearer can do to their own sign-in, and one thing they deliberately cannot.
*
* Changing the password is the only revocation they have: a staff token carries a fingerprint of
* the password hash, so setting a new one ends every session signed against the old one at once —
* a phone left on a ward, a cookie copied off it, a password read over somebody's shoulder. The
* copy says so plainly, because the consequence is the feature and somebody who does not know it
* happens will not reach for this when they most need it.
*
* Deleting the account is not here, and is not an oversight. Access is the linen room's to grant
* and theirs to remove: a wearer who could delete their own account would take the record of what
* they were issued with it.
*/
import { DELETE_ACCOUNT_URL, PRIVACY_EMAIL, PRIVACY_URL, TERMS_URL } from "@/lib/links";
import { useState } from "react";
import { MBar, MBody, MError, MRow, MRule, MSection, MTop } from "@/components/m";
import { INK, N600, N700 } from "@/components/staffui";
import { useStaff } from "@/lib/staffclient";
import { forgetPush } from "@/lib/staffpush";
import NotificationSettings, { type NotifyPrefs } from "@/components/screens/NotificationSettings";
const field: React.CSSProperties = {
width: "100%", minHeight: 52, padding: "0 14px", border: "2px solid var(--color-divider)",
borderRadius: 0, font: "inherit", fontSize: 16, background: "#fff", color: "var(--color-text)",
};
const label: React.CSSProperties = {
display: "block", fontSize: 12.5, fontWeight: 800, letterSpacing: "0.06em",
textTransform: "uppercase", color: N600,
};
export default function AccountScreen({ email, prefs, pushReady }: {
email: string; prefs: NotifyPrefs; pushReady: boolean;
}) {
const { me, mutate, busy } = useStaff();
const [open, setOpen] = useState(false);
const [current, setCurrent] = useState("");
const [next, setNext] = useState("");
const [err, setErr] = useState("");
const [done, setDone] = useState(false);
const [leaving, setLeaving] = useState(false);
// The server enforces the same floor; checking it here only saves a round trip and a refusal.
const ready = current.length > 0 && next.length >= 8;
/* ⛔ Signing out never waits on push.forget succeeding, and never fails because it didn't.
* Somebody on a ward with no signal still has to be able to leave a phone they are handing on.
* An orphaned token is reclaimed three other ways — the next registration re-points it, FCM
* reports it gone, and a password change clears the lot. */
async function signOut() {
setLeaving(true);
const token = forgetPush();
if (token) void mutate("push.forget", { token });
await fetch("/api/staff/logout", {
method: "POST", headers: { "content-type": "application/json" }, body: "{}",
}).catch(() => {});
// A full navigation: the cookie has just been cleared and every screen behind it is
// server-rendered.
window.location.replace("/my/signin");
}
return (
<>
setErr("")} />
{me.name}
{email}
{done ? (
Password changed
Every other device signed in as you has been signed out, and any phone of yours set
up for notifications has been unregistered. This one stays signed in.
) : (
<>
{/* A disclosure, not a link: the form is on this screen, so the row says so in words
a screen reader is given rather than only by what appears underneath it. */}
{open && (
{/* The words wrap the box rather than sitting beside it: on the one screen where
typing in the wrong one of two password fields is silent, both must announce
which they are. */}
At least 8 characters. Changing it signs you out everywhere else straight away.
This device stays signed in.
)}
>
)}
ThreadCount holds your sign-in and the linen room’s record of what you have been
issued. You can’t delete this account from here — ask your uniform coordinator and
they can remove it{PRIVACY_EMAIL ? <>, or write to {PRIVACY_EMAIL}> : null}.
{PRIVACY_URL && }
{DELETE_ACCOUNT_URL && }
{TERMS_URL && }
{/* The one thing a wearer can do to a phone they no longer have, so it is findable without
asking — and at the foot, because it is the last thing anybody comes here to do. */}