uhc-portal-components-react 0.1.16 → 0.1.17

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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.17
4
+
5
+ - Add provider-enabled microchip, tattoo, email and telephone subject locator
6
+ kinds without exposing any locator that the owning BFF has not enabled.
7
+ - Carry server-returned identifier evidence as presentation-only metadata and
8
+ add suitable browser input hints for ISO animal microchips and contacts.
9
+
3
10
  ## 0.1.16
4
11
 
5
12
  - Add `IdentityEvidenceDocumentPanel`, a brand-neutral signed-PDF upload and
@@ -37,6 +44,8 @@
37
44
 
38
45
  ## Unreleased
39
46
 
47
+ - Add the repository-wide mandatory red-green-refactor contributor contract
48
+ and mark the existing component suites with an explicit TDD contract header.
40
49
  - Correct the reuse contract: the package currently provides presentation
41
50
  primitives, not the full UHC Personal route journeys. Document the extraction
42
51
  required before PetChain can reuse login, protected profiles, individuals,
package/README.md CHANGED
@@ -56,7 +56,9 @@ The package deliberately exposes modules instead of a cloned application:
56
56
  - `InvitationAcceptancePanel`: controlled invitation-code UI for a related
57
57
  individual member; the host refreshes the authorized-subject list after its
58
58
  BFF accepts the invitation.
59
- - `SubjectAccessRequestPanel`: controlled QR, numeric-code or `did:web`
59
+ - `SubjectAccessRequestPanel`: controlled provider-enabled QR, numeric-code,
60
+ `did:web`, microchip, tattoo, email or telephone locator. Resolution and
61
+ returned identifier evidence never grant subject access.
60
62
  resolver plus section selector. It deliberately has no scanner role: the
61
63
  same component is reusable by an individual member or a professional.
62
64
  - `SoschainWorkspace`: subject-card picker and four-area workspace for Places,
@@ -1,4 +1,4 @@
1
- export type SubjectLocatorKind = 'qr' | 'numeric-code' | 'did-web';
1
+ export type SubjectLocatorKind = 'qr' | 'numeric-code' | 'did-web' | 'microchip' | 'tattoo' | 'email-address' | 'phone-number';
2
2
  export type SubjectAccessRequestStatus = 'idle' | 'resolving' | 'resolved' | 'requesting' | 'requested' | 'granted' | 'error';
3
3
  export type SubjectAccessSectionOption = Readonly<{
4
4
  code: string;
@@ -8,12 +8,20 @@ export type SubjectAccessSectionOption = Readonly<{
8
8
  export type ResolvedSubjectAccessTarget = Readonly<{
9
9
  subjectId: string;
10
10
  display: string;
11
+ /** Server-returned evidence for presentation only; it grants no access. */
12
+ identifiers?: readonly Readonly<{
13
+ kind: SubjectLocatorKind;
14
+ system: string;
15
+ value: string;
16
+ attested: boolean;
17
+ }>[];
11
18
  }>;
12
19
  export type SubjectAccessRequestPanelCopy = Readonly<{
13
20
  title: string;
14
21
  description: string;
15
22
  locatorKindLabel: string;
16
- locatorKinds: Record<SubjectLocatorKind, string>;
23
+ /** Only entries authorized and supported by the owning product are shown. */
24
+ locatorKinds: Partial<Record<SubjectLocatorKind, string>>;
17
25
  locatorLabel: string;
18
26
  resolve: string;
19
27
  resolving: string;
@@ -1 +1 @@
1
- {"version":3,"file":"SubjectAccessRequestPanel.d.ts","sourceRoot":"","sources":["../src/SubjectAccessRequestPanel.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAAG,IAAI,GAAG,cAAc,GAAG,SAAS,CAAA;AAClE,MAAM,MAAM,0BAA0B,GAClC,MAAM,GACN,WAAW,GACX,UAAU,GACV,YAAY,GACZ,WAAW,GACX,SAAS,GACT,OAAO,CAAA;AAEX,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAC,CAAA;AAEF,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IACjD,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAC,CAAA;AAEF,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAA;IAChD,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAC,CAAA;AAEF,MAAM,MAAM,8BAA8B,GAAG,QAAQ,CAAC;IACpD,IAAI,EAAE,6BAA6B,CAAA;IACnC,WAAW,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,0BAA0B,CAAA;IAClC,MAAM,CAAC,EAAE,2BAA2B,CAAA;IACpC,QAAQ,EAAE,SAAS,0BAA0B,EAAE,CAAA;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACvD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,IAAI,EACJ,WAAW,EACX,OAAO,EACP,MAAM,EACN,MAAM,EACN,QAAQ,EACR,KAAK,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,eAAe,EACf,SAAS,GACV,EAAE,8BAA8B,+BA4EhC"}
1
+ {"version":3,"file":"SubjectAccessRequestPanel.d.ts","sourceRoot":"","sources":["../src/SubjectAccessRequestPanel.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,kBAAkB,GAC1B,IAAI,GACJ,cAAc,GACd,SAAS,GACT,WAAW,GACX,QAAQ,GACR,eAAe,GACf,cAAc,CAAA;AAClB,MAAM,MAAM,0BAA0B,GAClC,MAAM,GACN,WAAW,GACX,UAAU,GACV,YAAY,GACZ,WAAW,GACX,SAAS,GACT,OAAO,CAAA;AAEX,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,OAAO,CAAA;CAClB,CAAC,CAAA;AAEF,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IACjD,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;IACf,2EAA2E;IAC3E,WAAW,CAAC,EAAE,SAAS,QAAQ,CAAC;QAC9B,IAAI,EAAE,kBAAkB,CAAA;QACxB,MAAM,EAAE,MAAM,CAAA;QACd,KAAK,EAAE,MAAM,CAAA;QACb,QAAQ,EAAE,OAAO,CAAA;KAClB,CAAC,EAAE,CAAA;CACL,CAAC,CAAA;AAEF,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,gBAAgB,EAAE,MAAM,CAAA;IACxB,6EAA6E;IAC7E,YAAY,EAAE,OAAO,CAAC,MAAM,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC,CAAA;IACzD,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,MAAM,CAAA;CAChB,CAAC,CAAA;AAEF,MAAM,MAAM,8BAA8B,GAAG,QAAQ,CAAC;IACpD,IAAI,EAAE,6BAA6B,CAAA;IACnC,WAAW,EAAE,kBAAkB,CAAA;IAC/B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,0BAA0B,CAAA;IAClC,MAAM,CAAC,EAAE,2BAA2B,CAAA;IACpC,QAAQ,EAAE,SAAS,0BAA0B,EAAE,CAAA;IAC/C,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,mBAAmB,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAA;IACvD,eAAe,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;IAC1C,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IACrC,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACvC,SAAS,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACtC,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,IAAI,EACJ,WAAW,EACX,OAAO,EACP,MAAM,EACN,MAAM,EACN,QAAQ,EACR,KAAK,EACL,mBAAmB,EACnB,eAAe,EACf,SAAS,EACT,eAAe,EACf,SAAS,GACV,EAAE,8BAA8B,+BAgFhC"}
@@ -7,6 +7,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
7
7
  * component; the authenticated BFF and GW decide identity and authorization.
8
8
  */
9
9
  export function SubjectAccessRequestPanel({ copy, locatorKind, locator, status, target, sections, error, onLocatorKindChange, onLocatorChange, onResolve, onToggleSection, onRequest, }) {
10
+ const locatorInput = locatorInputAttributes(locatorKind);
10
11
  function resolve(event) {
11
12
  event.preventDefault();
12
13
  void onResolve();
@@ -15,7 +16,18 @@ export function SubjectAccessRequestPanel({ copy, locatorKind, locator, status,
15
16
  event.preventDefault();
16
17
  void onRequest();
17
18
  }
18
- return (_jsxs("section", { className: "uhcp-access-panel", "aria-labelledby": "uhcp-access-request-title", children: [_jsx("h2", { id: "uhcp-access-request-title", children: copy.title }), _jsx("p", { children: copy.description }), _jsxs("form", { onSubmit: resolve, children: [_jsxs("label", { children: [_jsx("span", { children: copy.locatorKindLabel }), _jsx("select", { value: locatorKind, onChange: (event) => onLocatorKindChange(event.currentTarget.value), disabled: status === 'resolving', children: Object.entries(copy.locatorKinds).map(([kind, label]) => _jsx("option", { value: kind, children: label }, kind)) })] }), _jsxs("label", { children: [_jsx("span", { children: copy.locatorLabel }), _jsx("input", { value: locator, onChange: (event) => onLocatorChange(event.currentTarget.value), required: true, disabled: status === 'resolving' })] }), _jsx("button", { type: "submit", disabled: status === 'resolving' || !locator.trim(), children: status === 'resolving' ? copy.resolving : copy.resolve })] }), target && (_jsxs("form", { onSubmit: request, children: [_jsx("p", { children: _jsx("bdi", { children: target.display }) }), _jsxs("fieldset", { children: [_jsx("legend", { children: copy.sectionsLabel }), sections.map((section) => (_jsxs("label", { "data-section-code": section.code, children: [_jsx("input", { type: "checkbox", checked: section.selected, onChange: () => onToggleSection(section.code), disabled: status === 'requesting' || status === 'granted' }), _jsx("span", { children: section.label })] }, section.code)))] }), _jsx("button", { type: "submit", disabled: status === 'requesting'
19
+ return (_jsxs("section", { className: "uhcp-access-panel", "aria-labelledby": "uhcp-access-request-title", children: [_jsx("h2", { id: "uhcp-access-request-title", children: copy.title }), _jsx("p", { children: copy.description }), _jsxs("form", { onSubmit: resolve, children: [_jsxs("label", { children: [_jsx("span", { children: copy.locatorKindLabel }), _jsx("select", { value: locatorKind, onChange: (event) => onLocatorKindChange(event.currentTarget.value), disabled: status === 'resolving', children: Object.entries(copy.locatorKinds).map(([kind, label]) => _jsx("option", { value: kind, children: label }, kind)) })] }), _jsxs("label", { children: [_jsx("span", { children: copy.locatorLabel }), _jsx("input", { value: locator, onChange: (event) => onLocatorChange(event.currentTarget.value), type: locatorInput.type, inputMode: locatorInput.inputMode, pattern: locatorInput.pattern, required: true, disabled: status === 'resolving' })] }), _jsx("button", { type: "submit", disabled: status === 'resolving' || !locator.trim(), children: status === 'resolving' ? copy.resolving : copy.resolve })] }), target && (_jsxs("form", { onSubmit: request, children: [_jsx("p", { children: _jsx("bdi", { children: target.display }) }), _jsxs("fieldset", { children: [_jsx("legend", { children: copy.sectionsLabel }), sections.map((section) => (_jsxs("label", { "data-section-code": section.code, children: [_jsx("input", { type: "checkbox", checked: section.selected, onChange: () => onToggleSection(section.code), disabled: status === 'requesting' || status === 'granted' }), _jsx("span", { children: section.label })] }, section.code)))] }), _jsx("button", { type: "submit", disabled: status === 'requesting'
19
20
  || status === 'granted'
20
21
  || !sections.some((section) => section.selected), children: status === 'requesting' ? copy.requesting : copy.request })] })), status === 'requested' && _jsx("p", { role: "status", children: copy.requested }), status === 'granted' && _jsx("p", { role: "status", children: copy.granted }), error && _jsx("p", { role: "alert", children: error })] }));
21
22
  }
23
+ function locatorInputAttributes(kind) {
24
+ if (kind === 'microchip')
25
+ return { inputMode: 'numeric', pattern: '[0-9 -]{15,21}' };
26
+ if (kind === 'numeric-code')
27
+ return { inputMode: 'numeric' };
28
+ if (kind === 'email-address')
29
+ return { type: 'email', inputMode: 'email' };
30
+ if (kind === 'phone-number')
31
+ return { type: 'tel', inputMode: 'tel' };
32
+ return {};
33
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.1.16",
3
+ "version": "0.1.17",
4
4
  "description": "Brand-neutral React portal shell, account preferences and protected-profile UI for UHC and VetChain portals.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",