"use client"; /* Settings โ€” only what the app itself controls. Everything else about the facility lives on the desktop, so there is one place a setting can be wrong rather than two. */ import { DELETE_ACCOUNT_URL, PRIVACY_URL, TERMS_URL } from "@/lib/links"; import { useEffect, useState } from "react"; import { useRouter } from "next/navigation"; import { useSnap } from "@/lib/client"; import { locTree } from "@/lib/compute"; import { clearAllCounts } from "@/lib/opencount"; import { INK, MBody, MError, MRow, MRule, MSection, MStepper, MTop } from "@/components/m"; const BEEP_KEY = "tc.beep"; export default function MSettings() { const { s, isAdmin, mutate, busy } = useSnap(); const router = useRouter(); const [beep, setBeep] = useState(true); const [gate, setGate] = useState(s.settings.varianceReason); const [err, setErr] = useState(""); useEffect(() => { try { setBeep(localStorage.getItem(BEEP_KEY) !== "0"); } catch { /* blocked store */ } }, []); const toggleBeep = () => { const next = !beep; setBeep(next); try { localStorage.setItem(BEEP_KEY, next ? "1" : "0"); } catch { /* blocked store */ } }; const saveGate = async (n: number) => { setGate(n); const r = await mutate("settings.update", { varianceReason: n }); if (!r.ok) { setErr(r.error); setGate(s.settings.varianceReason); } }; const signOut = async () => { // Their part-counted shelves go with them. The tally is keyed per person, so what is left // behind can never be read by the next signed-in user โ€” but it is theirs, it is on a phone // that is passed around a linen room, and nothing would ever clear it again once they have // gone. Done before the logout POST so a failed request still leaves the device tidy. clearAllCounts(s.session.userId); await fetch("/api/auth/logout", { method: "POST" }); // /m/login, not /auth: /auth is the website's two-pane desktop sign-in, and landing on it // inside a phone app is how you make someone think the app is broken. A full navigation // rather than router.push, because the session cookie has just been cleared and every page // behind it is server-rendered. window.location.replace("/m/login"); }; const locs = locTree(s).length; return ( <> setErr("")} />
{s.session.name}
{[s.session.title || s.session.role, s.session.email].filter(Boolean).join(" ยท ")}
Desktop} /> Desktop} /> {beep ? "On" : "Off"} } /> : {gate}} /> {/* Deleting an account has to be reachable from inside the app, not only from a web page somebody has to know exists โ€” this is the app that created the facility in the first place, and it is a Play requirement besides. These rows go to the site's own pages rather than a second deletion screen: there is one account-deletion flow, and it is the one on the website. Absolute, and on the web they open in a new tab. On a phone they cannot: this shell registers no browser plugin, so nothing here is able to hand a URL to Chrome, and the page loads over the top of the counter with the site's own nav and no tab bar. The row says as much before the tap, and the hardware back button comes straight back. The other two ways out were worse: a row that does nothing when tapped, or no deletion route in the app at all. Somebody who signs in rather than signing up never passes the links on the create-account screen, so this is the only place the signed-in counter app names them at all. */} {(DELETE_ACCOUNT_URL || PRIVACY_URL || TERMS_URL) && } {DELETE_ACCOUNT_URL && } {PRIVACY_URL && } {TERMS_URL && }

Ordering, reports, the catalogue and the staff register are all on the desktop site.

); }