uhc-portal-components-react 0.1.15 → 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,22 @@
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
+
10
+ ## 0.1.16
11
+
12
+ - Add `IdentityEvidenceDocumentPanel`, a brand-neutral signed-PDF upload and
13
+ verification surface used by PetChain, UHC UNID and SOSChain.
14
+ - Keep rendered status provider-owned: selecting or uploading a PDF never
15
+ changes pending evidence to verified in browser state.
16
+ - Add `IdentityEvidenceDeclarationForm` for governed legal-name, jurisdiction,
17
+ identifier and relationship options with one high-level preparation
18
+ callback and no session, certificate or gateway fields.
19
+
3
20
  ## 0.1.15
4
21
 
5
22
  - Add an accessible, animated `PortalLoadingSkeleton` that authenticated
@@ -27,6 +44,8 @@
27
44
 
28
45
  ## Unreleased
29
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.
30
49
  - Correct the reuse contract: the package currently provides presentation
31
50
  primitives, not the full UHC Personal route journeys. Document the extraction
32
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,
@@ -71,6 +73,13 @@ The package deliberately exposes modules instead of a cloned application:
71
73
  exact capabilities for self upload, organization-worker upload or
72
74
  professional attestation; ICA or another trusted backend verifies the
73
75
  signature after upload.
76
+ - `IdentityEvidenceDocumentPanel`: selects and uploads one signed PDF for the
77
+ chosen identity, requests trusted verification and renders only the status
78
+ returned by the provider facade. It contains no certificate or gateway
79
+ plumbing.
80
+ - `IdentityEvidenceDeclarationForm`: collects the business fields used to
81
+ prepare a declaration. Hosts supply governed options and one high-level
82
+ callback; the form never authors claims or handles certificates.
74
83
 
75
84
  Clinical label semantics stay in `gdc-common-utils-ts` / the SDK reader. Hosts
76
85
  pass human titles to `ClinicalSectionSummary`: local `CodeableConcept.text`
@@ -0,0 +1,43 @@
1
+ export type IdentityEvidenceOption = Readonly<{
2
+ value: string;
3
+ label: string;
4
+ }>;
5
+ export type IdentityEvidenceDeclarationInput = Readonly<{
6
+ fullLegalName: string;
7
+ countryCode: string;
8
+ regional: boolean;
9
+ subdivisionCode?: string;
10
+ identifierKind: string;
11
+ identifierValue: string;
12
+ controllerCapacity: string;
13
+ }>;
14
+ export type IdentityEvidenceDeclarationFormCopy = Readonly<{
15
+ title: string;
16
+ body: string;
17
+ fullLegalName: string;
18
+ country: string;
19
+ identifierKind: string;
20
+ identifierValue: string;
21
+ regional: string;
22
+ region: string;
23
+ capacity: string;
24
+ prepare: string;
25
+ preparing: string;
26
+ required: string;
27
+ }>;
28
+ /**
29
+ * Brand-neutral declaration form shared by UHC, PetChain and SOSChain.
30
+ *
31
+ * The host supplies governed options and one high-level preparation callback.
32
+ * This component neither authors resource claims nor handles certificates,
33
+ * sessions, gateway messages or verification decisions.
34
+ */
35
+ export declare function IdentityEvidenceDeclarationForm({ copy, countries, regions, identifierKinds, capacities, onPrepare, }: Readonly<{
36
+ copy: IdentityEvidenceDeclarationFormCopy;
37
+ countries: readonly IdentityEvidenceOption[];
38
+ regions: readonly IdentityEvidenceOption[];
39
+ identifierKinds: readonly IdentityEvidenceOption[];
40
+ capacities: readonly IdentityEvidenceOption[];
41
+ onPrepare: (input: IdentityEvidenceDeclarationInput) => Promise<void>;
42
+ }>): import("react").JSX.Element;
43
+ //# sourceMappingURL=IdentityEvidenceDeclarationForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdentityEvidenceDeclarationForm.d.ts","sourceRoot":"","sources":["../src/IdentityEvidenceDeclarationForm.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAE/E,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC;IACtD,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,OAAO,CAAA;IACjB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAC,CAAA;AAEF,MAAM,MAAM,mCAAmC,GAAG,QAAQ,CAAC;IACzD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,wBAAgB,+BAA+B,CAAC,EAC9C,IAAI,EACJ,SAAS,EACT,OAAO,EACP,eAAe,EACf,UAAU,EACV,SAAS,GACV,EAAE,QAAQ,CAAC;IACV,IAAI,EAAE,mCAAmC,CAAA;IACzC,SAAS,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC5C,OAAO,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC1C,eAAe,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAClD,UAAU,EAAE,SAAS,sBAAsB,EAAE,CAAA;IAC7C,SAAS,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CACtE,CAAC,+BA+CD"}
@@ -0,0 +1,47 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ /**
4
+ * Brand-neutral declaration form shared by UHC, PetChain and SOSChain.
5
+ *
6
+ * The host supplies governed options and one high-level preparation callback.
7
+ * This component neither authors resource claims nor handles certificates,
8
+ * sessions, gateway messages or verification decisions.
9
+ */
10
+ export function IdentityEvidenceDeclarationForm({ copy, countries, regions, identifierKinds, capacities, onPrepare, }) {
11
+ const [fullLegalName, setFullLegalName] = useState('');
12
+ const [identifierValue, setIdentifierValue] = useState('');
13
+ const [countryCode, setCountryCode] = useState(countries[0]?.value || '');
14
+ const [identifierKind, setIdentifierKind] = useState(identifierKinds[0]?.value || '');
15
+ const [controllerCapacity, setControllerCapacity] = useState(capacities[0]?.value || '');
16
+ const [regional, setRegional] = useState(false);
17
+ const [subdivisionCode, setSubdivisionCode] = useState('');
18
+ const [busy, setBusy] = useState(false);
19
+ const [error, setError] = useState('');
20
+ async function prepare() {
21
+ if (!fullLegalName.trim() || !identifierValue.trim() || !countryCode || !identifierKind || !controllerCapacity || (regional && !subdivisionCode)) {
22
+ setError(copy.required);
23
+ return;
24
+ }
25
+ setBusy(true);
26
+ setError('');
27
+ try {
28
+ await onPrepare({
29
+ fullLegalName: fullLegalName.trim(),
30
+ countryCode,
31
+ regional,
32
+ ...(regional ? { subdivisionCode } : {}),
33
+ identifierKind,
34
+ identifierValue: identifierValue.trim(),
35
+ controllerCapacity,
36
+ });
37
+ }
38
+ finally {
39
+ setBusy(false);
40
+ }
41
+ }
42
+ return _jsxs("section", { className: "uhcp-identity-declaration", "aria-labelledby": "identity-declaration-form-title", children: [_jsxs("header", { children: [_jsx("h3", { id: "identity-declaration-form-title", children: copy.title }), _jsx("p", { children: copy.body })] }), _jsxs("div", { className: "uhcp-identity-declaration-fields", children: [_jsxs("label", { children: [copy.fullLegalName, _jsx("input", { value: fullLegalName, onChange: (event) => setFullLegalName(event.target.value) })] }), _jsxs("label", { children: [copy.country, _jsx("select", { value: countryCode, onChange: (event) => setCountryCode(event.target.value), children: options(countries) })] }), _jsxs("label", { children: [copy.identifierKind, _jsx("select", { value: identifierKind, onChange: (event) => setIdentifierKind(event.target.value), children: options(identifierKinds) })] }), _jsxs("label", { children: [copy.identifierValue, _jsx("input", { value: identifierValue, onChange: (event) => setIdentifierValue(event.target.value) })] }), _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: regional, onChange: (event) => { setRegional(event.target.checked); if (!event.target.checked)
43
+ setSubdivisionCode(''); } }), copy.regional] }), _jsxs("label", { children: [copy.region, _jsxs("select", { value: subdivisionCode, disabled: !regional, onChange: (event) => setSubdivisionCode(event.target.value), children: [_jsx("option", { value: "" }), options(regions)] })] }), _jsxs("label", { children: [copy.capacity, _jsx("select", { value: controllerCapacity, onChange: (event) => setControllerCapacity(event.target.value), children: options(capacities) })] })] }), error ? _jsx("p", { role: "alert", children: error }) : null, _jsx("button", { type: "button", onClick: () => void prepare(), disabled: busy, children: busy ? copy.preparing : copy.prepare })] });
44
+ }
45
+ function options(values) {
46
+ return values.map((option) => _jsx("option", { value: option.value, children: option.label }, option.value));
47
+ }
@@ -0,0 +1,34 @@
1
+ import type { IdentityEvidenceIdentifier, IdentityEvidenceStatus } from './IdentityEvidenceWorkspace.js';
2
+ export type IdentityEvidenceDocument = Readonly<{
3
+ id: string;
4
+ fileName: string;
5
+ status: IdentityEvidenceStatus;
6
+ }>;
7
+ export type IdentityEvidenceDocumentPanelCopy = Readonly<{
8
+ title: string;
9
+ body: string;
10
+ choosePdf: string;
11
+ upload: string;
12
+ uploading: string;
13
+ verify: string;
14
+ verifying: string;
15
+ noDocument: string;
16
+ invalidPdf: string;
17
+ statusLabels: Readonly<Record<IdentityEvidenceStatus, string>>;
18
+ }>;
19
+ /**
20
+ * Reusable signed-document panel for UHC, PetChain and SOSChain.
21
+ *
22
+ * The component only chooses a PDF and calls the host's high-level methods.
23
+ * It never parses certificates, builds gateway claims or promotes a local
24
+ * digest to verified evidence. The rendered status always comes from provider
25
+ * readback through `documents`.
26
+ */
27
+ export declare function IdentityEvidenceDocumentPanel({ copy, selectedIdentifier, documents, onUpload, onVerifySignaturePdf, }: Readonly<{
28
+ copy: IdentityEvidenceDocumentPanelCopy;
29
+ selectedIdentifier?: IdentityEvidenceIdentifier;
30
+ documents: readonly IdentityEvidenceDocument[];
31
+ onUpload: (controllerIdentifierId: string, pdf: File) => Promise<void>;
32
+ onVerifySignaturePdf: (evidenceId: string) => Promise<void>;
33
+ }>): import("react").JSX.Element;
34
+ //# sourceMappingURL=IdentityEvidenceDocumentPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdentityEvidenceDocumentPanel.d.ts","sourceRoot":"","sources":["../src/IdentityEvidenceDocumentPanel.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,0BAA0B,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAA;AAExG,MAAM,MAAM,wBAAwB,GAAG,QAAQ,CAAC;IAC9C,EAAE,EAAE,MAAM,CAAA;IACV,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,sBAAsB,CAAA;CAC/B,CAAC,CAAA;AAEF,MAAM,MAAM,iCAAiC,GAAG,QAAQ,CAAC;IACvD,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,sBAAsB,EAAE,MAAM,CAAC,CAAC,CAAA;CAC/D,CAAC,CAAA;AAEF;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,CAAC,EAC5C,IAAI,EACJ,kBAAkB,EAClB,SAAS,EACT,QAAQ,EACR,oBAAoB,GACrB,EAAE,QAAQ,CAAC;IACV,IAAI,EAAE,iCAAiC,CAAA;IACvC,kBAAkB,CAAC,EAAE,0BAA0B,CAAA;IAC/C,SAAS,EAAE,SAAS,wBAAwB,EAAE,CAAA;IAC9C,QAAQ,EAAE,CAAC,sBAAsB,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACtE,oBAAoB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;CAC5D,CAAC,+BAgED"}
@@ -0,0 +1,40 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ /**
4
+ * Reusable signed-document panel for UHC, PetChain and SOSChain.
5
+ *
6
+ * The component only chooses a PDF and calls the host's high-level methods.
7
+ * It never parses certificates, builds gateway claims or promotes a local
8
+ * digest to verified evidence. The rendered status always comes from provider
9
+ * readback through `documents`.
10
+ */
11
+ export function IdentityEvidenceDocumentPanel({ copy, selectedIdentifier, documents, onUpload, onVerifySignaturePdf, }) {
12
+ const [file, setFile] = useState();
13
+ const [busy, setBusy] = useState();
14
+ const [error, setError] = useState('');
15
+ async function upload() {
16
+ if (!selectedIdentifier || !file || file.type !== 'application/pdf') {
17
+ setError(copy.invalidPdf);
18
+ return;
19
+ }
20
+ setBusy('upload');
21
+ setError('');
22
+ try {
23
+ await onUpload(selectedIdentifier.id, file);
24
+ }
25
+ finally {
26
+ setBusy(undefined);
27
+ }
28
+ }
29
+ async function verify(evidenceId) {
30
+ setBusy('verify');
31
+ setError('');
32
+ try {
33
+ await onVerifySignaturePdf(evidenceId);
34
+ }
35
+ finally {
36
+ setBusy(undefined);
37
+ }
38
+ }
39
+ return (_jsxs("section", { className: "uhcp-identity-documents", "aria-labelledby": "identity-evidence-documents-title", children: [_jsxs("header", { children: [_jsx("h3", { id: "identity-evidence-documents-title", children: copy.title }), _jsx("p", { children: copy.body })] }), _jsxs("label", { children: [_jsx("span", { children: copy.choosePdf }), _jsx("input", { type: "file", accept: "application/pdf,.pdf", "aria-label": copy.choosePdf, onChange: (event) => setFile(event.target.files?.[0]) })] }), _jsx("button", { type: "button", onClick: () => void upload(), disabled: busy !== undefined || !selectedIdentifier, children: busy === 'upload' ? copy.uploading : copy.upload }), error ? _jsx("p", { role: "alert", children: error }) : null, documents.length ? (_jsx("ul", { children: documents.map((document) => (_jsxs("li", { children: [_jsxs("span", { children: [_jsx("strong", { children: document.fileName }), _jsx("small", { children: copy.statusLabels[document.status] })] }), document.status === 'pending' ? (_jsx("button", { type: "button", onClick: () => void verify(document.id), disabled: busy !== undefined, children: busy === 'verify' ? copy.verifying : copy.verify })) : null] }, document.id))) })) : _jsx("p", { children: copy.noDocument })] }));
40
+ }
@@ -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/dist/index.d.ts CHANGED
@@ -16,4 +16,6 @@ export * from './ProtectedIndexEmergencyData.js';
16
16
  export * from './PortalSettingsPanel.js';
17
17
  export * from './LegalMarkdownDocument.js';
18
18
  export * from './IdentityEvidenceWorkspace.js';
19
+ export * from './IdentityEvidenceDocumentPanel.js';
20
+ export * from './IdentityEvidenceDeclarationForm.js';
19
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,0CAA0C,CAAA;AACxD,cAAc,kCAAkC,CAAA;AAChD,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gCAAgC,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,yBAAyB,CAAA;AACvC,cAAc,mBAAmB,CAAA;AACjC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,0CAA0C,CAAA;AACxD,cAAc,kCAAkC,CAAA;AAChD,cAAc,0BAA0B,CAAA;AACxC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,oCAAoC,CAAA;AAClD,cAAc,sCAAsC,CAAA"}
package/dist/index.js CHANGED
@@ -16,3 +16,5 @@ export * from './ProtectedIndexEmergencyData.js';
16
16
  export * from './PortalSettingsPanel.js';
17
17
  export * from './LegalMarkdownDocument.js';
18
18
  export * from './IdentityEvidenceWorkspace.js';
19
+ export * from './IdentityEvidenceDocumentPanel.js';
20
+ export * from './IdentityEvidenceDeclarationForm.js';
package/dist/styles.css CHANGED
@@ -277,8 +277,29 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
277
277
  .uhcp-identity-upload-action:hover { border-color: var(--uhcp-turquoise); }
278
278
  .uhcp-identity-upload-action:disabled { cursor: not-allowed; opacity: .6; }
279
279
  .uhcp-identity-upload-action small { color: var(--uhcp-muted); line-height: 1.45; }
280
+ .uhcp-identity-documents { background: var(--uhcp-panel); border: 1px solid var(--uhcp-border); border-radius: 1.5rem; color: var(--uhcp-text); display: grid; gap: 1rem; padding: 1.25rem; }
281
+ .uhcp-identity-documents h3, .uhcp-identity-documents p { margin: 0; }
282
+ .uhcp-identity-documents header p, .uhcp-identity-documents small { color: var(--uhcp-muted); }
283
+ .uhcp-identity-documents label { display: grid; font-weight: 800; gap: .5rem; }
284
+ .uhcp-identity-documents input { border: 1px solid var(--uhcp-border); border-radius: .85rem; color: var(--uhcp-text); padding: .75rem; }
285
+ .uhcp-identity-documents > button, .uhcp-identity-documents li button { background: linear-gradient(135deg, var(--uhcp-action-start), var(--uhcp-action-end)); border: 0; border-radius: .85rem; color: #fff; cursor: pointer; font: inherit; font-weight: 800; min-height: 2.75rem; padding: .65rem 1rem; }
286
+ .uhcp-identity-documents button:disabled { cursor: not-allowed; opacity: .55; }
287
+ .uhcp-identity-documents ul { display: grid; gap: .65rem; list-style: none; margin: 0; padding: 0; }
288
+ .uhcp-identity-documents li { align-items: center; background: var(--uhcp-panel-muted); border-radius: 1rem; display: flex; gap: 1rem; justify-content: space-between; padding: .85rem; }
289
+ .uhcp-identity-documents li span { display: grid; gap: .25rem; }
290
+ .uhcp-identity-documents [role='alert'] { color: #c64747; font-weight: 800; }
291
+ .uhcp-identity-declaration { background: var(--uhcp-panel); border: 1px solid var(--uhcp-border); border-radius: 1.5rem; color: var(--uhcp-text); display: grid; gap: 1rem; padding: 1.25rem; }
292
+ .uhcp-identity-declaration h3, .uhcp-identity-declaration p { margin: 0; }
293
+ .uhcp-identity-declaration header p { color: var(--uhcp-muted); line-height: 1.55; margin-top: .4rem; }
294
+ .uhcp-identity-declaration-fields { display: grid; gap: 1rem; }
295
+ .uhcp-identity-declaration label { display: grid; font-weight: 800; gap: .5rem; }
296
+ .uhcp-identity-declaration label:has(input[type='checkbox']) { align-items: center; display: flex; }
297
+ .uhcp-identity-declaration input:not([type='checkbox']), .uhcp-identity-declaration select { background: var(--uhcp-panel); border: 1px solid var(--uhcp-border); border-radius: .85rem; color: var(--uhcp-text); font: inherit; min-height: 2.75rem; padding: .7rem .8rem; }
298
+ .uhcp-identity-declaration > button { background: linear-gradient(135deg, var(--uhcp-action-start), var(--uhcp-action-end)); border: 0; border-radius: .85rem; color: #fff; cursor: pointer; font: inherit; font-weight: 800; min-height: 2.75rem; padding: .65rem 1rem; }
299
+ .uhcp-identity-declaration [role='alert'] { color: #c64747; font-weight: 800; }
280
300
  @media (min-width: 760px) {
281
301
  .uhcp-identity-upload-actions { grid-template-columns: repeat(2, minmax(0, 1fr)); }
302
+ .uhcp-identity-declaration-fields { grid-template-columns: repeat(2, minmax(0, 1fr)); }
282
303
  }
283
304
 
284
305
  .uhcp-clinical-summary {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.1.15",
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",