Files

112 lines
4.4 KiB
TypeScript

// The labels each component takes, built from a message lookup. Every key the account page uses is
// named here and nowhere else, so `__tests__/i18n.test.ts` can run these builders against the
// catalogues and fail on a key either language lacks -- the page itself holds no string.
//
// `t` takes a key relative to the module (`export.heading`); the page binds it to
// `i18n.message("account." + key)`. The app's `app.failed` is passed in already looked up.
import { RECENT_SIGN_IN_SECONDS } from "../contract/constants.js"
import type { DeletionStatus } from "../contract/procedures.js"
import type { AccountAnalyticsLabels } from "./account-analytics.js"
import type { AccountDeletionLabels } from "./account-deletion.js"
import type { AccountExportLabels } from "./account-export.js"
export type Translate = (key: string, values?: Record<string, string | number>) => string
/** The sections this module has a name for; another module's key is shown as it is. */
const NAMED_SECTIONS = ["account", "guides", "support"] as const
export function sectionNames(t: Translate): Record<string, string> {
return Object.fromEntries(NAMED_SECTIONS.map((key) => [key, t(`sections.${key}`)]))
}
const named = (keys: readonly string[], names: Readonly<Record<string, string>>): string =>
keys.map((key) => names[key] ?? key).join(", ")
export function pageLabels(t: Translate) {
return {
title: t("title"),
intro: t("intro"),
link: t("link"),
profileHeading: t("profile.heading"),
name: t("profile.name"),
email: t("profile.email"),
}
}
export function exportLabels(t: Translate, failed: string): AccountExportLabels {
return {
heading: t("export.heading"),
body: t("export.body"),
submit: t("export.submit"),
busy: t("export.busy"),
done: t("export.done"),
partial: t("export.partial", { sections: "{sections}" }),
filename: t("export.filename"),
failed,
sectionNames: sectionNames(t),
}
}
export function deletionLabels(
t: Translate,
failed: string,
status: Pick<DeletionStatus, "modules" | "lastOwnerOf" | "onlyMemberOf">,
email: string,
): AccountDeletionLabels {
const names = sectionNames(t)
const organizations = (list: readonly { name: string }[]) => list.map((org) => org.name).join(", ")
return {
heading: t("deletion.heading"),
body: t("deletion.body"),
services: status.modules.length > 0 ? t("deletion.services", { modules: named(status.modules, names) }) : "",
...(status.lastOwnerOf.length > 0
? { lastOwner: t("deletion.lastOwner", { organizations: organizations(status.lastOwnerOf) }) }
: {}),
...(status.onlyMemberOf.length > 0
? { onlyMember: t("deletion.onlyMember", { organizations: organizations(status.onlyMemberOf) }) }
: {}),
reauth: t("deletion.reauth", { minutes: Math.round(RECENT_SIGN_IN_SECONDS / 60) }),
reauthLink: t("deletion.reauthLink"),
notInteractive: t("deletion.notInteractive"),
confirmLabel: t("deletion.confirmLabel"),
confirmHint: t("deletion.confirmHint", { email }),
submit: t("deletion.submit"),
busy: t("deletion.busy"),
completed: t("deletion.completed"),
erasing: t("deletion.erasing", { modules: "{modules}" }),
home: t("deletion.home"),
failed,
sectionNames: names,
}
}
/** The platform stores an analytics request reports on (ADR-049 §3). */
const ANALYTICS_STORES = ["session_replay", "errors", "proxy_logs", "traces", "logs", "analytics"] as const
const ANALYTICS_STATUSES = ["pending", "running", "completed", "failed", "expired"] as const
export function analyticsLabels(t: Translate, failed: string): AccountAnalyticsLabels {
return {
heading: t("analytics.heading"),
body: t("analytics.body"),
erase: t("analytics.erase"),
exportSubmit: t("analytics.exportSubmit"),
busy: t("analytics.busy"),
confirmErase: t("analytics.confirmErase"),
confirm: t("analytics.confirm"),
cancel: t("analytics.cancel"),
download: t("analytics.download"),
filename: t("analytics.filename"),
status: Object.fromEntries(
ANALYTICS_STATUSES.map((key) => [key, t(`analytics.status.${key}`)]),
) as AccountAnalyticsLabels["status"],
store: t("analytics.store"),
storeStatus: t("analytics.storeStatus"),
deleted: t("analytics.deleted"),
anonymized: t("analytics.anonymized"),
exported: t("analytics.exported"),
storeNames: Object.fromEntries(ANALYTICS_STORES.map((key) => [key, t(`analytics.stores.${key}`)])),
failed,
}
}