uhc-portal-components-react 0.1.18 → 0.1.19

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,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.19
4
+
5
+ - Add an accessible Encounter transfer console with patient lookup, a
6
+ horizontally scrollable care journey, explicit return/on-hold versus
7
+ definitive/completed choices, and an in-progress destination.
8
+ - Add emergency-contact call, video and message actions plus PDF, FHIR Bundle
9
+ and calendar attachment choices without deriving authorization in the UI.
10
+ - Keep plain-language help visible and place FHIR resource names in optional
11
+ technical details.
12
+ - Render a host-provided encounter business identifier without replacing the
13
+ FHIR resource identity or deriving identifiers in browser state.
14
+
3
15
  ## 0.1.18
4
16
 
5
17
  - Add shared, read-only Health summary and Care journey areas to the SOSChain
package/README.md CHANGED
@@ -64,6 +64,14 @@ The package deliberately exposes modules instead of a cloned application:
64
64
  - `SoschainWorkspace`: subject-card picker and four-area workspace for Places,
65
65
  devices/vehicles and read-only emergency communications. The host supplies
66
66
  already-authorized cards and capabilities.
67
+ - `EncounterTransferConsole`: visual patient-transfer workspace. The host
68
+ resolves the authorized subject, contacts and write capability; the component
69
+ only reports the chosen source outcome (`on-hold` when returning or
70
+ `completed` when leaving definitively) and never treats browser state as
71
+ clinical authority. `EncounterTransferStage.identifier` remains the FHIR
72
+ resource identity; an optional `displayIdentifier` is a provider-assigned
73
+ human-readable business identifier. The component never generates it or
74
+ resolves same-second concurrency.
67
75
  - `OrganizationWorkforceAdministration`: controlled license-capacity,
68
76
  employee lifecycle and invitation-status UI. Invitations remain host-owned
69
77
  application records; the component does not reserve licenses or create GW
@@ -0,0 +1,84 @@
1
+ export type EncounterTransferStatus = 'planned' | 'in-progress' | 'on-hold' | 'completed';
2
+ export type EncounterSourceOutcome = 'on-hold' | 'completed';
3
+ export type EncounterTransferStage = Readonly<{
4
+ identifier: string;
5
+ /** Human-readable provider business identifier; never replaces the FHIR resource id. */
6
+ displayIdentifier?: string;
7
+ serviceLabel: string;
8
+ locationLabel?: string;
9
+ arrivedAt: string;
10
+ status: EncounterTransferStatus;
11
+ }>;
12
+ export type EmergencyContactAction = Readonly<{
13
+ identifier: string;
14
+ name: string;
15
+ relationship: string;
16
+ phone?: string;
17
+ }>;
18
+ export type EncounterTransferConsoleCopy = Readonly<{
19
+ patientSearchTitle: string;
20
+ scanQr: string;
21
+ patientId: string;
22
+ search: string;
23
+ journeyTitle: string;
24
+ sourceTitle: string;
25
+ destinationTitle: string;
26
+ returning: string;
27
+ returningHint: string;
28
+ notReturning: string;
29
+ notReturningHint: string;
30
+ transferTo: string;
31
+ reviewChanges: string;
32
+ applyTransfer: string;
33
+ emergencyActions: string;
34
+ call: string;
35
+ videoCall: string;
36
+ sendMessage: string;
37
+ text: string;
38
+ audio: string;
39
+ messageLabel: string;
40
+ attach: string;
41
+ pdf: string;
42
+ fhirBundle: string;
43
+ calendar: string;
44
+ send: string;
45
+ resourceSummary: string;
46
+ sourceUpdate: string;
47
+ sourceHistory: string;
48
+ destinationUpdate: string;
49
+ destinationHistory: string;
50
+ indexProjection: string;
51
+ demoWarning: string;
52
+ helpTitle: string;
53
+ helpBody: string;
54
+ transferReady: string;
55
+ messageReady: string;
56
+ callReady: string;
57
+ videoReady: string;
58
+ patientReady: string;
59
+ reviewReady: string;
60
+ attachmentReady: string;
61
+ technicalDetails: string;
62
+ encounterIdentifier: string;
63
+ }>;
64
+ export type EncounterTransferConsoleProps = Readonly<{
65
+ copy: EncounterTransferConsoleCopy;
66
+ patientDisplay: string;
67
+ encounters: readonly EncounterTransferStage[];
68
+ sourceEncounterId: string;
69
+ destinationEncounterId: string;
70
+ contacts: readonly EmergencyContactAction[];
71
+ demo?: boolean;
72
+ onApplyTransfer?: (sourceOutcome: EncounterSourceOutcome) => void;
73
+ }>;
74
+ /**
75
+ * Shared visual editor for one already-authorized subject transfer.
76
+ *
77
+ * Selection and demo state never grant access. The host must resolve the
78
+ * subject, contacts, department sender, HealthcareService and write
79
+ * capability in its BFF. `onApplyTransfer` reports only the requested source
80
+ * outcome; the provider commits authoritative Encounter changes before any
81
+ * completed Communication projects the result to the subject index.
82
+ */
83
+ export declare function EncounterTransferConsole({ copy, patientDisplay, encounters, sourceEncounterId, destinationEncounterId, contacts, demo, onApplyTransfer }: EncounterTransferConsoleProps): import("react").JSX.Element;
84
+ //# sourceMappingURL=EncounterTransferConsole.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EncounterTransferConsole.d.ts","sourceRoot":"","sources":["../src/EncounterTransferConsole.tsx"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useId, useMemo, useRef, useState } from 'react';
3
+ const icons = {
4
+ scan: _jsxs(_Fragment, { children: [_jsx("path", { d: "M4 8V5a1 1 0 0 1 1-1h3M16 4h3a1 1 0 0 1 1 1v3M20 16v3a1 1 0 0 1-1 1h-3M8 20H5a1 1 0 0 1-1-1v-3" }), _jsx("path", { d: "M8 8h3v3H8zM14 8h2v2M8 14h2v2M13 13h3v3h-3z" })] }),
5
+ phone: _jsx("path", { d: "M7.2 3.8 9.4 7 8 9.1a14 14 0 0 0 6.9 6.9l2.1-1.4 3.2 2.2-.8 3a2 2 0 0 1-2.1 1.4C9.8 20.2 3.8 14.2 2.8 6.7A2 2 0 0 1 4.2 4.6z" }),
6
+ video: _jsxs(_Fragment, { children: [_jsx("rect", { x: "3", y: "6", width: "12", height: "12", rx: "2" }), _jsx("path", { d: "m15 10 6-3v10l-6-3z" })] }),
7
+ message: _jsx("path", { d: "M4 4h16v12H9l-5 4z" }),
8
+ chevron: _jsx("path", { d: "m9 5 7 7-7 7" }),
9
+ };
10
+ function Icon({ name }) {
11
+ return _jsx("svg", { viewBox: "0 0 24 24", "aria-hidden": "true", children: icons[name] });
12
+ }
13
+ /**
14
+ * Shared visual editor for one already-authorized subject transfer.
15
+ *
16
+ * Selection and demo state never grant access. The host must resolve the
17
+ * subject, contacts, department sender, HealthcareService and write
18
+ * capability in its BFF. `onApplyTransfer` reports only the requested source
19
+ * outcome; the provider commits authoritative Encounter changes before any
20
+ * completed Communication projects the result to the subject index.
21
+ */
22
+ export function EncounterTransferConsole({ copy, patientDisplay, encounters, sourceEncounterId, destinationEncounterId, contacts, demo = false, onApplyTransfer }) {
23
+ const [sourceOutcome, setSourceOutcome] = useState('on-hold');
24
+ const [selectedContact, setSelectedContact] = useState(contacts[0]?.identifier);
25
+ const [messageOpen, setMessageOpen] = useState(false);
26
+ const [messageMode, setMessageMode] = useState('text');
27
+ const [attachments, setAttachments] = useState([]);
28
+ const [showTechnical, setShowTechnical] = useState(false);
29
+ const [status, setStatus] = useState('');
30
+ const railRef = useRef(null);
31
+ const source = useMemo(() => encounters.find((item) => item.identifier === sourceEncounterId), [encounters, sourceEncounterId]);
32
+ const destination = useMemo(() => encounters.find((item) => item.identifier === destinationEncounterId), [encounters, destinationEncounterId]);
33
+ const history = useMemo(() => encounters.filter((item) => item.identifier !== sourceEncounterId && item.identifier !== destinationEncounterId), [encounters, sourceEncounterId, destinationEncounterId]);
34
+ const contact = contacts.find((item) => item.identifier === selectedContact) ?? contacts[0];
35
+ const helpId = useId();
36
+ function toggleAttachment(kind) {
37
+ setAttachments(current => current.includes(kind) ? current.filter(item => item !== kind) : [...current, kind]);
38
+ setStatus(copy.attachmentReady);
39
+ }
40
+ function applyTransfer() {
41
+ onApplyTransfer?.(sourceOutcome);
42
+ setStatus(copy.transferReady);
43
+ }
44
+ return _jsxs("section", { className: "uhcp-transfer-console", children: [_jsx("aside", { className: "uhcp-transfer-contacts", children: _jsxs("details", { open: true, children: [_jsx("summary", { children: copy.emergencyActions }), _jsx("div", { className: "uhcp-transfer-contact-list", role: "list", children: contacts.map((item) => _jsxs("button", { type: "button", role: "listitem", "aria-pressed": item.identifier === contact?.identifier, onClick: () => setSelectedContact(item.identifier), children: [_jsx("span", { "aria-hidden": "true", children: item.name.split(/\s+/).map(part => part[0]).slice(0, 2).join('') }), _jsx("strong", { children: item.name }), _jsxs("small", { children: [item.relationship, item.phone ? ` · ${item.phone}` : ''] })] }, item.identifier)) }), _jsxs("div", { className: "uhcp-transfer-contact-actions", children: [_jsxs("button", { type: "button", onClick: () => setStatus(copy.callReady), children: [_jsx(Icon, { name: "phone" }), copy.call] }), _jsxs("button", { type: "button", onClick: () => setStatus(copy.videoReady), children: [_jsx(Icon, { name: "video" }), copy.videoCall] }), _jsxs("button", { type: "button", "aria-pressed": messageOpen, onClick: () => setMessageOpen(value => !value), children: [_jsx(Icon, { name: "message" }), copy.sendMessage] })] }), messageOpen && contact ? _jsxs("form", { className: "uhcp-transfer-composer", onSubmit: (event) => { event.preventDefault(); setStatus(copy.messageReady); }, children: [_jsxs("h3", { children: [copy.sendMessage, ": ", contact.name] }), _jsxs("div", { className: "uhcp-transfer-mode", role: "group", "aria-label": copy.sendMessage, children: [_jsx("button", { type: "button", "aria-pressed": messageMode === 'text', onClick: () => setMessageMode('text'), children: copy.text }), _jsx("button", { type: "button", "aria-pressed": messageMode === 'audio', onClick: () => setMessageMode('audio'), children: copy.audio })] }), messageMode === 'text' ? _jsxs("label", { children: [copy.messageLabel, _jsx("textarea", { rows: 5 })] }) : _jsxs("button", { className: "uhcp-transfer-record", type: "button", children: ["\u25CF ", copy.audio] }), _jsxs("fieldset", { children: [_jsx("legend", { children: copy.attach }), _jsxs("div", { children: [_jsx("button", { type: "button", "aria-pressed": attachments.includes('pdf'), onClick: () => toggleAttachment('pdf'), children: copy.pdf }), _jsx("button", { type: "button", "aria-pressed": attachments.includes('fhir'), onClick: () => toggleAttachment('fhir'), children: copy.fhirBundle }), _jsx("button", { type: "button", "aria-pressed": attachments.includes('calendar'), onClick: () => toggleAttachment('calendar'), children: copy.calendar })] })] }), _jsx("button", { className: "uhcp-transfer-primary", type: "submit", children: copy.send })] }) : null] }) }), _jsxs("div", { className: "uhcp-transfer-main", children: [_jsxs("header", { className: "uhcp-transfer-patient", children: [_jsx("h2", { children: copy.patientSearchTitle }), _jsxs("div", { children: [_jsxs("button", { type: "button", onClick: () => setStatus(copy.patientReady), children: [_jsx(Icon, { name: "scan" }), copy.scanQr] }), _jsx("span", { "aria-hidden": "true" }), _jsxs("label", { children: [copy.patientId, _jsx("input", { defaultValue: patientDisplay })] }), _jsx("button", { type: "button", onClick: () => setStatus(copy.patientReady), children: copy.search })] })] }), _jsxs("section", { className: "uhcp-transfer-journey", role: "region", "aria-label": copy.journeyTitle, "aria-describedby": helpId, children: [_jsxs("header", { children: [_jsx("h2", { children: copy.journeyTitle }), _jsxs("div", { children: [_jsx("button", { type: "button", "aria-label": "Anterior", onClick: () => railRef.current?.scrollBy({ left: -260, behavior: 'smooth' }), children: _jsx(Icon, { name: "chevron" }) }), _jsx("button", { type: "button", "aria-label": "Siguiente", onClick: () => railRef.current?.scrollBy({ left: 260, behavior: 'smooth' }), children: _jsx(Icon, { name: "chevron" }) })] })] }), _jsxs("div", { className: "uhcp-transfer-rail", ref: railRef, children: [history.map((item) => _jsx(EncounterCard, { encounter: item }, item.identifier)), source ? _jsxs("article", { className: "uhcp-transfer-card uhcp-transfer-source", children: [_jsx("h3", { children: copy.sourceTitle }), _jsx(EncounterCardBody, { encounter: source, identifierLabel: copy.encounterIdentifier }), _jsxs("fieldset", { children: [_jsx("legend", { children: copy.helpTitle }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "source-outcome", checked: sourceOutcome === 'on-hold', onChange: () => setSourceOutcome('on-hold') }), _jsxs("span", { children: [_jsx("strong", { children: copy.returning }), _jsx("small", { children: copy.returningHint })] })] }), _jsxs("label", { children: [_jsx("input", { type: "radio", name: "source-outcome", checked: sourceOutcome === 'completed', onChange: () => setSourceOutcome('completed') }), _jsxs("span", { children: [_jsx("strong", { children: copy.notReturning }), _jsx("small", { children: copy.notReturningHint })] })] })] })] }) : null, _jsxs("div", { className: "uhcp-transfer-arrow", children: [_jsx("span", { children: copy.transferTo }), _jsx("i", {}), _jsx(Icon, { name: "chevron" })] }), destination ? _jsxs("article", { className: "uhcp-transfer-card uhcp-transfer-destination", children: [_jsx("h3", { children: copy.destinationTitle }), _jsx(EncounterCardBody, { encounter: { ...destination, status: 'in-progress' }, identifierLabel: copy.encounterIdentifier })] }) : null] }), _jsxs("details", { className: "uhcp-transfer-help", open: true, children: [_jsx("summary", { id: helpId, children: copy.helpTitle }), _jsx("p", { children: copy.helpBody })] }), _jsxs("div", { className: "uhcp-transfer-controls", children: [_jsx("button", { type: "button", onClick: () => { setShowTechnical(true); setStatus(copy.reviewReady); }, children: copy.reviewChanges }), _jsx("button", { className: "uhcp-transfer-primary", type: "button", onClick: applyTransfer, children: copy.applyTransfer })] })] }), _jsxs("section", { className: "uhcp-transfer-review", children: [_jsxs("header", { children: [_jsx("h2", { children: copy.resourceSummary }), demo ? _jsx("p", { children: copy.demoWarning }) : null] }), _jsx("ol", { "aria-label": copy.resourceSummary, children: [[copy.sourceUpdate, 'Encounter'], [copy.sourceHistory, 'EncounterHistory'], [copy.destinationUpdate, 'Encounter'], [copy.destinationHistory, 'EncounterHistory'], [copy.indexProjection, 'Communication']].map(([label, resource], index) => _jsxs("li", { children: [_jsx("span", { children: index + 1 }), _jsx("strong", { children: label }), _jsxs("details", { open: showTechnical, children: [_jsx("summary", { children: copy.technicalDetails }), _jsx("code", { children: resource })] })] }, `${resource}-${index}`)) })] }), status ? _jsx("p", { className: "uhcp-transfer-status", role: "status", children: status }) : null] })] });
45
+ }
46
+ function EncounterCard({ encounter }) {
47
+ return _jsx("article", { className: "uhcp-transfer-card", children: _jsx(EncounterCardBody, { encounter: encounter }) });
48
+ }
49
+ function EncounterCardBody({ encounter, identifierLabel }) {
50
+ return _jsxs("div", { className: "uhcp-transfer-card-body", children: [_jsx("time", { children: encounter.arrivedAt }), _jsx("strong", { children: encounter.serviceLabel }), encounter.locationLabel ? _jsx("span", { children: encounter.locationLabel }) : null, _jsx("small", { "data-status": encounter.status, children: encounter.status }), _jsx("code", { "aria-label": identifierLabel, children: encounter.displayIdentifier ?? encounter.identifier })] });
51
+ }
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * from './IpsBundleSummary.js';
11
11
  export * from './InvitationAcceptancePanel.js';
12
12
  export * from './SubjectAccessRequestPanel.js';
13
13
  export * from './SoschainWorkspace.js';
14
+ export * from './EncounterTransferConsole.js';
14
15
  export * from './OrganizationWorkforceAdministration.js';
15
16
  export * from './ProtectedIndexEmergencyData.js';
16
17
  export * from './PortalSettingsPanel.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,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"}
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,+BAA+B,CAAA;AAC7C,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
@@ -11,6 +11,7 @@ export * from './IpsBundleSummary.js';
11
11
  export * from './InvitationAcceptancePanel.js';
12
12
  export * from './SubjectAccessRequestPanel.js';
13
13
  export * from './SoschainWorkspace.js';
14
+ export * from './EncounterTransferConsole.js';
14
15
  export * from './OrganizationWorkforceAdministration.js';
15
16
  export * from './ProtectedIndexEmergencyData.js';
16
17
  export * from './PortalSettingsPanel.js';
package/dist/styles.css CHANGED
@@ -172,6 +172,85 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
172
172
  padding: 1.25rem;
173
173
  }
174
174
 
175
+ .uhcp-transfer-console { background:#fff; color:#102754; display:grid; font-family:Inter,ui-sans-serif,system-ui,sans-serif; grid-template-columns:minmax(16rem,23rem) minmax(0,1fr); min-height:calc(100vh - 4.5rem); }
176
+ .uhcp-transfer-console button,.uhcp-transfer-console input,.uhcp-transfer-console textarea { font:inherit; }
177
+ .uhcp-transfer-console svg { fill:none; height:1.25rem; stroke:currentColor; stroke-linecap:round; stroke-linejoin:round; stroke-width:1.8; width:1.25rem; }
178
+ .uhcp-transfer-contacts { border-inline-end:1px solid #dce5ec; padding:1.2rem; }
179
+ .uhcp-transfer-contacts summary { cursor:pointer; font-size:1.05rem; font-weight:850; list-style-position:inside; padding:.35rem 0 1rem; }
180
+ .uhcp-transfer-contact-list { border-block:1px solid #e2e9ef; display:grid; padding:.45rem 0; }
181
+ .uhcp-transfer-contact-list button { background:transparent; border:0; border-inline-start:3px solid transparent; color:inherit; cursor:pointer; display:grid; gap:.15rem; grid-template-columns:2.7rem 1fr; padding:.75rem; text-align:start; }
182
+ .uhcp-transfer-contact-list button[aria-pressed=true] { background:#eaf8fd; border-inline-start-color:#09a9dc; }
183
+ .uhcp-transfer-contact-list button>span { align-items:center; background:#d7e7f1; border-radius:50%; display:flex; font-weight:800; grid-row:span 2; height:2.4rem; justify-content:center; width:2.4rem; }
184
+ .uhcp-transfer-contact-list small { color:#58708e; }
185
+ .uhcp-transfer-contact-actions { display:grid; gap:.55rem; padding:1rem 0; }
186
+ .uhcp-transfer-contact-actions button,.uhcp-transfer-mode button,.uhcp-transfer-composer fieldset button { align-items:center; background:#fff; border:1px solid #cad7e2; border-radius:.55rem; color:inherit; cursor:pointer; display:flex; gap:.7rem; padding:.7rem .85rem; }
187
+ .uhcp-transfer-contact-actions button[aria-pressed=true],.uhcp-transfer-mode button[aria-pressed=true] { background:#eaf8fd; border-color:#09a9dc; color:#006f96; font-weight:800; }
188
+ .uhcp-transfer-composer fieldset button[aria-pressed=true] { background:#eaf8fd; border-color:#09a9dc; color:#006f96; font-weight:800; }
189
+ .uhcp-transfer-composer { display:grid; gap:.8rem; }
190
+ .uhcp-transfer-composer h3 { font-size:.95rem; margin:.2rem 0 0; }
191
+ .uhcp-transfer-mode { display:grid; grid-template-columns:1fr 1fr; }
192
+ .uhcp-transfer-mode button { justify-content:center; }
193
+ .uhcp-transfer-composer label { display:grid; font-size:.82rem; font-weight:750; gap:.35rem; }
194
+ .uhcp-transfer-composer textarea { border:1px solid #cad7e2; border-radius:.55rem; color:inherit; resize:vertical; padding:.75rem; }
195
+ .uhcp-transfer-composer fieldset { border:0; margin:0; padding:0; }
196
+ .uhcp-transfer-composer legend { font-size:.82rem; font-weight:750; margin-bottom:.4rem; }
197
+ .uhcp-transfer-composer fieldset>div { display:flex; flex-wrap:wrap; gap:.4rem; }
198
+ .uhcp-transfer-record { background:#fff; border:1px dashed #09a9dc; border-radius:.55rem; color:#006f96; padding:1rem; }
199
+ .uhcp-transfer-primary { background:#0796a8!important; border-color:#0796a8!important; color:#fff!important; font-weight:850!important; }
200
+ .uhcp-transfer-main { min-width:0; padding:1rem; }
201
+ .uhcp-transfer-patient,.uhcp-transfer-journey,.uhcp-transfer-review { border:1px solid #dce5ec; border-radius:.7rem; box-shadow:0 4px 16px rgb(16 39 84 / 5%); }
202
+ .uhcp-transfer-patient { padding:1rem; }
203
+ .uhcp-transfer-patient h2,.uhcp-transfer-journey h2,.uhcp-transfer-review h2 { font-size:1.18rem; margin:0; }
204
+ .uhcp-transfer-patient>div { align-items:center; display:grid; gap:.75rem; grid-template-columns:minmax(11rem,.85fr) 1px minmax(13rem,1fr) auto; margin-top:.75rem; }
205
+ .uhcp-transfer-patient button,.uhcp-transfer-patient label { align-items:center; background:#fff; border:1px solid #9fb3c8; border-radius:.45rem; display:flex; gap:.65rem; min-height:3rem; padding:.7rem .9rem; }
206
+ .uhcp-transfer-patient button { color:inherit; cursor:pointer; font-weight:800; justify-content:center; }
207
+ .uhcp-transfer-patient button:last-child { background:#0796a8; border-color:#0796a8; color:#fff; }
208
+ .uhcp-transfer-patient>div>span { background:#cbd7e1; height:2rem; }
209
+ .uhcp-transfer-patient label { color:#64748b; }
210
+ .uhcp-transfer-patient input { border:0; color:#102754; min-width:0; outline:0; width:100%; }
211
+ .uhcp-transfer-journey { margin-top:.8rem; overflow:hidden; padding:1rem; }
212
+ .uhcp-transfer-journey>header,.uhcp-transfer-review>header { align-items:center; display:flex; justify-content:space-between; }
213
+ .uhcp-transfer-journey>header>div { display:flex; gap:.4rem; }
214
+ .uhcp-transfer-journey>header button { align-items:center; background:#fff; border:1px solid #cad7e2; border-radius:.45rem; color:inherit; display:flex; padding:.45rem; }
215
+ .uhcp-transfer-journey>header button:first-child svg { transform:rotate(180deg); }
216
+ .uhcp-transfer-rail { align-items:center; display:flex; gap:.8rem; min-height:18rem; overflow-x:auto; padding:1rem .25rem; scrollbar-color:#aebfce #edf2f5; }
217
+ .uhcp-transfer-card { border:1px solid #cad7e2; border-radius:.5rem; flex:0 0 10rem; min-height:12rem; overflow:hidden; }
218
+ .uhcp-transfer-card h3 { background:#087db8; color:#fff; font-size:.82rem; margin:0; padding:.65rem; }
219
+ .uhcp-transfer-card-body { display:grid; gap:.45rem; padding:.85rem; }
220
+ .uhcp-transfer-card-body time,.uhcp-transfer-card-body span,.uhcp-transfer-card-body code { color:#60738c; font-size:.72rem; }
221
+ .uhcp-transfer-card-body small { background:#edf2f5; border-radius:999px; color:#466079; font-size:.7rem; justify-self:start; padding:.25rem .55rem; }
222
+ .uhcp-transfer-card-body small[data-status=in-progress] { background:#d7f4e5; color:#087a47; }
223
+ .uhcp-transfer-card-body small[data-status=completed] { background:#dff6e8; color:#087a47; }
224
+ .uhcp-transfer-card-body small[data-status=on-hold] { background:#fff1d2; color:#9a5a00; }
225
+ .uhcp-transfer-source { border-color:#078dcc; flex-basis:13.5rem; }
226
+ .uhcp-transfer-destination { border-color:#069f69; flex-basis:13rem; }
227
+ .uhcp-transfer-destination h3 { background:#069f69; }
228
+ .uhcp-transfer-source fieldset { border:0; border-top:1px solid #dce5ec; margin:.2rem .7rem .7rem; padding:.7rem 0 0; }
229
+ .uhcp-transfer-source legend { font-size:.72rem; font-weight:800; }
230
+ .uhcp-transfer-source label { align-items:start; display:flex; gap:.45rem; padding:.35rem 0; }
231
+ .uhcp-transfer-source label span { display:grid; }
232
+ .uhcp-transfer-source label small { color:#60738c; font-size:.68rem; }
233
+ .uhcp-transfer-arrow { align-items:center; color:#0796a8; display:grid; flex:0 0 5rem; grid-template-columns:1fr auto; text-align:center; }
234
+ .uhcp-transfer-arrow span { font-size:.7rem; font-weight:800; grid-column:1/-1; }
235
+ .uhcp-transfer-arrow i { background:#0796a8; height:2px; }
236
+ .uhcp-transfer-arrow svg { margin-left:-.45rem; }
237
+ .uhcp-transfer-help { background:#f4f9fc; border-radius:.5rem; padding:.65rem .8rem; }
238
+ .uhcp-transfer-help summary { cursor:pointer; font-size:.78rem; font-weight:800; }
239
+ .uhcp-transfer-help p { color:#51677e; font-size:.78rem; margin:.4rem 0 0; }
240
+ .uhcp-transfer-controls { display:flex; gap:.55rem; justify-content:flex-end; padding-top:.75rem; }
241
+ .uhcp-transfer-controls button { background:#fff; border:1px solid #0796a8; border-radius:.45rem; color:#08738a; padding:.7rem 1rem; }
242
+ .uhcp-transfer-review { margin-top:.8rem; padding:1rem; }
243
+ .uhcp-transfer-review header p { background:#fff5dd; border:1px solid #f3ce79; border-radius:.4rem; color:#925800; font-size:.72rem; margin:0; padding:.5rem .7rem; }
244
+ .uhcp-transfer-review ol { list-style:none; margin:.7rem 0 0; padding:0; }
245
+ .uhcp-transfer-review li { align-items:center; border-top:1px solid #e1e8ee; display:grid; gap:.7rem; grid-template-columns:1.8rem 1fr auto; padding:.55rem; }
246
+ .uhcp-transfer-review li>span { align-items:center; background:#e8f6fc; border-radius:50%; color:#087db8; display:flex; font-size:.72rem; font-weight:900; height:1.7rem; justify-content:center; width:1.7rem; }
247
+ .uhcp-transfer-review li strong { font-size:.8rem; }
248
+ .uhcp-transfer-review details { font-size:.68rem; }
249
+ .uhcp-transfer-review summary { color:#60738c; cursor:pointer; }
250
+ .uhcp-transfer-status { background:#dff6e8; border-radius:.45rem; color:#087a47; font-weight:750; padding:.75rem; }
251
+ @media(max-width:900px){.uhcp-transfer-console{grid-template-columns:1fr}.uhcp-transfer-contacts{border-bottom:1px solid #dce5ec;border-inline-end:0}.uhcp-transfer-contact-actions{grid-template-columns:repeat(3,1fr)}.uhcp-transfer-patient>div{grid-template-columns:1fr}.uhcp-transfer-patient>div>span{display:none}.uhcp-transfer-review>header{align-items:flex-start;gap:.7rem;flex-direction:column}}
252
+ @media(max-width:560px){.uhcp-transfer-main{padding:.55rem}.uhcp-transfer-contact-actions{grid-template-columns:1fr}.uhcp-transfer-rail{align-items:stretch}.uhcp-transfer-review li{grid-template-columns:1.8rem 1fr}.uhcp-transfer-review li details{grid-column:2}.uhcp-transfer-controls button{flex:1}.uhcp-transfer-review header p{font-size:.65rem}}
253
+
175
254
  .uhcp-identity-workspace {
176
255
  background: var(--uhcp-panel);
177
256
  border: 1px solid var(--uhcp-border);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uhc-portal-components-react",
3
- "version": "0.1.18",
3
+ "version": "0.1.19",
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",