uhc-portal-components-react 0.2.8 → 0.2.9

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,14 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.2.9 - 2026-10-10
4
+
5
+ - Add one reusable identity entity editor for animal controllers and related
6
+ parties, with a fixed responsible-party relationship for the controller and
7
+ host-governed relationship choices for additional entities.
8
+ - Keep identity evidence inside the entity it supports and keep the regional
9
+ identifier control in a stable layout while enabling its region only when
10
+ applicable.
11
+
3
12
  ## 0.2.8 - 2026-10-10
4
13
 
5
14
  - Restore the visual animal-photo picker from the earlier VetChain Expo flow:
@@ -8,6 +8,7 @@ export type AnimalIdentityOnboardingV2Copy = AnimalIdentityOnboardingCopy & Read
8
8
  photoTooLarge: string;
9
9
  photoDimensionsInvalid: string;
10
10
  ownerKind: string;
11
+ responsibleParty?: string;
11
12
  personOwner: string;
12
13
  organizationOwner: string;
13
14
  regionalIdentifier: string;
@@ -1 +1 @@
1
- {"version":3,"file":"AnimalIdentityOnboardingV2.d.ts","sourceRoot":"","sources":["../src/AnimalIdentityOnboardingV2.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,+BAA+B,CAAA;AAEtC,MAAM,MAAM,8BAA8B,GAAG,4BAA4B,GAAG,QAAQ,CAAC;IACnF,+BAA+B,EAAE,MAAM,CAAA;IACvC,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAC,CAAA;AAEF,KAAK,YAAY,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAG9D;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAmB,EAAE,cAAmB,EAAE,sBAA2B,EAAE,qBAAqB,EAAE,UAAiB,EAAE,IAAY,EAAE,EAAE,QAAQ,CAAC;IACnN,IAAI,EAAE,8BAA8B,CAAA;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,SAAS,QAAQ,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IAC3E,cAAc,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IACxC,sBAAsB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAA;IAC1E,qBAAqB,CAAC,EAAE,QAAQ,CAAC;QAAE,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;QAAC,YAAY,EAAE,SAAS,YAAY,EAAE,CAAA;KAAE,CAAC,CAAA;IAC5G,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAC,+BAkJD"}
1
+ {"version":3,"file":"AnimalIdentityOnboardingV2.d.ts","sourceRoot":"","sources":["../src/AnimalIdentityOnboardingV2.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,4BAA4B,EAC5B,6BAA6B,EAC9B,MAAM,+BAA+B,CAAA;AAGtC,MAAM,MAAM,8BAA8B,GAAG,4BAA4B,GAAG,QAAQ,CAAC;IACnF,+BAA+B,EAAE,MAAM,CAAA;IACvC,aAAa,EAAE,MAAM,CAAA;IACrB,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,EAAE,MAAM,CAAA;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,aAAa,EAAE,MAAM,CAAA;IACrB,sBAAsB,EAAE,MAAM,CAAA;IAC9B,SAAS,EAAE,MAAM,CAAA;IACjB,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB,EAAE,MAAM,CAAA;IACzB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,eAAe,EAAE,MAAM,CAAA;IACvB,mBAAmB,EAAE,MAAM,CAAA;IAC3B,eAAe,EAAE,MAAM,CAAA;IACvB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;CAC3B,CAAC,CAAA;AAEF,KAAK,YAAY,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAG9D;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAmB,EAAE,cAAmB,EAAE,sBAA2B,EAAE,qBAAqB,EAAE,UAAiB,EAAE,IAAY,EAAE,EAAE,QAAQ,CAAC;IACnN,IAAI,EAAE,8BAA8B,CAAA;IACpC,QAAQ,EAAE,CAAC,KAAK,EAAE,6BAA6B,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACxE,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,cAAc,CAAC,EAAE,SAAS,QAAQ,CAAC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAA;IAC3E,cAAc,CAAC,EAAE,SAAS,YAAY,EAAE,CAAA;IACxC,sBAAsB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC,CAAC,CAAA;IAC1E,qBAAqB,CAAC,EAAE,QAAQ,CAAC;QAAE,MAAM,EAAE,SAAS,YAAY,EAAE,CAAC;QAAC,YAAY,EAAE,SAAS,YAAY,EAAE,CAAA;KAAE,CAAC,CAAA;IAC5G,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,IAAI,CAAC,EAAE,OAAO,CAAA;CACf,CAAC,+BAmID"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useState } from 'react';
3
+ import { IdentityEntityEditorV2 } from './IdentityEntityEditorV2.js';
3
4
  const MAX_ANIMAL_PHOTO_BYTES = 2 * 1024 * 1024;
4
5
  /**
5
6
  * Progressive animal onboarding presentation. It preserves the V1 payload so
@@ -12,9 +13,6 @@ export function AnimalIdentityOnboardingV2({ copy, onSubmit, submitAction, speci
12
13
  const [animalDocument, setAnimalDocument] = useState();
13
14
  const [photoError, setPhotoError] = useState('');
14
15
  const [contactError, setContactError] = useState('');
15
- const [controllerKind, setControllerKind] = useState('person');
16
- const [controllerCountry, setControllerCountry] = useState(countryOptions[0]?.value || '');
17
- const [regionalIdentifier, setRegionalIdentifier] = useState(false);
18
16
  useEffect(() => () => {
19
17
  if (previewUrl.startsWith('blob:'))
20
18
  URL.revokeObjectURL(previewUrl);
@@ -83,7 +81,7 @@ export function AnimalIdentityOnboardingV2({ copy, onSubmit, submitAction, speci
83
81
  controllerIdentifierType: requiredText(form, 'controllerIdentifierType'),
84
82
  controllerIdentifierValue: requiredText(form, 'controllerIdentifierValue'),
85
83
  controllerCountry: requiredText(form, 'controllerCountry').toUpperCase(),
86
- controllerKind,
84
+ controllerKind: requiredText(form, 'controllerKind'),
87
85
  controllerRegion: optionalText(form, 'controllerRegion'),
88
86
  controllerEmail,
89
87
  controllerTelephone,
@@ -104,7 +102,17 @@ export function AnimalIdentityOnboardingV2({ copy, onSubmit, submitAction, speci
104
102
  ? _jsx("img", { src: previewUrl, alt: copy.animalPreview.replace('{name}', animalName || copy.animalName) })
105
103
  : _jsx("span", { "aria-hidden": "true", children: "\uFF0B" }), _jsx("input", { name: "animalDocument", type: "file", accept: "image/jpeg,image/png", required: !animalDocument, "aria-label": copy.addAnimalPhoto, onChange: event => void previewAnimal(event.currentTarget.files?.[0]) })] }), previewUrl ? _jsx("button", { type: "button", className: "uhcp-animal-photo-remove", "aria-label": copy.removeAnimalPhoto, title: copy.removeAnimalPhoto, onClick: removeAnimalPhoto, children: "\u00D7" }) : null, _jsx("small", { children: copy.photoHelp }), photoError ? _jsx("p", { role: "alert", children: photoError }) : null] }), _jsxs("div", { className: "uhcp-animal-onboarding-fields", children: [_jsxs("label", { children: [copy.animalName, _jsx("input", { name: "animalName", required: true, maxLength: 80, value: animalName, onChange: event => setAnimalName(event.currentTarget.value) })] }), _jsxs("label", { children: [copy.taxonomyId, speciesOptions.length > 0
106
104
  ? _jsx("select", { name: "taxonomyId", required: true, defaultValue: speciesOptions[0]?.taxonomyId, children: speciesOptions.map(option => _jsx("option", { value: option.taxonomyId, children: option.label }, option.taxonomyId)) })
107
- : _jsx("input", { name: "taxonomyId", required: true, inputMode: "numeric", pattern: "[1-9][0-9]{0,6}", defaultValue: "9615" })] }), _jsxs("label", { children: [copy.birthDate, _jsx("input", { name: "birthDate", type: "date" })] }), _jsxs("label", { children: [copy.sex, _jsxs("select", { name: "sex", defaultValue: "unknown", children: [_jsx("option", { value: "unknown", children: copy.sexUnknown }), _jsx("option", { value: "female", children: copy.sexFemale }), _jsx("option", { value: "male", children: copy.sexMale }), _jsx("option", { value: "other", children: copy.sexOther })] })] }), _jsxs("label", { children: [copy.identifierSystem, _jsxs("select", { name: "identifierSystem", defaultValue: "urn:iso:std:iso:11784:11785", children: [_jsx("option", { value: "urn:iso:std:iso:11784:11785", children: "ISO 11784/11785" }), _jsx("option", { value: "https://europa.eu/pet-passport", children: "EU pet passport" }), _jsx("option", { value: "https://vetchain.app/identifier/tattoo", children: "Tattoo" })] })] }), _jsxs("label", { children: [copy.identifierValue, _jsx("input", { name: "identifierValue", required: true, maxLength: 80, autoComplete: "off" })] })] })] })] }), _jsxs("details", { "aria-labelledby": "animal-onboarding-v2-controller-step", children: [_jsxs("summary", { id: "animal-onboarding-v2-controller-step", children: [_jsx(StepNumber, { value: 2 }), " ", copy.controllerStep] }), _jsxs("div", { className: "uhcp-animal-onboarding-fields", children: [_jsxs("fieldset", { className: "uhcp-animal-owner-kind", children: [_jsx("legend", { children: copy.ownerKind }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "controllerKind", value: "person", checked: controllerKind === 'person', onChange: () => setControllerKind('person') }), " ", copy.personOwner] }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "controllerKind", value: "organization", checked: controllerKind === 'organization', onChange: () => setControllerKind('organization') }), " ", copy.organizationOwner] })] }), _jsxs("label", { className: "uhcp-animal-owner-name", children: [copy.controllerLegalName, _jsx("input", { name: "controllerLegalName", required: true, maxLength: 160, autoComplete: controllerKind === 'person' ? 'name' : 'organization' })] }), _jsxs("label", { children: [copy.controllerCountry, countryOptions.length ? _jsx("select", { name: "controllerCountry", required: true, value: controllerCountry, onChange: event => { setControllerCountry(event.currentTarget.value); setRegionalIdentifier(false); }, children: countryOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) }) : _jsx("input", { name: "controllerCountry", required: true, pattern: "[A-Za-z]{2}", maxLength: 2, autoComplete: "country", onChange: event => setControllerCountry(event.currentTarget.value.toUpperCase()) })] }), _jsxs("label", { className: "uhcp-animal-regional-identifier", children: [_jsx("input", { type: "checkbox", checked: regionalIdentifier, disabled: !regionOptionsByCountry[controllerCountry]?.length, onChange: event => setRegionalIdentifier(event.currentTarget.checked) }), " ", copy.regionalIdentifier] }), regionalIdentifier ? _jsxs("label", { children: [copy.controllerRegion, _jsx("select", { name: "controllerRegion", required: true, children: (regionOptionsByCountry[controllerCountry] || []).map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) })] }) : null, _jsxs("label", { children: [copy.controllerIdentifierType, identifierTypeOptions ? _jsx("select", { name: "controllerIdentifierType", required: true, children: identifierTypeOptions[controllerKind].map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) }, controllerKind) : _jsx("input", { name: "controllerIdentifierType", required: true, defaultValue: "national_identity_card", maxLength: 80 })] }), _jsxs("label", { children: [copy.controllerIdentifierValue, _jsx("input", { name: "controllerIdentifierValue", required: true, maxLength: 120, autoComplete: "off" })] }), _jsxs("label", { children: [copy.controllerEmail, _jsx("input", { name: "controllerEmail", type: "email", autoComplete: "email" })] }), _jsxs("label", { children: [copy.controllerTelephone, _jsx("input", { name: "controllerTelephone", type: "tel", autoComplete: "tel" })] }), _jsxs("label", { children: [copy.relationship, _jsxs("select", { name: "relationship", defaultValue: "owner", children: [_jsx("option", { value: "owner", children: copy.owner }), _jsx("option", { value: "caregiver", children: copy.caregiver })] })] }), _jsxs("label", { className: "uhcp-animal-controller-confirmation", children: [_jsx("input", { type: "checkbox", defaultChecked: true, required: true }), " ", copy.controllerIsLegalRepresentative] }), contactError ? _jsx("p", { role: "alert", children: contactError }) : null] })] }), _jsxs("details", { "aria-labelledby": "animal-onboarding-v2-evidence-step", children: [_jsxs("summary", { id: "animal-onboarding-v2-evidence-step", children: [_jsx(StepNumber, { value: 3 }), " ", copy.evidenceStep] }), _jsxs("div", { className: "uhcp-animal-onboarding-fields", children: [_jsxs("label", { children: [copy.verificationMethod, _jsxs("select", { name: "verificationMethod", defaultValue: "pipp", children: [_jsx("option", { value: "pipp", children: copy.physicalInPerson }), _jsx("option", { value: "sripp", children: copy.supervisedRemote }), _jsx("option", { value: "eid", children: copy.electronicId }), _jsx("option", { value: "uripp", children: copy.unsupervisedRemote })] })] }), _jsxs("label", { children: [copy.ownerDocument, _jsx("input", { name: "ownerDocument", type: "file", accept: "application/pdf,image/jpeg,image/png", required: true })] }), _jsxs("label", { children: [copy.relationshipDocument, _jsx("input", { name: "relationshipDocument", type: "file", accept: "application/pdf,image/jpeg,image/png", required: true })] }), _jsxs("label", { children: [copy.controllerPin, _jsx("input", { name: "controllerPin", type: "password", inputMode: "numeric", pattern: "[0-9]{6,12}", required: true, autoComplete: "new-password" })] })] })] }), _jsx("button", { type: "submit", className: "uhcp-animal-onboarding-submit", "data-portal-action": submitAction, disabled: disabled, children: copy.submit })] })] });
105
+ : _jsx("input", { name: "taxonomyId", required: true, inputMode: "numeric", pattern: "[1-9][0-9]{0,6}", defaultValue: "9615" })] }), _jsxs("label", { children: [copy.birthDate, _jsx("input", { name: "birthDate", type: "date" })] }), _jsxs("label", { children: [copy.sex, _jsxs("select", { name: "sex", defaultValue: "unknown", children: [_jsx("option", { value: "unknown", children: copy.sexUnknown }), _jsx("option", { value: "female", children: copy.sexFemale }), _jsx("option", { value: "male", children: copy.sexMale }), _jsx("option", { value: "other", children: copy.sexOther })] })] }), _jsxs("label", { children: [copy.identifierSystem, _jsxs("select", { name: "identifierSystem", defaultValue: "urn:iso:std:iso:11784:11785", children: [_jsx("option", { value: "urn:iso:std:iso:11784:11785", children: "ISO 11784/11785" }), _jsx("option", { value: "https://europa.eu/pet-passport", children: "EU pet passport" }), _jsx("option", { value: "https://vetchain.app/identifier/tattoo", children: "Tattoo" })] })] }), _jsxs("label", { children: [copy.identifierValue, _jsx("input", { name: "identifierValue", required: true, maxLength: 80, autoComplete: "off" })] })] })] })] }), _jsxs("details", { "aria-labelledby": "animal-onboarding-v2-controller-step", children: [_jsxs("summary", { id: "animal-onboarding-v2-controller-step", children: [_jsx(StepNumber, { value: 2 }), " ", copy.controllerStep] }), _jsx(IdentityEntityEditorV2, { mode: "controller", countryOptions: countryOptions, regionOptionsByCountry: regionOptionsByCountry, identifierTypeOptions: identifierTypeOptions, contactError: contactError, copy: {
106
+ entityType: copy.ownerKind, personEntity: copy.personOwner, organizationEntity: copy.organizationOwner,
107
+ fullLegalName: copy.controllerLegalName, country: copy.controllerCountry, regionalIdentifier: copy.regionalIdentifier,
108
+ region: copy.controllerRegion, identifierType: copy.controllerIdentifierType, identifierValue: copy.controllerIdentifierValue,
109
+ email: copy.controllerEmail, telephone: copy.controllerTelephone, relationship: copy.relationship,
110
+ responsibleParty: copy.responsibleParty ?? copy.owner, evidence: copy.evidenceStep,
111
+ verificationMethod: copy.verificationMethod, physicalInPerson: copy.physicalInPerson,
112
+ supervisedRemote: copy.supervisedRemote, electronicId: copy.electronicId, unsupervisedRemote: copy.unsupervisedRemote,
113
+ identityDocument: copy.ownerDocument, relationshipDocument: copy.relationshipDocument, pin: copy.controllerPin,
114
+ controllerConfirmation: copy.controllerIsLegalRepresentative,
115
+ } })] }), _jsx("button", { type: "submit", className: "uhcp-animal-onboarding-submit", "data-portal-action": submitAction, disabled: disabled, children: copy.submit })] })] });
108
116
  }
109
117
  function StepNumber({ value }) {
110
118
  return _jsx("span", { className: "uhcp-identity-step-number", "aria-hidden": "true", children: value });
@@ -0,0 +1,48 @@
1
+ export type IdentityEntitySelectOption = Readonly<{
2
+ value: string;
3
+ label: string;
4
+ }>;
5
+ export type IdentityEntityEditorV2Copy = Readonly<{
6
+ entityType: string;
7
+ personEntity: string;
8
+ organizationEntity: string;
9
+ fullLegalName: string;
10
+ country: string;
11
+ regionalIdentifier: string;
12
+ region: string;
13
+ identifierType: string;
14
+ identifierValue: string;
15
+ email: string;
16
+ telephone: string;
17
+ relationship: string;
18
+ responsibleParty: string;
19
+ evidence: string;
20
+ verificationMethod: string;
21
+ physicalInPerson: string;
22
+ supervisedRemote: string;
23
+ electronicId: string;
24
+ unsupervisedRemote: string;
25
+ identityDocument: string;
26
+ relationshipDocument: string;
27
+ pin: string;
28
+ controllerConfirmation: string;
29
+ }>;
30
+ /**
31
+ * Reusable identity-and-evidence editor for one controller or related entity.
32
+ * A controller has a fixed responsible-party relationship; related entities
33
+ * receive their host-governed relationship choices.
34
+ */
35
+ export declare function IdentityEntityEditorV2({ copy, mode, countryOptions, regionOptionsByCountry, identifierTypeOptions, relationshipOptions, fieldPrefix, contactError, }: Readonly<{
36
+ copy: IdentityEntityEditorV2Copy;
37
+ mode: 'controller' | 'related';
38
+ countryOptions?: readonly IdentityEntitySelectOption[];
39
+ regionOptionsByCountry?: Readonly<Record<string, readonly IdentityEntitySelectOption[]>>;
40
+ identifierTypeOptions?: Readonly<{
41
+ person: readonly IdentityEntitySelectOption[];
42
+ organization: readonly IdentityEntitySelectOption[];
43
+ }>;
44
+ relationshipOptions?: readonly IdentityEntitySelectOption[];
45
+ fieldPrefix?: string;
46
+ contactError?: string;
47
+ }>): import("react").JSX.Element;
48
+ //# sourceMappingURL=IdentityEntityEditorV2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IdentityEntityEditorV2.d.ts","sourceRoot":"","sources":["../src/IdentityEntityEditorV2.tsx"],"names":[],"mappings":"AAEA,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAEnF,MAAM,MAAM,0BAA0B,GAAG,QAAQ,CAAC;IAChD,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,aAAa,EAAE,MAAM,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,kBAAkB,EAAE,MAAM,CAAA;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,MAAM,CAAA;IACjB,YAAY,EAAE,MAAM,CAAA;IACpB,gBAAgB,EAAE,MAAM,CAAA;IACxB,QAAQ,EAAE,MAAM,CAAA;IAChB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,gBAAgB,EAAE,MAAM,CAAA;IACxB,YAAY,EAAE,MAAM,CAAA;IACpB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,oBAAoB,EAAE,MAAM,CAAA;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,sBAAsB,EAAE,MAAM,CAAA;CAC/B,CAAC,CAAA;AAEF;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,EACrC,IAAI,EACJ,IAAI,EACJ,cAAmB,EACnB,sBAA2B,EAC3B,qBAAqB,EACrB,mBAAwB,EACxB,WAAgB,EAChB,YAAY,GACb,EAAE,QAAQ,CAAC;IACV,IAAI,EAAE,0BAA0B,CAAA;IAChC,IAAI,EAAE,YAAY,GAAG,SAAS,CAAA;IAC9B,cAAc,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAA;IACtD,sBAAsB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,0BAA0B,EAAE,CAAC,CAAC,CAAA;IACxF,qBAAqB,CAAC,EAAE,QAAQ,CAAC;QAAE,MAAM,EAAE,SAAS,0BAA0B,EAAE,CAAC;QAAC,YAAY,EAAE,SAAS,0BAA0B,EAAE,CAAA;KAAE,CAAC,CAAA;IACxI,mBAAmB,CAAC,EAAE,SAAS,0BAA0B,EAAE,CAAA;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,YAAY,CAAC,EAAE,MAAM,CAAA;CACtB,CAAC,+BA0CD"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { useState } from 'react';
3
+ /**
4
+ * Reusable identity-and-evidence editor for one controller or related entity.
5
+ * A controller has a fixed responsible-party relationship; related entities
6
+ * receive their host-governed relationship choices.
7
+ */
8
+ export function IdentityEntityEditorV2({ copy, mode, countryOptions = [], regionOptionsByCountry = {}, identifierTypeOptions, relationshipOptions = [], fieldPrefix = '', contactError, }) {
9
+ const [entityType, setEntityType] = useState('person');
10
+ const [country, setCountry] = useState(countryOptions[0]?.value || '');
11
+ const [regional, setRegional] = useState(false);
12
+ const regions = regionOptionsByCountry[country] ?? [];
13
+ const name = (value) => fieldPrefix ? `${fieldPrefix}.${value}` : value;
14
+ return _jsxs("div", { className: "uhcp-identity-entity-editor", children: [_jsxs("div", { className: "uhcp-identity-entity-heading-row", children: [_jsxs("fieldset", { className: "uhcp-animal-owner-kind", children: [_jsx("legend", { children: copy.entityType }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: name('controllerKind'), value: "person", checked: entityType === 'person', onChange: () => setEntityType('person') }), " ", copy.personEntity] }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: name('controllerKind'), value: "organization", checked: entityType === 'organization', onChange: () => setEntityType('organization') }), " ", copy.organizationEntity] })] }), _jsxs("div", { className: "uhcp-identity-entity-relationship", children: [_jsx("span", { children: copy.relationship }), mode === 'controller'
15
+ ? _jsxs(_Fragment, { children: [_jsx("strong", { children: copy.responsibleParty }), _jsx("input", { type: "hidden", name: name('relationship'), value: "owner" })] })
16
+ : _jsx("select", { name: name('relationship'), "aria-label": copy.relationship, required: true, defaultValue: relationshipOptions[0]?.value, children: relationshipOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) })] })] }), _jsxs("div", { className: "uhcp-animal-onboarding-fields", children: [_jsxs("label", { className: "uhcp-animal-owner-name", children: [copy.fullLegalName, _jsx("input", { name: name('controllerLegalName'), required: true, maxLength: 160, autoComplete: entityType === 'person' ? 'name' : 'organization' })] }), _jsxs("label", { children: [copy.country, countryOptions.length ? _jsx("select", { name: name('controllerCountry'), required: true, value: country, onChange: event => setCountry(event.currentTarget.value), children: countryOptions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) }) : _jsx("input", { name: name('controllerCountry'), required: true, pattern: "[A-Za-z]{2}", maxLength: 2, autoComplete: "country", onChange: event => setCountry(event.currentTarget.value.toUpperCase()) })] }), _jsxs("label", { className: "uhcp-animal-regional-identifier", children: [_jsx("input", { type: "checkbox", checked: regional, disabled: !regions.length, onChange: event => setRegional(event.currentTarget.checked) }), " ", copy.regionalIdentifier] }), _jsxs("label", { children: [copy.region, _jsxs("select", { name: name('controllerRegion'), required: regional, disabled: !regional, children: [_jsx("option", { value: "" }), regions.map(option => _jsx("option", { value: option.value, children: option.label }, option.value))] })] }), _jsxs("label", { children: [copy.identifierType, identifierTypeOptions ? _jsx("select", { name: name('controllerIdentifierType'), required: true, children: identifierTypeOptions[entityType].map(option => _jsx("option", { value: option.value, children: option.label }, option.value)) }, entityType) : _jsx("input", { name: name('controllerIdentifierType'), required: true, defaultValue: "national_identity_card", maxLength: 80 })] }), _jsxs("label", { children: [copy.identifierValue, _jsx("input", { name: name('controllerIdentifierValue'), required: true, maxLength: 120, autoComplete: "off" })] }), _jsxs("label", { children: [copy.email, _jsx("input", { name: name('controllerEmail'), type: "email", autoComplete: "email" })] }), _jsxs("label", { children: [copy.telephone, _jsx("input", { name: name('controllerTelephone'), type: "tel", autoComplete: "tel" })] }), mode === 'controller' ? _jsxs("label", { className: "uhcp-animal-controller-confirmation", children: [_jsx("input", { type: "checkbox", defaultChecked: true, required: true }), " ", copy.controllerConfirmation] }) : null, contactError ? _jsx("p", { role: "alert", children: contactError }) : null] }), _jsxs("fieldset", { className: "uhcp-identity-entity-evidence", children: [_jsx("legend", { children: copy.evidence }), _jsxs("div", { className: "uhcp-animal-onboarding-fields", children: [_jsxs("label", { children: [copy.verificationMethod, _jsxs("select", { name: name('verificationMethod'), defaultValue: "pipp", children: [_jsx("option", { value: "pipp", children: copy.physicalInPerson }), _jsx("option", { value: "sripp", children: copy.supervisedRemote }), _jsx("option", { value: "eid", children: copy.electronicId }), _jsx("option", { value: "uripp", children: copy.unsupervisedRemote })] })] }), _jsxs("label", { children: [copy.identityDocument, _jsx("input", { name: name('ownerDocument'), type: "file", accept: "application/pdf,image/jpeg,image/png", required: true })] }), _jsxs("label", { children: [copy.relationshipDocument, _jsx("input", { name: name('relationshipDocument'), type: "file", accept: "application/pdf,image/jpeg,image/png", required: true })] }), mode === 'controller' ? _jsxs("label", { children: [copy.pin, _jsx("input", { name: name('controllerPin'), type: "password", inputMode: "numeric", pattern: "[0-9]{6,12}", required: true, autoComplete: "new-password" })] }) : null] })] })] });
17
+ }
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export * from './IdentityEvidenceDocumentPanel.js';
38
38
  export * from './IdentityEvidenceDeclarationForm.js';
39
39
  export * from './AnimalIdentityOnboarding.js';
40
40
  export * from './AnimalIdentityOnboardingV2.js';
41
+ export * from './IdentityEntityEditorV2.js';
41
42
  export * from './AnimalCardArtifact.js';
42
43
  export * from './AnimalControllerAttestationPanel.js';
43
44
  export * from './EmergencyTaskHub.js';
@@ -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,2BAA2B,CAAA;AACzC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wCAAwC,CAAA;AACtD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,mCAAmC,CAAA;AACjD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,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;AACpD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yBAAyB,CAAA;AACvC,cAAc,uCAAuC,CAAA;AACrD,cAAc,uBAAuB,CAAA;AACrC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,8BAA8B,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,2BAA2B,CAAA;AACzC,cAAc,kBAAkB,CAAA;AAChC,cAAc,kBAAkB,CAAA;AAChC,cAAc,4BAA4B,CAAA;AAC1C,cAAc,8BAA8B,CAAA;AAC5C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,uBAAuB,CAAA;AACrC,cAAc,wCAAwC,CAAA;AACtD,cAAc,0BAA0B,CAAA;AACxC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,mCAAmC,CAAA;AACjD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,qCAAqC,CAAA;AACnD,cAAc,mCAAmC,CAAA;AACjD,cAAc,gCAAgC,CAAA;AAC9C,cAAc,0BAA0B,CAAA;AACxC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,2BAA2B,CAAA;AACzC,cAAc,8BAA8B,CAAA;AAC5C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,wBAAwB,CAAA;AACtC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,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;AACpD,cAAc,+BAA+B,CAAA;AAC7C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,6BAA6B,CAAA;AAC3C,cAAc,yBAAyB,CAAA;AACvC,cAAc,uCAAuC,CAAA;AACrD,cAAc,uBAAuB,CAAA;AACrC,cAAc,iCAAiC,CAAA;AAC/C,cAAc,8BAA8B,CAAA"}
package/dist/index.js CHANGED
@@ -38,6 +38,7 @@ export * from './IdentityEvidenceDocumentPanel.js';
38
38
  export * from './IdentityEvidenceDeclarationForm.js';
39
39
  export * from './AnimalIdentityOnboarding.js';
40
40
  export * from './AnimalIdentityOnboardingV2.js';
41
+ export * from './IdentityEntityEditorV2.js';
41
42
  export * from './AnimalCardArtifact.js';
42
43
  export * from './AnimalControllerAttestationPanel.js';
43
44
  export * from './EmergencyTaskHub.js';
package/dist/styles.css CHANGED
@@ -782,7 +782,8 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
782
782
  .uhcp-animal-onboarding-v2 summary::after { content:'⌄'; margin-inline-start:auto; transition:transform .18s ease; }
783
783
  .uhcp-animal-onboarding-v2 details[open] summary::after { transform:rotate(180deg); }
784
784
  .uhcp-animal-onboarding-v2 details > .uhcp-animal-onboarding-fields,
785
- .uhcp-animal-onboarding-v2 details > .uhcp-animal-onboarding-primary { border-top:1px solid var(--uhcp-border, #d9dee7); padding:1rem; }
785
+ .uhcp-animal-onboarding-v2 details > .uhcp-animal-onboarding-primary,
786
+ .uhcp-animal-onboarding-v2 details > .uhcp-identity-entity-editor { border-top:1px solid var(--uhcp-border, #d9dee7); padding:1rem; }
786
787
  .uhcp-animal-onboarding-primary { align-items:start; display:grid; gap:1rem; grid-template-columns:minmax(10rem, 14rem) minmax(0, 1fr); }
787
788
  .uhcp-animal-photo { display:grid; gap:.45rem; position:relative; }
788
789
  .uhcp-animal-photo-dropzone { align-items:center; aspect-ratio:1; background:var(--uhcp-accent-soft, #e9f3ff); border:2px dashed color-mix(in srgb, var(--uhcp-turquoise, #1597a6) 58%, var(--uhcp-border, #d9dee7)); border-radius:1.25rem; cursor:pointer; display:flex; font-size:4rem; font-weight:850; justify-content:center; overflow:hidden; width:100%; }
@@ -794,10 +795,15 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
794
795
  .uhcp-animal-owner-kind { border:0!important; display:flex; gap:1rem; grid-column:1/-1; padding:0!important; }
795
796
  .uhcp-animal-owner-kind label,.uhcp-animal-regional-identifier { align-items:center; display:flex!important; gap:.45rem; }
796
797
  .uhcp-animal-owner-kind input,.uhcp-animal-regional-identifier input { min-height:auto!important; width:auto!important; }
798
+ .uhcp-identity-entity-editor { display:grid; gap:1rem; }
799
+ .uhcp-identity-entity-heading-row { align-items:stretch; display:grid; gap:1rem; grid-template-columns:minmax(0,1fr) minmax(12rem,.7fr); }
800
+ .uhcp-identity-entity-relationship { align-content:center; background:var(--uhcp-panel-muted, #f4f7fa); border:1px solid var(--uhcp-border, #d9dee7); border-radius:1rem; display:grid; gap:.35rem; padding:1rem; }
801
+ .uhcp-identity-entity-relationship span { color:var(--uhcp-muted, #5f6875); font-size:.85rem; font-weight:750; }
802
+ .uhcp-identity-entity-evidence { background:var(--uhcp-panel-muted, #f4f7fa); }
797
803
  .uhcp-animal-owner-name { grid-column:1/-1; }
798
804
  .uhcp-animal-controller-confirmation { align-items:center; background:var(--uhcp-accent-soft, #e9f3ff); border-radius:.75rem; display:flex !important; grid-column:1 / -1; padding:.75rem; }
799
805
  .uhcp-animal-controller-confirmation input { min-height:auto !important; width:auto !important; }
800
- @media (max-width: 42rem) { .uhcp-animal-onboarding-primary { grid-template-columns:1fr; } .uhcp-animal-photo { justify-self:center; max-width:15rem; width:100%; } }
806
+ @media (max-width: 42rem) { .uhcp-animal-onboarding-primary,.uhcp-identity-entity-heading-row { grid-template-columns:1fr; } .uhcp-animal-photo { justify-self:center; max-width:15rem; width:100%; } }
801
807
  .uhcp-animal-card { aspect-ratio: 1.586; background: linear-gradient(145deg, #0a4169 0%, #087f8d 60%, #18a4a6 100%); border: 1px solid color-mix(in srgb, #fff 32%, transparent); border-radius: 1.15rem; box-shadow: 0 1rem 2.5rem rgb(2 30 51 / 22%); box-sizing: border-box; color: #fff; display: grid; gap: .8rem; grid-template-rows: auto 1fr auto; max-width: 33.5rem; min-height: 18.25rem; overflow: hidden; padding: 1.25rem; position: relative; width: 100%; }
802
808
  .uhcp-animal-card::after { background: radial-gradient(circle, rgb(255 255 255 / 18%), transparent 68%); content: ''; height: 18rem; inset: -8rem -7rem auto auto; pointer-events: none; position: absolute; width: 18rem; }
803
809
  .uhcp-animal-card-header, .uhcp-animal-card-body, .uhcp-animal-card-brand { align-items: center; display: flex; }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
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",