@dloizides/ui-access-admin 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +51 -0
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/index.d.mts +544 -0
- package/dist/index.d.ts +544 -0
- package/dist/index.js +576 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +558 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/AccessResultTone.ts","../src/constants.ts","../src/expiry/expiryPolicy.ts","../src/links/capabilityLinkHelpers.ts","../src/links/useCapabilityLinkMint.ts","../src/theme/useAccessAdminPalette.ts","../src/AccessLinkPanel/AccessLinkPanel.tsx","../src/accounts/accountOptions.ts","../src/accounts/useSubjectAccountLink.ts","../src/AccountLinkPanel/AccountLinkPanel.tsx"],"names":["AccessResultTone","ISO_DATE_LENGTH","useState","useRef","useEffect","useCallback","copyText","useUi","useMemo","Linking","View","jsx","Text","jsxs","Button","StyleSheet","SPACE_XS","SPACE_SM","SPACE_MD","SPACE_LG","FONT_SM","FONT_MD","buildStyles","SelectControl"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * How a settled write should be reported. Its own file per the repo's\n * \"one exported enum per file\" rule.\n *\n * Two values, not three. There is no \"warning\" because every branch this package\n * reports is either a thing that worked or a thing the user has to act on — and\n * the one case that tempts a warning is the most important error in the package:\n * a mint that SUCCEEDED but whose URL never reached the clipboard. That is\n * reported as `Error`, loudly, because the URL is readable exactly once and a\n * user who dismisses it without copying by hand has to revoke and re-mint. An\n * amber \"heads up\" would let that slide past.\n */\nexport const enum AccessResultTone {\n Success = 'success',\n Error = 'error',\n}\n\n/** Reports a settled outcome with an ALREADY-LOCALIZED message. */\nexport type AccessResultReporter = (message: string, tone: AccessResultTone) => void;\n","/**\n * The package's two host contracts: the translation keys it resolves, and the\n * testIDs it renders.\n */\n\n/**\n * Every translation key this package resolves through `t(...)` — the host's i18n contract.\n *\n * ── WHY A MACHINE-READABLE MAP AND NOT A README TABLE ─────────────────────────\n * The kit is deliberately fallback-free: `t` is the host's own resolver (kefi passes\n * `FM`), and a missing key renders the RAW DOTTED NAME to the user — a panel warning\n * `accessAdmin.capabilityWarning` instead of explaining that anyone holding the URL\n * has the access. Because every `t(...)` call site in this package lives inside\n * `node_modules` once published, a host grepping its own source for untranslated\n * strings cannot see them. Hand-maintained key lists rot on exactly this path: one\n * portal in this fleet was found missing 26 kit keys, rendering raw names to users.\n *\n * So: bind a missing-key guard to this map, the way kefi-web's\n * `kitTranslationKeys.ts` already binds `LAYOUT_I18N` / `TABLE_I18N`. Then a kit\n * upgrade that adds a string FAILS the host's test suite instead of shipping raw\n * key text. `accessAdminI18n.test.ts` asserts this map stays complete and unused-free,\n * so the map cannot drift from the call sites either.\n *\n * The KEY NAMES are the package's; the WORDING is entirely the host's. That split is\n * what lets kefi keep its warm, specific copy (\"This link lets them see their own\n * guests and what they are owed\") under a key a survey tool can reuse with its own.\n */\nexport const ACCESS_ADMIN_I18N = {\n // ── AccessLinkPanel: framing ────────────────────────────────────────────────\n /** Panel heading. `{{p1}}` = subject display name. */\n panelHeading: 'accessAdmin.link.panelHeading',\n /** Supporting line explaining what the link grants. */\n panelNote: 'accessAdmin.link.panelNote',\n /** The security warning. Shown always, not only after a mint — see AccessLinkPanel. */\n capabilityWarning: 'accessAdmin.link.capabilityWarning',\n /** \"A link created now stops working on {{p1}}.\" `{{p1}}` = yyyy-mm-dd. */\n expiryPreview: 'accessAdmin.link.expiryPreview',\n\n // ── AccessLinkPanel: minting ────────────────────────────────────────────────\n mint: 'accessAdmin.link.mint',\n mintHint: 'accessAdmin.link.mintHint',\n /** Heading over the revealed URL. `{{p1}}` = subject display name. */\n mintedTitle: 'accessAdmin.link.mintedTitle',\n /** \"Shown once — copy it now.\" The honesty that makes the one-shot reveal safe. */\n mintedHint: 'accessAdmin.link.mintedHint',\n /** Reported when the mint landed AND the clipboard write succeeded. `{{p1}}` = name. */\n copySuccess: 'accessAdmin.link.copySuccess',\n /** Reported when the mint landed but the clipboard REFUSED. `{{p1}}` = name. */\n mintNotCopied: 'accessAdmin.link.mintNotCopied',\n /** Reported when a re-copy of an already-revealed URL failed. `{{p1}}` = name. */\n copyFailed: 'accessAdmin.link.copyFailed',\n\n // ── AccessLinkPanel: acting on a revealed URL ───────────────────────────────\n recopy: 'accessAdmin.link.recopy',\n recopyHint: 'accessAdmin.link.recopyHint',\n copied: 'accessAdmin.link.copied',\n dismiss: 'accessAdmin.link.dismiss',\n dismissHint: 'accessAdmin.link.dismissHint',\n email: 'accessAdmin.link.email',\n emailHint: 'accessAdmin.link.emailHint',\n /** \"This opens YOUR mail app — we do not send it for you.\" */\n emailNote: 'accessAdmin.link.emailNote',\n /** Mail subject. `{{p1}}` = subject display name. */\n emailSubject: 'accessAdmin.link.emailSubject',\n /** Mail body. `{{p1}}` = name, `{{p2}}` = url, `{{p3}}` = expiry date. */\n emailBody: 'accessAdmin.link.emailBody',\n\n // ── AccessLinkPanel: the live list ──────────────────────────────────────────\n /** \"Live links ({{p1}})\". `{{p1}}` = count. */\n liveHeading: 'accessAdmin.link.liveHeading',\n /** \"Created {{p1}} · stops working {{p2}}\". */\n liveMeta: 'accessAdmin.link.liveMeta',\n /** Shown in `liveMeta`'s `{{p2}}` slot when a link has no expiry at all. */\n expiresNever: 'accessAdmin.link.expiresNever',\n noLive: 'accessAdmin.link.noLive',\n /** Shown when the link list FAILED to load — never conflated with \"there are none\". */\n liveLoadError: 'accessAdmin.link.liveLoadError',\n close: 'accessAdmin.link.close',\n closeHint: 'accessAdmin.link.closeHint',\n\n // ── AccountLinkPanel ────────────────────────────────────────────────────────\n /** Panel heading. `{{p1}}` = subject display name. */\n accountPanelHeading: 'accessAdmin.account.panelHeading',\n accountPanelNote: 'accessAdmin.account.panelNote',\n accountPickerLabel: 'accessAdmin.account.pickerLabel',\n accountPickerHint: 'accessAdmin.account.pickerHint',\n accountPickerPlaceholder: 'accessAdmin.account.pickerPlaceholder',\n accountOptionHint: 'accessAdmin.account.optionHint',\n /** Label for a directory entry carrying neither a display name nor an email. */\n accountUnnamed: 'accessAdmin.account.unnamed',\n /** Shown when the directory is empty (or every entry is taken by another subject). */\n accountNone: 'accessAdmin.account.none',\n accountLink: 'accessAdmin.account.link',\n accountLinkHint: 'accessAdmin.account.linkHint',\n /** `{{p1}}` = subject display name. */\n accountLinkSuccess: 'accessAdmin.account.linkSuccess',\n accountUnlink: 'accessAdmin.account.unlink',\n accountUnlinkHint: 'accessAdmin.account.unlinkHint',\n /** `{{p1}}` = subject display name. */\n accountUnlinkSuccess: 'accessAdmin.account.unlinkSuccess',\n accountClose: 'accessAdmin.account.close',\n accountCloseHint: 'accessAdmin.account.closeHint',\n} as const;\n\n/** The shape of {@link ACCESS_ADMIN_I18N} — useful for typing an override map. */\nexport type AccessAdminI18n = typeof ACCESS_ADMIN_I18N;\n\n/**\n * Default testIDs. Every one is overridable via each panel's `testIDPrefix`, because\n * Playwright selectors in an adopting app already exist and a shared component is not\n * a good enough reason to rewrite someone's E2E suite.\n */\nexport const ACCESS_ADMIN_TEST_IDS = {\n linkPanel: 'access-link-panel',\n accountPanel: 'account-link-panel',\n} as const;\n","/**\n * How long a freshly minted capability link should live.\n *\n * ── THE GENERALIZATION ────────────────────────────────────────────────────────\n * kefi computed this as \"the event date, plus a two-week payout-reconciliation\n * tail, clamped to what the API accepts\". Every noun there is kefi's, but the\n * SHAPE is not: a capability is nearly always anchored to some real-world moment\n * (an event, a deadline, a booking, a review window) and needs to outlive that\n * moment by however long the follow-up work takes. So the policy is expressed as\n * an anchor plus a tail, and the host names them.\n *\n * ── THE ONE RULE THAT DOES NOT BEND ───────────────────────────────────────────\n * There is NO code path here that returns \"never\". Not for a missing anchor, not\n * for an unparseable one, not for an anchor in the past. A capability link is a\n * bearer token pasted into a chat app; the expiry is the only thing that limits\n * the blast radius of it being forwarded. A fallback to \"never\" would turn the\n * least-informed case — we could not read the date — into the most dangerous\n * outcome, which is exactly backwards. A missing anchor yields the bare tail: a\n * link that still dies on a clock.\n */\n\n/** Milliseconds in one day. */\nconst MS_PER_DAY = 86_400_000;\n\n/** Number of leading ISO characters that make up `yyyy-mm-dd`. */\nconst ISO_DATE_LENGTH = 10;\n\n/**\n * The host's expiry rule.\n *\n * `minDays`/`maxDays` are REQUIRED rather than defaulted, because they encode\n * what a specific API will accept. A default here would be a guess that fails\n * server-side at mint time, which is the worst place to find out.\n */\nexport interface ExpiryPolicy {\n /**\n * ISO date/timestamp the capability is anchored to, or null/undefined when\n * there is no anchor. Unparseable values are treated as absent.\n */\n readonly anchorDate?: string | null;\n /** Whole days the link survives PAST the anchor (or from now, when unanchored). */\n readonly tailDays: number;\n /** Smallest expiry the host's API accepts. */\n readonly minDays: number;\n /** Largest expiry the host's API accepts. Anchors beyond this clamp, never unbound. */\n readonly maxDays: number;\n}\n\n/**\n * Whole days from `now` until `anchorDate`, or null when the date is unusable.\n *\n * Both sides are floored to UTC midnight before subtracting, so the answer does\n * not flip by one depending on what time of day the button happens to be pressed.\n * Negative when the anchor is in the past — the caller decides what that means.\n */\nexport function daysUntilAnchor(anchorDate: string | null | undefined, now: Date): number | null {\n if (typeof anchorDate !== 'string' || anchorDate.trim() === '') return null;\n const anchor = Date.parse(anchorDate);\n if (Number.isNaN(anchor)) return null;\n return Math.floor(anchor / MS_PER_DAY) - Math.floor(now.getTime() / MS_PER_DAY);\n}\n\n/**\n * The expiry, in whole days from now, for a link minted under this policy.\n *\n * Three cases, all of which still expire:\n * - no usable anchor → the bare tail;\n * - anchor in the past → tail minus however long ago it was, floored at `minDays`,\n * so a link minted while settling up afterwards still dies soon;\n * - anchor beyond the ceiling → clamped to `maxDays`.\n */\nexport function capabilityExpiryDays(policy: ExpiryPolicy, now: Date): number {\n const untilAnchor = daysUntilAnchor(policy.anchorDate, now);\n const raw = untilAnchor === null ? policy.tailDays : untilAnchor + policy.tailDays;\n if (raw < policy.minDays) return policy.minDays;\n if (raw > policy.maxDays) return policy.maxDays;\n return raw;\n}\n\n/** The `yyyy-mm-dd` date a link minted now under this policy would stop working on. */\nexport function capabilityExpiryDate(policy: ExpiryPolicy, now: Date): string {\n const days = capabilityExpiryDays(policy, now);\n return new Date(now.getTime() + days * MS_PER_DAY).toISOString().slice(0, ISO_DATE_LENGTH);\n}\n","/**\n * Pure rules for presenting a subject's capability links.\n *\n * Logic-only (no JSX) so the parts that are quietly easy to get wrong — which\n * links belong to whom, which are still worth revoking, and what goes into a\n * mail compose window — are unit-tested without a renderer.\n */\nimport type { CapabilityLink } from '../types';\n\n/** Number of leading ISO characters that make up `yyyy-mm-dd`. */\nconst ISO_DATE_LENGTH = 10;\n\n/**\n * A subject's links, newest first.\n *\n * Matching is on `subjectId` and nothing else. The messy part — working out\n * WHICH subject an API's link row belongs to when the wire format does not say —\n * is the host's job, done once when it normalizes its DTOs. That keeps a\n * product's data-model compromise out of the shared filter.\n */\nexport function linksForSubject(\n links: readonly CapabilityLink[],\n subjectId: string,\n): CapabilityLink[] {\n return links\n .filter((link) => link.subjectId === subjectId)\n .sort((a, b) => String(b.createdAt ?? '').localeCompare(String(a.createdAt ?? '')));\n}\n\n/** The still-usable links belonging to a subject — the ones worth revoking. */\nexport function activeLinksForSubject(\n links: readonly CapabilityLink[],\n subjectId: string,\n): CapabilityLink[] {\n return linksForSubject(links, subjectId).filter((link) => link.isActive);\n}\n\n/** An ISO timestamp as a bare `yyyy-mm-dd`, or the supplied fallback when absent. */\nexport function formatLinkDate(value: string | null | undefined, fallback: string): string {\n if (typeof value !== 'string' || value.trim() === '') return fallback;\n return value.slice(0, ISO_DATE_LENGTH);\n}\n\n/**\n * A `mailto:` compose URL carrying the link, or null when there is nothing to send.\n *\n * NO recipient address is filled in, and that is deliberate rather than an\n * omission: an `AccessSubject` has no email field (see `types.ts` for why it\n * stays that small), so the sender picks the address in their own mail client.\n * It is also why the panel calls this \"open in email\" and warns that nothing is\n * sent on the user's behalf — a compose window they abandon looks identical to\n * one they send.\n */\nexport function buildCapabilityLinkMailto(\n subject: string,\n body: string,\n url: string,\n): string | null {\n if (url.trim() === '') return null;\n return `mailto:?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;\n}\n","/**\n * Mint-and-copy state for ONE subject's capability link.\n *\n * ── WHY THE COPY RESULT IS THREADED THROUGH INSTEAD OF IGNORED ────────────────\n * The clipboard write happens AFTER the network round-trip, in the mint's\n * continuation — not synchronously inside the press. Chrome accepts that from a\n * focused document with recent user activation; WebKit is stricter about tying\n * the write to the gesture task, and these panels get used from phones. So the\n * write is treated as one that MAY be refused rather than one that is assumed to\n * land.\n *\n * That matters more here than it would anywhere else, because the URL is\n * revealed exactly ONCE. If the copy silently failed and the user dismissed the\n * panel, the link would be unrecoverable — they would have to revoke and\n * re-mint, having already told someone it was on the way. So a refused copy is\n * reported as an ERROR even though the mint itself succeeded, and the URL stays\n * on screen to be copied by hand.\n *\n * ── NO REACT-QUERY ────────────────────────────────────────────────────────────\n * The mint is an injected promise, so this hook owns its own in-flight flag. A\n * host wires its mutation (and its cache invalidation) inside the callback.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { copyText } from '@dloizides/ui-layout';\n\nimport { AccessResultTone, type AccessResultReporter } from '../AccessResultTone';\nimport { ACCESS_ADMIN_I18N } from '../constants';\nimport { capabilityExpiryDays, type ExpiryPolicy } from '../expiry/expiryPolicy';\nimport type {\n AccessSubject,\n CapabilityLink,\n DescribeError,\n MintCapabilityLink,\n} from '../types';\n\n/** Translate function — mirrors the fleet's `FM(key, p1?, p2?, p3?)` shape. */\nexport type AccessTranslate = (key: string, p1?: string, p2?: string, p3?: string) => string;\n\nexport interface UseCapabilityLinkMintOptions {\n readonly subject: AccessSubject;\n readonly policy: ExpiryPolicy;\n readonly mint: MintCapabilityLink;\n readonly describeError: DescribeError;\n readonly onResult: AccessResultReporter;\n readonly t: AccessTranslate;\n /** Injectable clock, so the expiry maths is testable. Defaults to the real one. */\n readonly now?: () => Date;\n /** Optional platform clipboard writer (React Native's `Clipboard.setString`, say). */\n readonly clipboardWriter?: (text: string) => void | Promise<void>;\n}\n\nexport interface CapabilityLinkMintState {\n /** The just-minted link, revealed once, or null before any mint. */\n readonly minted: CapabilityLink | null;\n /** True while a mint is in flight. */\n readonly isPending: boolean;\n /** True when the last mint's URL actually reached the clipboard. */\n readonly copied: boolean;\n /** Mint a fresh link for this subject and copy it. */\n readonly mint: () => void;\n /** Re-copy the revealed URL, after a refused write. */\n readonly recopy: () => void;\n /** Forget the revealed URL — it cannot be read again afterwards. */\n readonly dismiss: () => void;\n}\n\nexport function useCapabilityLinkMint(\n options: UseCapabilityLinkMintOptions,\n): CapabilityLinkMintState {\n const { subject, policy, mint, describeError, onResult, t, now, clipboardWriter } = options;\n\n const [minted, setMinted] = useState<CapabilityLink | null>(null);\n const [copied, setCopied] = useState<boolean>(false);\n const [isPending, setIsPending] = useState<boolean>(false);\n\n // The mint is async and these panels close (a row collapses, a drawer dismisses)\n // while it is in flight, so every post-await setState is guarded.\n const mountedRef = useRef<boolean>(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n const copyUrl = useCallback(\n async (url: string): Promise<boolean> => {\n const ok = await copyText(url, clipboardWriter);\n if (mountedRef.current) setCopied(ok);\n return ok;\n },\n [clipboardWriter],\n );\n\n const runMint = useCallback((): void => {\n if (isPending) return;\n setIsPending(true);\n\n void (async () => {\n try {\n const expiresInDays = capabilityExpiryDays(policy, now === undefined ? new Date() : now());\n const link = await mint({ subject, expiresInDays });\n if (!mountedRef.current) return;\n\n setMinted(link);\n const ok = await copyUrl(link.url ?? '');\n if (!mountedRef.current) return;\n\n onResult(\n t(\n ok ? ACCESS_ADMIN_I18N.copySuccess : ACCESS_ADMIN_I18N.mintNotCopied,\n subject.displayName,\n ),\n ok ? AccessResultTone.Success : AccessResultTone.Error,\n );\n } catch (error) {\n if (!mountedRef.current) return;\n onResult(describeError(error as Error), AccessResultTone.Error);\n } finally {\n if (mountedRef.current) setIsPending(false);\n }\n })();\n }, [isPending, policy, now, mint, subject, copyUrl, onResult, t, describeError]);\n\n const recopy = useCallback((): void => {\n const url = minted?.url ?? '';\n if (url === '') return;\n\n void (async () => {\n const ok = await copyUrl(url);\n if (!mountedRef.current) return;\n onResult(\n t(ok ? ACCESS_ADMIN_I18N.copySuccess : ACCESS_ADMIN_I18N.copyFailed, subject.displayName),\n ok ? AccessResultTone.Success : AccessResultTone.Error,\n );\n })();\n }, [minted, copyUrl, onResult, t, subject.displayName]);\n\n const dismiss = useCallback((): void => {\n setMinted(null);\n setCopied(false);\n }, []);\n\n return { minted, isPending, copied, mint: runMint, recopy, dismiss };\n}\n","/**\n * The handful of colour roles these panels need, resolved from the host's\n * `UiProvider` theme.\n *\n * ── WHY A MAPPING LAYER AT ALL ────────────────────────────────────────────────\n * The kefi original read a `KefiColors` object with slots named for kefi's brand\n * (`brandDeep`, `positiveBg`, `surfaceMuted`). Carrying those names into a shared\n * package would have made every other portal invent a kefi palette to use it. So\n * the panels ask for ROLES — \"the surface a panel sits on\", \"the colour of a\n * security warning\" — and this module answers them from the theme every portal\n * already broadcasts.\n *\n * Not a single literal colour is defined here. Every value traces back to the\n * host's `@dloizides/design-tokens` theme, so a rebrand reaches these panels for\n * free and the `no-raw-color-literal` gate has nothing to catch.\n */\nimport { useMemo } from 'react';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nexport interface AccessAdminPalette {\n /** Background of the panel itself — a recessed surface inside a section. */\n readonly panelSurface: string;\n /** Hairline borders. */\n readonly border: string;\n readonly textPrimary: string;\n readonly textSecondary: string;\n /** The security warning, and the destructive action. */\n readonly danger: string;\n /** Fill and edge of the \"here is your new link\" box. */\n readonly revealSurface: string;\n readonly revealBorder: string;\n /** Heading inside the reveal box — the strongest brand tone available. */\n readonly revealHeading: string;\n}\n\nexport function useAccessAdminPalette(): AccessAdminPalette {\n const { theme } = useUi();\n const { colors, palette, semantic } = theme;\n\n return useMemo<AccessAdminPalette>(() => {\n const success = semantic.success ?? semantic.error;\n return {\n panelSurface: colors.surface,\n border: colors.border,\n textPrimary: colors.text,\n textSecondary: colors.textSecondary,\n danger: semantic.error['500'],\n // A tinted step when the host's scale has one, else the elevated surface —\n // never a hardcoded pastel, which would be wrong in dark mode.\n revealSurface: success['50'] ?? success['100'] ?? colors.surfaceElevated,\n revealBorder: success['500'],\n revealHeading: palette.primary['700'] ?? palette.primary['500'],\n };\n }, [colors, palette, semantic]);\n}\n","/**\n * The capability-link panel for ONE subject.\n *\n * ── SCOPED TO ONE SUBJECT ON PURPOSE ──────────────────────────────────────────\n * These links are CAPABILITIES: whoever holds the URL has the access, with no\n * sign-in in the way. A screen listing every subject's live link would itself be\n * a high-value secret. So this panel shows one subject's links, and only while\n * the user is looking at that subject.\n *\n * The primary action mints AND copies in a single press, because the real\n * workflow is pasting the link into a chat app. Email is a secondary COMPOSE\n * action (see `buildCapabilityLinkMailto`). Revoking any of this subject's live\n * links is reachable here, so a leaked link can be killed without disturbing\n * anyone else's.\n *\n * ── WHAT THE HOST OWNS ────────────────────────────────────────────────────────\n * The mint call, the error wording, and the per-link revoke control (via\n * `renderLinkActions`) — revocation usually needs a confirm step wired to the\n * host's own dialog and mutation, so the package renders the row and lets the\n * host fill the action slot rather than shipping half a revoke flow.\n */\nimport React, { useMemo } from 'react';\n\nimport { Linking, StyleSheet, Text, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { AccessResultTone, type AccessResultReporter } from '../AccessResultTone';\nimport { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS } from '../constants';\nimport { capabilityExpiryDate, type ExpiryPolicy } from '../expiry/expiryPolicy';\nimport {\n activeLinksForSubject,\n buildCapabilityLinkMailto,\n formatLinkDate,\n} from '../links/capabilityLinkHelpers';\nimport { useCapabilityLinkMint } from '../links/useCapabilityLinkMint';\nimport { useAccessAdminPalette, type AccessAdminPalette } from '../theme/useAccessAdminPalette';\nimport type {\n AccessSubject,\n CapabilityLink,\n DescribeError,\n MintCapabilityLink,\n} from '../types';\n\n/** Spacing scale — kept local so the package needs no spacing dependency. */\nconst SPACE_XS = 4;\nconst SPACE_SM = 8;\nconst SPACE_MD = 12;\nconst SPACE_LG = 16;\n\nconst FONT_SM = 12;\nconst FONT_MD = 13;\n\nexport interface AccessLinkPanelProps {\n /** The subject whose links are being managed. */\n readonly subject: AccessSubject;\n /** How long a link minted now should live. */\n readonly policy: ExpiryPolicy;\n /**\n * Every capability link the host knows about, normalized. Filtered to this\n * subject here — the host does not need to pre-filter.\n */\n readonly links: readonly CapabilityLink[];\n /**\n * True when the link list FAILED to load.\n *\n * Distinguished from \"loaded, and there are none\" deliberately: an empty list\n * caused by a failed fetch reads as \"this subject has no live link\", which\n * invites minting a SECOND live capability for someone who already has one —\n * and leaves the user believing there is nothing to revoke.\n */\n readonly linksFailed?: boolean;\n readonly mint: MintCapabilityLink;\n readonly describeError: DescribeError;\n readonly onClose: () => void;\n readonly onResult: AccessResultReporter;\n /** Renders the host's revoke control for one live link. */\n readonly renderLinkActions?: (link: CapabilityLink) => React.ReactNode;\n /** Injectable clock, for tests. */\n readonly now?: () => Date;\n /** Optional platform clipboard writer. */\n readonly clipboardWriter?: (text: string) => void | Promise<void>;\n /** Root testID; children derive from it. Defaults to `access-link-panel`. */\n readonly testIDPrefix?: string;\n}\n\nexport const AccessLinkPanel = ({\n subject,\n policy,\n links,\n linksFailed = false,\n mint,\n describeError,\n onClose,\n onResult,\n renderLinkActions,\n now,\n clipboardWriter,\n testIDPrefix = ACCESS_ADMIN_TEST_IDS.linkPanel,\n}: AccessLinkPanelProps): React.ReactElement => {\n const { t } = useUi();\n const palette = useAccessAdminPalette();\n const styles = useMemo(() => buildStyles(palette), [palette]);\n\n const state = useCapabilityLinkMint({\n subject,\n policy,\n mint,\n describeError,\n onResult,\n t,\n now,\n clipboardWriter,\n });\n\n const expiryDate = useMemo(\n () => capabilityExpiryDate(policy, now === undefined ? new Date() : now()),\n [policy, now],\n );\n const liveLinks = useMemo(() => activeLinksForSubject(links, subject.id), [links, subject.id]);\n const mintedUrl = state.minted?.url ?? '';\n\n const handleEmail = (): void => {\n const mailto = buildCapabilityLinkMailto(\n t(ACCESS_ADMIN_I18N.emailSubject, subject.displayName),\n t(ACCESS_ADMIN_I18N.emailBody, subject.displayName, mintedUrl, expiryDate),\n mintedUrl,\n );\n if (mailto === null) return;\n // Single-arg `openURL` is the RN API contract and behaves on native as well as\n // web. react-native-web routes everything but `tel:` through\n // `window.open(url, '_blank')`, so on web this hands off to the mail client in a\n // new tab; some browsers leave an about:blank tab behind. Cosmetic.\n void Linking.openURL(mailto).catch(() => {\n onResult(t(ACCESS_ADMIN_I18N.copyFailed, subject.displayName), AccessResultTone.Error);\n });\n };\n\n return (\n <View style={styles.panel} testID={testIDPrefix}>\n <Text style={styles.heading}>{t(ACCESS_ADMIN_I18N.panelHeading, subject.displayName)}</Text>\n <Text style={styles.note}>{t(ACCESS_ADMIN_I18N.panelNote)}</Text>\n {/* Shown ALWAYS, not only after a mint: the decision to create a bearer token\n is made before the press, so the warning has to be readable before it. */}\n <Text style={styles.warning} testID={`${testIDPrefix}-capability-warning`}>\n {t(ACCESS_ADMIN_I18N.capabilityWarning)}\n </Text>\n <Text style={styles.note} testID={`${testIDPrefix}-expiry-preview`}>\n {t(ACCESS_ADMIN_I18N.expiryPreview, expiryDate)}\n </Text>\n\n {state.minted !== null ? (\n <View style={styles.revealBox} testID={`${testIDPrefix}-minted`}>\n <Text style={styles.revealTitle}>\n {t(ACCESS_ADMIN_I18N.mintedTitle, subject.displayName)}\n </Text>\n <Text style={styles.note}>{t(ACCESS_ADMIN_I18N.mintedHint)}</Text>\n <Text selectable style={styles.url} testID={`${testIDPrefix}-minted-url`}>\n {mintedUrl}\n </Text>\n <View style={styles.actions}>\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.recopyHint)}\n accessibilityLabel={state.copied ? t(ACCESS_ADMIN_I18N.copied) : t(ACCESS_ADMIN_I18N.recopy)}\n label={state.copied ? t(ACCESS_ADMIN_I18N.copied) : t(ACCESS_ADMIN_I18N.recopy)}\n onPress={state.recopy}\n testID={`${testIDPrefix}-recopy`}\n />\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.emailHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.email)}\n label={t(ACCESS_ADMIN_I18N.email)}\n onPress={handleEmail}\n testID={`${testIDPrefix}-email`}\n variant=\"secondary\"\n />\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.dismissHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.dismiss)}\n label={t(ACCESS_ADMIN_I18N.dismiss)}\n onPress={state.dismiss}\n testID={`${testIDPrefix}-dismiss`}\n variant=\"secondary\"\n />\n </View>\n <Text style={styles.note}>{t(ACCESS_ADMIN_I18N.emailNote)}</Text>\n </View>\n ) : null}\n\n {linksFailed ? (\n <Text style={styles.warning} testID={`${testIDPrefix}-load-error`}>\n {t(ACCESS_ADMIN_I18N.liveLoadError)}\n </Text>\n ) : null}\n\n {!linksFailed && liveLinks.length > 0 ? (\n <View style={styles.liveBox}>\n <Text style={styles.subheading}>\n {t(ACCESS_ADMIN_I18N.liveHeading, String(liveLinks.length))}\n </Text>\n {liveLinks.map((link) => (\n <View key={link.id} style={styles.liveRow}>\n <Text style={styles.liveMeta}>\n {t(\n ACCESS_ADMIN_I18N.liveMeta,\n formatLinkDate(link.createdAt, ''),\n formatLinkDate(link.expiresAt, t(ACCESS_ADMIN_I18N.expiresNever)),\n )}\n </Text>\n {renderLinkActions === undefined ? null : renderLinkActions(link)}\n </View>\n ))}\n </View>\n ) : null}\n\n {!linksFailed && liveLinks.length === 0 ? (\n <Text style={styles.note} testID={`${testIDPrefix}-no-live`}>\n {t(ACCESS_ADMIN_I18N.noLive)}\n </Text>\n ) : null}\n\n <View style={styles.actions}>\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.mintHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.mint)}\n disabled={state.isPending}\n label={t(ACCESS_ADMIN_I18N.mint)}\n loading={state.isPending}\n onPress={state.mint}\n testID={`${testIDPrefix}-mint`}\n />\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.closeHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.close)}\n disabled={state.isPending}\n label={t(ACCESS_ADMIN_I18N.close)}\n onPress={onClose}\n testID={`${testIDPrefix}-close`}\n variant=\"secondary\"\n />\n </View>\n </View>\n );\n};\n\n/** Builds the panel styles from the live palette (re-run when the theme changes). */\nconst buildStyles = (c: AccessAdminPalette) =>\n StyleSheet.create({\n actions: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACE_SM },\n heading: { color: c.textPrimary, fontSize: FONT_MD, fontWeight: '700' },\n liveBox: { gap: SPACE_SM, marginTop: SPACE_XS },\n liveMeta: { color: c.textSecondary, fontSize: FONT_SM },\n liveRow: {\n borderTopColor: c.border,\n borderTopWidth: 1,\n gap: SPACE_XS,\n paddingTop: SPACE_SM,\n },\n note: { color: c.textSecondary, fontSize: FONT_SM },\n panel: {\n backgroundColor: c.panelSurface,\n borderColor: c.border,\n borderRadius: SPACE_SM,\n borderWidth: 1,\n gap: SPACE_XS,\n marginBottom: SPACE_LG,\n padding: SPACE_MD,\n },\n revealBox: {\n backgroundColor: c.revealSurface,\n borderColor: c.revealBorder,\n borderRadius: SPACE_SM,\n borderWidth: 1,\n gap: SPACE_XS,\n marginVertical: SPACE_SM,\n padding: SPACE_MD,\n },\n revealTitle: { color: c.revealHeading, fontSize: FONT_MD, fontWeight: '800' },\n subheading: { color: c.textPrimary, fontSize: FONT_SM, fontWeight: '700' },\n url: { color: c.textPrimary, fontSize: FONT_MD, fontWeight: '600' },\n warning: { color: c.danger, fontSize: FONT_SM, fontWeight: '600' },\n });\n","/**\n * Pure rules for the account picker.\n *\n * Logic-only so the two decisions that actually matter — what an account is\n * CALLED when the directory gives you almost nothing, and which accounts must\n * not be offered at all — are tested without a renderer.\n */\nimport type { ControlOption } from '@dloizides/ui-forms';\n\nimport type { AccessSubject, LinkableAccount } from '../types';\n\n/** True when a value is a non-blank string. */\nfunction isFilled(value: string | null | undefined): value is string {\n return typeof value === 'string' && value.trim() !== '';\n}\n\n/**\n * What to call an account: its display name, else its email, else the caller's\n * already-localized fallback.\n *\n * Directories genuinely return entries with neither — a freshly invited user who\n * has not completed a profile is the common one. Rendering those as a blank row\n * gives an unpickable option that looks like a rendering fault.\n */\nexport function accountDisplayLabel(account: LinkableAccount, unnamedLabel: string): string {\n if (isFilled(account.displayName)) return account.displayName.trim();\n if (isFilled(account.email)) return account.email.trim();\n return unnamedLabel;\n}\n\n/**\n * Build the picker's options for one subject.\n *\n * Accounts already bound to a DIFFERENT subject are dropped. That is not tidying:\n * every host that has built this backs it with a uniqueness constraint and\n * answers a duplicate binding with a 409, so offering such an account can only\n * ever produce an error the user cannot act on.\n *\n * The subject's OWN currently-bound account is KEPT, so the picker can show it as\n * the current selection instead of looking empty on a subject that is in fact\n * linked — which would read as \"not linked\" and invite a pointless re-link.\n *\n * Directory order is preserved; hosts return these sorted.\n */\nexport function buildAccountOptions(\n accounts: readonly LinkableAccount[],\n bindings: ReadonlyMap<string, string | null>,\n subject: AccessSubject,\n unnamedLabel: string,\n): ControlOption[] {\n const takenByOthers = new Set<string>();\n bindings.forEach((accountId, subjectId) => {\n if (subjectId !== subject.id && isFilled(accountId)) takenByOthers.add(accountId);\n });\n\n return accounts\n .filter((account) => !takenByOthers.has(account.userId))\n .map((account) => ({\n value: account.userId,\n label: accountDisplayLabel(account, unnamedLabel),\n }));\n}\n","/**\n * Selection state and submit orchestration for the account picker.\n *\n * Holds no JSX so the selection transitions — and, more importantly, the rules\n * about WHEN a link or unlink is allowed — are testable without a renderer.\n * Those rules are the guard rails around a destructive action: unlinking is what\n * stops a real person's work being attributed to them.\n */\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { AccessResultTone, type AccessResultReporter } from '../AccessResultTone';\nimport { ACCESS_ADMIN_I18N } from '../constants';\nimport type { AccessTranslate } from '../links/useCapabilityLinkMint';\nimport type { AccessSubject, DescribeError, LinkSubjectAccount } from '../types';\n\nexport interface UseSubjectAccountLinkOptions {\n readonly subject: AccessSubject;\n /** The account currently bound to this subject, or null when it has none. */\n readonly boundAccountId: string | null;\n readonly linkAccount: LinkSubjectAccount;\n readonly describeError: DescribeError;\n readonly onResult: AccessResultReporter;\n readonly t: AccessTranslate;\n}\n\nexport interface SubjectAccountLinkState {\n /** The account chosen in the picker, or null when none is. */\n readonly selectedAccountId: string | null;\n readonly select: (accountId: string) => void;\n readonly isPending: boolean;\n /** True when the chosen account differs from the one already bound. */\n readonly canLink: boolean;\n /** True when there is a binding to remove. */\n readonly canUnlink: boolean;\n readonly link: () => void;\n readonly unlink: () => void;\n}\n\nexport function useSubjectAccountLink(\n options: UseSubjectAccountLinkOptions,\n): SubjectAccountLinkState {\n const { subject, boundAccountId, linkAccount, describeError, onResult, t } = options;\n\n const [selectedAccountId, setSelectedAccountId] = useState<string | null>(boundAccountId);\n const [isPending, setIsPending] = useState<boolean>(false);\n\n const mountedRef = useRef<boolean>(true);\n useEffect(() => {\n mountedRef.current = true;\n return () => {\n mountedRef.current = false;\n };\n }, []);\n\n // Re-seed when the user switches to another subject, and after a write lands (the\n // host re-renders with a refreshed binding). Without this the picker would keep\n // showing the PREVIOUS subject's selection against the new subject's name.\n useEffect(() => {\n setSelectedAccountId(boundAccountId);\n }, [subject.id, boundAccountId]);\n\n const canLink = !isPending && selectedAccountId !== null && selectedAccountId !== boundAccountId;\n const canUnlink = !isPending && boundAccountId !== null;\n\n const submit = useCallback(\n (accountId: string | null, successKey: string): void => {\n setIsPending(true);\n void (async () => {\n try {\n await linkAccount(subject, accountId);\n if (!mountedRef.current) return;\n onResult(t(successKey, subject.displayName), AccessResultTone.Success);\n } catch (error) {\n if (!mountedRef.current) return;\n onResult(describeError(error as Error), AccessResultTone.Error);\n } finally {\n if (mountedRef.current) setIsPending(false);\n }\n })();\n },\n [linkAccount, subject, onResult, t, describeError],\n );\n\n const link = useCallback((): void => {\n if (!canLink || selectedAccountId === null) return;\n submit(selectedAccountId, ACCESS_ADMIN_I18N.accountLinkSuccess);\n }, [canLink, selectedAccountId, submit]);\n\n const unlink = useCallback((): void => {\n if (!canUnlink) return;\n submit(null, ACCESS_ADMIN_I18N.accountUnlinkSuccess);\n }, [canUnlink, submit]);\n\n return { selectedAccountId, select: setSelectedAccountId, isPending, canLink, canUnlink, link, unlink };\n}\n","/**\n * The account picker for ONE subject.\n *\n * Binds a subject to the account it signs in with, or removes that binding.\n * Unlinking sits behind its own press rather than being a value in the picker,\n * because a mis-tap in a list must not be able to detach someone from their work.\n *\n * The picker is the shared `SelectControl` from `@dloizides/ui-forms` rather than\n * a local one — the fleet already grew six independent select implementations\n * before that was promoted, and this is not going to be the seventh.\n */\nimport React, { useMemo } from 'react';\n\nimport { StyleSheet, Text, View } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\nimport { useUi } from '@dloizides/ui-feedback';\nimport { SelectControl } from '@dloizides/ui-forms';\n\nimport type { AccessResultReporter } from '../AccessResultTone';\nimport { buildAccountOptions } from '../accounts/accountOptions';\nimport { useSubjectAccountLink } from '../accounts/useSubjectAccountLink';\nimport { ACCESS_ADMIN_I18N, ACCESS_ADMIN_TEST_IDS } from '../constants';\nimport { useAccessAdminPalette, type AccessAdminPalette } from '../theme/useAccessAdminPalette';\nimport type { AccessSubject, DescribeError, LinkableAccount, LinkSubjectAccount } from '../types';\n\nconst SPACE_XS = 4;\nconst SPACE_SM = 8;\nconst SPACE_MD = 12;\nconst SPACE_LG = 16;\nconst FONT_SM = 12;\nconst FONT_MD = 13;\n\nexport interface AccountLinkPanelProps {\n readonly subject: AccessSubject;\n /** The account currently bound to this subject, or null. */\n readonly boundAccountId: string | null;\n /** The directory of accounts that could be bound. */\n readonly accounts: readonly LinkableAccount[];\n /**\n * Which account each subject currently holds, keyed by subject id.\n *\n * The whole map, not just this subject's: accounts already taken by ANOTHER\n * subject are hidden from the picker, because offering them can only produce a\n * uniqueness error the user cannot act on.\n */\n readonly bindings: ReadonlyMap<string, string | null>;\n readonly linkAccount: LinkSubjectAccount;\n readonly describeError: DescribeError;\n readonly onClose: () => void;\n readonly onResult: AccessResultReporter;\n /** Root testID; children derive from it. Defaults to `account-link-panel`. */\n readonly testIDPrefix?: string;\n}\n\nexport const AccountLinkPanel = ({\n subject,\n boundAccountId,\n accounts,\n bindings,\n linkAccount,\n describeError,\n onClose,\n onResult,\n testIDPrefix = ACCESS_ADMIN_TEST_IDS.accountPanel,\n}: AccountLinkPanelProps): React.ReactElement => {\n const { t } = useUi();\n const palette = useAccessAdminPalette();\n const styles = useMemo(() => buildStyles(palette), [palette]);\n\n const state = useSubjectAccountLink({\n subject,\n boundAccountId,\n linkAccount,\n describeError,\n onResult,\n t,\n });\n\n const unnamedLabel = t(ACCESS_ADMIN_I18N.accountUnnamed);\n const options = useMemo(\n () => buildAccountOptions(accounts, bindings, subject, unnamedLabel),\n [accounts, bindings, subject, unnamedLabel],\n );\n\n const selectedLabel =\n options.find((option) => option.value === state.selectedAccountId)?.label ?? '';\n\n return (\n <View style={styles.panel} testID={testIDPrefix}>\n <Text style={styles.heading}>\n {t(ACCESS_ADMIN_I18N.accountPanelHeading, subject.displayName)}\n </Text>\n <Text style={styles.note}>{t(ACCESS_ADMIN_I18N.accountPanelNote)}</Text>\n\n {options.length > 0 ? (\n <SelectControl\n // The accessible name carries the SELECTION, not just the field name —\n // \"Sign-in account: Maria K\" — because the trigger's visible text is\n // replaced by this string for a screen reader.\n accessibilityHint={t(ACCESS_ADMIN_I18N.accountPickerHint)}\n accessibilityLabel={`${t(ACCESS_ADMIN_I18N.accountPickerLabel)}: ${\n selectedLabel === '' ? t(ACCESS_ADMIN_I18N.accountPickerPlaceholder) : selectedLabel\n }`}\n onChange={state.select}\n optionHint={t(ACCESS_ADMIN_I18N.accountOptionHint)}\n options={options}\n placeholder={t(ACCESS_ADMIN_I18N.accountPickerPlaceholder)}\n testID={`${testIDPrefix}-picker`}\n value={state.selectedAccountId ?? ''}\n />\n ) : (\n <Text style={styles.note} testID={`${testIDPrefix}-no-accounts`}>\n {t(ACCESS_ADMIN_I18N.accountNone)}\n </Text>\n )}\n\n <View style={styles.actions}>\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.accountLinkHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.accountLink)}\n disabled={!state.canLink}\n label={t(ACCESS_ADMIN_I18N.accountLink)}\n loading={state.isPending}\n onPress={state.link}\n testID={`${testIDPrefix}-link`}\n />\n {state.canUnlink ? (\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.accountUnlinkHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.accountUnlink)}\n disabled={state.isPending}\n label={t(ACCESS_ADMIN_I18N.accountUnlink)}\n onPress={state.unlink}\n testID={`${testIDPrefix}-unlink`}\n variant=\"danger\"\n />\n ) : null}\n <Button\n accessibilityHint={t(ACCESS_ADMIN_I18N.accountCloseHint)}\n accessibilityLabel={t(ACCESS_ADMIN_I18N.accountClose)}\n disabled={state.isPending}\n label={t(ACCESS_ADMIN_I18N.accountClose)}\n onPress={onClose}\n testID={`${testIDPrefix}-close`}\n variant=\"secondary\"\n />\n </View>\n </View>\n );\n};\n\n/** Builds the panel styles from the live palette (re-run when the theme changes). */\nconst buildStyles = (c: AccessAdminPalette) =>\n StyleSheet.create({\n actions: { flexDirection: 'row', flexWrap: 'wrap', gap: SPACE_SM },\n heading: { color: c.textPrimary, fontSize: FONT_MD, fontWeight: '700' },\n note: { color: c.textSecondary, fontSize: FONT_SM },\n panel: {\n backgroundColor: c.panelSurface,\n borderColor: c.border,\n borderRadius: SPACE_SM,\n borderWidth: 1,\n gap: SPACE_XS,\n marginBottom: SPACE_LG,\n padding: SPACE_MD,\n },\n });\n"]}
|