- {accountLabel(account)}
- {/* Meta, so muted: what the grant lets this person do, in the
- words the server resolved rather than a level code. */}
-
- {account.canWrite
- ? t("recordSharing.switcher.canWrite")
- : t("recordSharing.switcher.readOnly")}
-
-
{t("recordSharing.banner.viewing", { name })}
{" "}
- {/* Resolved server-side, and it says something at BOTH levels now.
- v1.36.1 is the release that made `canWrite` true, and until this
- line changed the write case rendered nothing at all: a delegate who
- could add to somebody's health record was told only whose record it
- was. That matters more than the read case, not less, and the rest of
- the product leans on it — a control the record refuses is absent
- rather than disabled, on the stated grounds that the banner names
- the mode globally. It has to actually do that. */}
- {active.canWrite
- ? t("recordSharing.banner.canAdd")
- : t("recordSharing.banner.readOnly")}
+ {recordKindLabel(presentation.recordKind, t)}.{" "}
+ {accessLabel(presentation.access, t)}
);
}
+
+function accessLabel(
+ access: ReturnType["access"],
+ t: ReturnType["t"],
+): string {
+ if (access === "manage") return t("recordSharing.row.canManage");
+ return access === "view-and-add"
+ ? t("recordSharing.banner.canAdd")
+ : t("recordSharing.banner.readOnly");
+}
+
+function recordKindLabel(
+ recordKind: ReturnType["recordKind"],
+ t: ReturnType["t"],
+): string {
+ return recordKind === "managed"
+ ? t("recordSharing.lookingAfter.kindManaged")
+ : t("recordSharing.lookingAfter.kindShared");
+}
diff --git a/src/lib/navigation/record-presentation.ts b/src/lib/navigation/record-presentation.ts
new file mode 100644
index 000000000..3922c0243
--- /dev/null
+++ b/src/lib/navigation/record-presentation.ts
@@ -0,0 +1,30 @@
+import type {
+ AccountAccessEntry,
+ AccountRecordKind,
+} from "@/lib/sharing/account-access-view";
+
+export type RecordAccessPresentation = "view" | "view-and-add" | "manage";
+
+export interface RecordPresentation {
+ access: RecordAccessPresentation;
+ recordKind: AccountRecordKind;
+}
+
+/**
+ * The server publishes both a resolved `canWrite` decision and the canonical
+ * three-level label. Chrome binds those values here without treating either as
+ * an authorization input: a handler still resolves the active grant afresh.
+ */
+export function resolveRecordPresentation(
+ entry: Pick,
+): RecordPresentation {
+ return {
+ access:
+ entry.level === "manage"
+ ? "manage"
+ : entry.canWrite
+ ? "view-and-add"
+ : "view",
+ recordKind: entry.recordKind,
+ };
+}
diff --git a/src/lib/navigation/shared-record.ts b/src/lib/navigation/shared-record.ts
index 23f04767d..15ba5be41 100644
--- a/src/lib/navigation/shared-record.ts
+++ b/src/lib/navigation/shared-record.ts
@@ -37,12 +37,12 @@ interface RouteFamily {
}
const SHARED_RECORD_ROUTE_FAMILIES: readonly RouteFamily[] = [
- ...WHOLE_RECORD_ROUTE_FAMILIES.map((href) => ({
+ ...WHOLE_RECORD_ROUTE_FAMILIES.map((href): RouteFamily => ({
href,
scope: ENTIRE_RECORD,
})),
- ...SHARE_DOMAINS.flatMap((domain) =>
- SHARED_RECORD_DOMAIN_ROUTE_FAMILIES[domain].map((href) => ({
+ ...SHARE_DOMAINS.flatMap((domain): RouteFamily[] =>
+ SHARED_RECORD_DOMAIN_ROUTE_FAMILIES[domain].map((href): RouteFamily => ({
href,
scope: domain,
})),