uhc-portal-components-react 0.1.44 → 0.1.46
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 +21 -0
- package/dist/ClinicalArtifactEditor.d.ts +14 -0
- package/dist/ClinicalArtifactEditor.d.ts.map +1 -1
- package/dist/ClinicalArtifactEditor.js +62 -15
- package/dist/ClinicalBundleDraftEditor.d.ts +4 -0
- package/dist/ClinicalBundleDraftEditor.d.ts.map +1 -1
- package/dist/ClinicalBundleDraftEditor.js +35 -4
- package/dist/styles.css +21 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.1.46 - 2026-10-08
|
|
6
|
+
|
|
7
|
+
- Create clinical Bundle entries through explicit section and resource-type
|
|
8
|
+
selectors, followed by one accessible `+ Add entry` action. Keep the staged
|
|
9
|
+
entries grouped in collapsible sections with their existing edit and delete
|
|
10
|
+
actions.
|
|
11
|
+
- Let every schema-driven clinical resource form stage several PDF, PNG or
|
|
12
|
+
JPEG documents. Each file becomes an independent claims-first
|
|
13
|
+
`DocumentReference` with SHA-256 content hash and is linked from the parent
|
|
14
|
+
resource through its canonical `contained-reference-list`; files remain
|
|
15
|
+
local until the final Bundle submission.
|
|
16
|
+
|
|
17
|
+
## 0.1.45 - 2026-10-07
|
|
18
|
+
|
|
19
|
+
- Present governed terminology sources as a compact dropdown with checkboxes,
|
|
20
|
+
retaining the server default while allowing several systems at once.
|
|
21
|
+
- Resolve each terminology default from the exact resource and coded claim;
|
|
22
|
+
no coding system is assumed globally. Render required FHIR R4 code bindings
|
|
23
|
+
from `fhir-data-utils-ts` with localized labels while persisting their
|
|
24
|
+
canonical codes.
|
|
25
|
+
|
|
5
26
|
## 0.1.44 - 2026-10-07
|
|
6
27
|
|
|
7
28
|
- Let the shared IPS editor hydrate claims-first resources from an imported
|
|
@@ -22,6 +22,8 @@ export type ClinicalArtifactEditorRequest = Readonly<{
|
|
|
22
22
|
}>;
|
|
23
23
|
/** Authoritative claims-first provider Bundle hydrated through BundleReader. */
|
|
24
24
|
initialBundle?: Readonly<Record<string, unknown>>;
|
|
25
|
+
/** Documents already staged with this local entry. */
|
|
26
|
+
initialAttachments?: readonly ClinicalArtifactAttachment[];
|
|
25
27
|
}>;
|
|
26
28
|
export type ClinicalArtifactDraft = Readonly<{
|
|
27
29
|
resourceType: string;
|
|
@@ -33,6 +35,15 @@ export type ClinicalArtifactDraft = Readonly<{
|
|
|
33
35
|
operationValues?: MultichannelOperationValues;
|
|
34
36
|
/** Claims-first batch produced by the shared BundleEditor. */
|
|
35
37
|
changesBundle?: ClinicalArtifactChangesBundle;
|
|
38
|
+
/** Local document evidence linked to this entry when the enclosing Bundle is built. */
|
|
39
|
+
attachments?: readonly ClinicalArtifactAttachment[];
|
|
40
|
+
}>;
|
|
41
|
+
export type ClinicalArtifactAttachment = Readonly<{
|
|
42
|
+
id: string;
|
|
43
|
+
name: string;
|
|
44
|
+
contentType: 'application/pdf' | 'image/jpeg' | 'image/png';
|
|
45
|
+
contentHash: string;
|
|
46
|
+
dataBase64: string;
|
|
36
47
|
}>;
|
|
37
48
|
export type ClinicalArtifactChangesBundle = Readonly<{
|
|
38
49
|
resourceType: string;
|
|
@@ -89,6 +100,9 @@ export type ClinicalArtifactEditorCopy = Readonly<{
|
|
|
89
100
|
readbackMissing: string;
|
|
90
101
|
pending?: string;
|
|
91
102
|
retry?: string;
|
|
103
|
+
attachments?: string;
|
|
104
|
+
addAttachments?: string;
|
|
105
|
+
removeAttachment?: string;
|
|
92
106
|
dateTime?: ClinicalDateTimeFieldLabels;
|
|
93
107
|
}>;
|
|
94
108
|
export type ClinicalArtifactSaveOutcome = Readonly<{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClinicalArtifactEditor.d.ts","sourceRoot":"","sources":["../src/ClinicalArtifactEditor.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,kDAAkD,CAAA;
|
|
1
|
+
{"version":3,"file":"ClinicalArtifactEditor.d.ts","sourceRoot":"","sources":["../src/ClinicalArtifactEditor.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useEffect, useId, useMemo, useRef, useState } from 'react';
|
|
4
|
-
import { clinicalArtifactEditorClaimsFromFhirR4, clinicalArtifactFhirR4ToFlat, composeFhirDateTimeFromLocalParts, splitFhirDateTimeForInput, } from 'fhir-data-utils-ts';
|
|
4
|
+
import { clinicalArtifactEditorClaimsFromFhirR4, clinicalArtifactFhirR4ToFlat, clinicalArtifactCodedOptionsForClaim, composeFhirDateTimeFromLocalParts, splitFhirDateTimeForInput, } from 'fhir-data-utils-ts';
|
|
5
5
|
import { buildMultichannelOperationBundle, MultichannelOperationMode, readMultichannelOperationFromBundle, selectMultichannelOperationClaimValues, } from 'sos-data-utils-ts/multichannel-operation-schemas';
|
|
6
6
|
import { ClinicalEditorLayer } from './ClinicalEditorLayer.js';
|
|
7
7
|
import { ClinicalSpeechInputButton } from './ClinicalSpeechInput.js';
|
|
@@ -57,6 +57,7 @@ export function ClinicalArtifactEditor({ request, schema, operationSchema, autho
|
|
|
57
57
|
const [selectedTerminologySources, setSelectedTerminologySources] = useState([]);
|
|
58
58
|
const [terminologySourcesClaim, setTerminologySourcesClaim] = useState('');
|
|
59
59
|
const [saving, setSaving] = useState(false);
|
|
60
|
+
const [attachments, setAttachments] = useState(request.initialAttachments ?? []);
|
|
60
61
|
const [error, setError] = useState('');
|
|
61
62
|
const [pending, setPending] = useState('');
|
|
62
63
|
const draftId = useRef(request.artifactId ?? crypto.randomUUID());
|
|
@@ -130,6 +131,7 @@ export function ClinicalArtifactEditor({ request, schema, operationSchema, autho
|
|
|
130
131
|
sectionCode: request.sectionCode,
|
|
131
132
|
mode: request.mode,
|
|
132
133
|
claims,
|
|
134
|
+
attachments,
|
|
133
135
|
...(operationSchema ? buildOperationDraft(operationSchema, authoringContext, request, draftId.current, claims) : {}),
|
|
134
136
|
});
|
|
135
137
|
if (!result)
|
|
@@ -155,12 +157,19 @@ export function ClinicalArtifactEditor({ request, schema, operationSchema, autho
|
|
|
155
157
|
setSaving(false);
|
|
156
158
|
}
|
|
157
159
|
}
|
|
160
|
+
function toggleTerminologySource(sourceId, selected) {
|
|
161
|
+
setSelectedTerminologySources(current => {
|
|
162
|
+
const next = selected ? [...new Set([...current, sourceId])] : current.filter(candidate => candidate !== sourceId);
|
|
163
|
+
return next.length ? next : current;
|
|
164
|
+
});
|
|
165
|
+
}
|
|
158
166
|
return _jsx(ClinicalEditorLayer, { onDismiss: onCancel, children: _jsxs("section", { className: "uhcp-clinical-editor", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, "aria-describedby": descriptionId, children: [_jsxs("header", { children: [_jsxs("div", { children: [_jsx("h2", { id: titleId, children: copy.title }), _jsx("p", { id: descriptionId, children: copy.description })] }), _jsx("button", { type: "button", onClick: onCancel, "aria-label": copy.close, children: "\u00D7" })] }), _jsxs("form", { onSubmit: (event) => { event.preventDefault(); void submit(); }, children: [fields.map((claim) => {
|
|
159
167
|
const parameter = claim.slice(request.resourceType.length + 1);
|
|
160
168
|
const label = fieldLabel(claim);
|
|
161
169
|
const terminologyEnabled = Boolean(searchTerminology && terminologyCodeClaim(request.resourceType, claim));
|
|
162
170
|
const inputId = `${titleId}-${claim}`;
|
|
163
171
|
const value = claims[claim] ?? '';
|
|
172
|
+
const codedOptions = clinicalArtifactCodedOptionsForClaim(claim, locale);
|
|
164
173
|
const schemaNode = operationSchema?.properties.claims?.properties?.[claim];
|
|
165
174
|
const update = (event) => {
|
|
166
175
|
setClaims((current) => ({ ...current, [claim]: event.target.value }));
|
|
@@ -178,13 +187,60 @@ export function ClinicalArtifactEditor({ request, schema, operationSchema, autho
|
|
|
178
187
|
if (terminologyEnabled)
|
|
179
188
|
setActiveTerminologyClaim(claim);
|
|
180
189
|
};
|
|
181
|
-
return _jsxs("div", { className: fieldClassName, children: [_jsxs("span", { className: "uhcp-clinical-editor-field-heading", children: [_jsxs("label", { htmlFor: inputId, children: [label, requiredClaims.has(claim) ? ' *' : ''] }), isSpeechCompatibleField(parameter, schemaNode) ? _jsx(ClinicalSpeechInputButton, { resourceType: request.resourceType, claim: claim, locale: locale, fieldLabel: label, onTranscript: appendTranscript }) : null] }),
|
|
182
|
-
: _jsx("input", { id: inputId, "aria-label": label, value: value, required: requiredClaims.has(claim), type: fieldInputType(parameter, operationSchema?.properties.claims?.properties?.[claim]), onChange: update }), terminologyEnabled && activeTerminologyClaim === claim ? _jsxs("div", { className: "uhcp-terminology-results", children: [terminologySources.length ? _jsxs("
|
|
190
|
+
return _jsxs("div", { className: fieldClassName, children: [_jsxs("span", { className: "uhcp-clinical-editor-field-heading", children: [_jsxs("label", { htmlFor: inputId, children: [label, requiredClaims.has(claim) ? ' *' : ''] }), isSpeechCompatibleField(parameter, schemaNode, codedOptions.length > 0) ? _jsx(ClinicalSpeechInputButton, { resourceType: request.resourceType, claim: claim, locale: locale, fieldLabel: label, onTranscript: appendTranscript }) : null] }), codedOptions.length ? _jsxs("select", { id: inputId, "aria-label": label, value: value, required: requiredClaims.has(claim), onChange: update, children: [!requiredClaims.has(claim) ? _jsx("option", { value: "" }) : null, codedOptions.map((option) => _jsx("option", { value: option.code, children: option.label }, option.code))] }) : isMultiline(parameter) ? _jsx("textarea", { id: inputId, "aria-label": label, value: value, required: requiredClaims.has(claim), rows: 3, onChange: update })
|
|
191
|
+
: _jsx("input", { id: inputId, "aria-label": label, value: value, required: requiredClaims.has(claim), type: fieldInputType(parameter, operationSchema?.properties.claims?.properties?.[claim]), onChange: update }), terminologyEnabled && activeTerminologyClaim === claim ? _jsxs("div", { className: "uhcp-terminology-results", children: [terminologySources.length ? _jsxs("details", { className: "uhcp-terminology-source-picker", children: [_jsxs("summary", { children: [copy.terminologySources || 'Coding systems', ": ", terminologySources.filter(source => selectedTerminologySources.includes(source.id)).map(source => source.label || source.id).join(', ')] }), _jsxs("fieldset", { "aria-label": copy.terminologySources || 'Coding systems', children: [_jsx("legend", { className: "uhcp-sr-only", children: copy.terminologySources || 'Coding systems' }), terminologySources.map(source => _jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: selectedTerminologySources.includes(source.id), onChange: event => toggleTerminologySource(source.id, event.currentTarget.checked) }), _jsx("span", { children: source.label || source.id })] }, source.id))] })] }) : null, terminologyBusy ? _jsx("small", { role: "status", children: copy.terminologyLoading }) : null, terminologyError ? _jsx("small", { role: "alert", children: copy.terminologyUnavailable }) : null, candidates.length ? _jsx("ul", { children: candidates.map((candidate) => _jsx("li", { children: _jsxs("button", { type: "button", onClick: () => {
|
|
183
192
|
setClaims((current) => selectedCodingClaims(request.resourceType, claim, candidate, acceptedClaims, current));
|
|
184
193
|
setCandidates([]);
|
|
185
194
|
setActiveTerminologyClaim(undefined);
|
|
186
195
|
}, children: [candidate.display, _jsxs("small", { children: [candidate.system, " \u00B7 ", candidate.code] })] }) }, `${candidate.system}|${candidate.code}`)) }) : null] }) : null] }, claim);
|
|
187
|
-
}),
|
|
196
|
+
}), _jsxs("fieldset", { className: "uhcp-clinical-editor-attachments", children: [_jsx("legend", { children: copy.attachments || 'Documents' }), _jsxs("label", { children: [_jsx("span", { children: copy.addAttachments || 'Add PDF or image' }), _jsx("input", { type: "file", multiple: true, accept: "application/pdf,image/png,image/jpeg,.pdf,.png,.jpg,.jpeg", "aria-label": copy.addAttachments || 'Add PDF or image', onChange: (event) => {
|
|
197
|
+
const files = [...(event.currentTarget.files ?? [])];
|
|
198
|
+
event.currentTarget.value = '';
|
|
199
|
+
void Promise.all(files.map(readClinicalAttachment)).then((next) => {
|
|
200
|
+
setAttachments((current) => [...current, ...next]);
|
|
201
|
+
}).catch((reason) => setError(reason instanceof Error ? reason.message : String(reason)));
|
|
202
|
+
} })] }), attachments.length ? _jsx("ul", { children: attachments.map((attachment) => _jsxs("li", { children: [_jsx("span", { children: attachment.name }), _jsx("button", { type: "button", "aria-label": `${copy.removeAttachment || 'Remove document'} ${attachment.name}`, onClick: () => setAttachments(current => current.filter(candidate => candidate.id !== attachment.id)), children: "\u00D7" })] }, attachment.id)) }) : null] }), error ? _jsx("p", { className: "uhcp-clinical-editor-error", role: "alert", children: error }) : null, pending ? _jsx("p", { className: "uhcp-clinical-editor-pending", role: "status", children: copy.pending || pending }) : null, _jsxs("footer", { children: [_jsx("button", { type: "button", onClick: onCancel, children: copy.cancel }), _jsx("button", { type: "submit", disabled: saving, children: saving ? copy.saving : pending ? (copy.retry || copy.save) : copy.save })] })] })] }) });
|
|
203
|
+
}
|
|
204
|
+
async function readClinicalAttachment(file) {
|
|
205
|
+
const contentType = normalizeClinicalAttachmentType(file);
|
|
206
|
+
const bytes = new Uint8Array(await readFileBytes(file));
|
|
207
|
+
const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));
|
|
208
|
+
return Object.freeze({
|
|
209
|
+
id: crypto.randomUUID(),
|
|
210
|
+
name: file.name,
|
|
211
|
+
contentType,
|
|
212
|
+
contentHash: `sha256:${hex(digest)}`,
|
|
213
|
+
dataBase64: bytesToBase64(bytes),
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
function normalizeClinicalAttachmentType(file) {
|
|
217
|
+
if (file.type === 'application/pdf' || file.type === 'image/png' || file.type === 'image/jpeg')
|
|
218
|
+
return file.type;
|
|
219
|
+
const extension = file.name.toLowerCase().split('.').pop();
|
|
220
|
+
if (extension === 'pdf')
|
|
221
|
+
return 'application/pdf';
|
|
222
|
+
if (extension === 'png')
|
|
223
|
+
return 'image/png';
|
|
224
|
+
if (extension === 'jpg' || extension === 'jpeg')
|
|
225
|
+
return 'image/jpeg';
|
|
226
|
+
throw new TypeError('clinical_attachment_type_unsupported');
|
|
227
|
+
}
|
|
228
|
+
function readFileBytes(file) {
|
|
229
|
+
return new Promise((resolve, reject) => {
|
|
230
|
+
const reader = new FileReader();
|
|
231
|
+
reader.onerror = () => reject(reader.error ?? new Error('clinical_attachment_read_failed'));
|
|
232
|
+
reader.onload = () => reader.result instanceof ArrayBuffer ? resolve(reader.result) : reject(new Error('clinical_attachment_read_failed'));
|
|
233
|
+
reader.readAsArrayBuffer(file);
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
function bytesToBase64(bytes) {
|
|
237
|
+
let binary = '';
|
|
238
|
+
for (let index = 0; index < bytes.length; index += 1)
|
|
239
|
+
binary += String.fromCharCode(bytes[index] ?? 0);
|
|
240
|
+
return btoa(binary);
|
|
241
|
+
}
|
|
242
|
+
function hex(bytes) {
|
|
243
|
+
return [...bytes].map(value => value.toString(16).padStart(2, '0')).join('');
|
|
188
244
|
}
|
|
189
245
|
const DEFAULT_DATE_TIME_LABELS = Object.freeze({
|
|
190
246
|
date: 'Date',
|
|
@@ -223,8 +279,8 @@ function composeTemporalClaim(parts, timeZone) {
|
|
|
223
279
|
function isDateTimeSchemaNode(schemaNode) {
|
|
224
280
|
return schemaNode?.format === 'date-time' || schemaNode?.format === 'fhir-date-time';
|
|
225
281
|
}
|
|
226
|
-
function isSpeechCompatibleField(parameter, schemaNode) {
|
|
227
|
-
if (
|
|
282
|
+
function isSpeechCompatibleField(parameter, schemaNode, hasCodedOptions = false) {
|
|
283
|
+
if (hasCodedOptions)
|
|
228
284
|
return false;
|
|
229
285
|
if (schemaNode?.type === 'number' || schemaNode?.type === 'integer' || schemaNode?.type === 'boolean')
|
|
230
286
|
return false;
|
|
@@ -275,15 +331,6 @@ function defaultClaims(resourceType) {
|
|
|
275
331
|
return { [`${resourceType}.clinical-status`]: 'active' };
|
|
276
332
|
return {};
|
|
277
333
|
}
|
|
278
|
-
function statusOptions(resourceType, parameter) {
|
|
279
|
-
if (parameter !== 'status' && !parameter.endsWith('-status'))
|
|
280
|
-
return undefined;
|
|
281
|
-
if (resourceType === 'Immunization')
|
|
282
|
-
return ['completed', 'not-done', 'entered-in-error'];
|
|
283
|
-
if (resourceType === 'Observation' || resourceType === 'DiagnosticReport')
|
|
284
|
-
return ['final', 'preliminary', 'amended', 'entered-in-error'];
|
|
285
|
-
return ['active', 'completed', 'inactive', 'entered-in-error'];
|
|
286
|
-
}
|
|
287
334
|
function terminologyCodeClaim(resourceType, inputClaim) {
|
|
288
335
|
const parameter = inputClaim.slice(resourceType.length + 1);
|
|
289
336
|
// `code-text` is the generic primary-concept alias. Immunization deliberately
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import 'gdc-common-utils-ts/utils/allergy-intolerance-entry-editor';
|
|
2
2
|
import 'gdc-common-utils-ts/utils/condition-entry-editor';
|
|
3
|
+
import 'gdc-common-utils-ts/utils/document-reference-entry-editor';
|
|
3
4
|
import 'gdc-common-utils-ts/utils/immunization-entry-editor';
|
|
4
5
|
import 'gdc-common-utils-ts/utils/medication-statement-entry-editor';
|
|
5
6
|
import 'gdc-common-utils-ts/utils/observation-entry-editor';
|
|
@@ -26,6 +27,9 @@ export type ClinicalBundleDraftEditorCopy = Readonly<{
|
|
|
26
27
|
description: string;
|
|
27
28
|
empty: string;
|
|
28
29
|
add: string;
|
|
30
|
+
section?: string;
|
|
31
|
+
resourceType?: string;
|
|
32
|
+
addEntry?: string;
|
|
29
33
|
edit: string;
|
|
30
34
|
remove: string;
|
|
31
35
|
submit: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClinicalBundleDraftEditor.d.ts","sourceRoot":"","sources":["../src/ClinicalBundleDraftEditor.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ClinicalBundleDraftEditor.d.ts","sourceRoot":"","sources":["../src/ClinicalBundleDraftEditor.tsx"],"names":[],"mappings":"AAQA,OAAO,4DAA4D,CAAA;AACnE,OAAO,kDAAkD,CAAA;AACzD,OAAO,2DAA2D,CAAA;AAClE,OAAO,qDAAqD,CAAA;AAC5D,OAAO,6DAA6D,CAAA;AACpE,OAAO,oDAAoD,CAAA;AAC3D,OAAO,kDAAkD,CAAA;AACzD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,kDAAkD,CAAA;AACnG,OAAO,EAEL,KAAK,gCAAgC,EAErC,KAAK,0BAA0B,EAE/B,KAAK,sBAAsB,EAC3B,KAAK,yBAAyB,EAC9B,KAAK,4BAA4B,EACjC,KAAK,+BAA+B,EACrC,MAAM,6BAA6B,CAAA;AAGpC,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAAC;IAC/C,MAAM,EAAE,sBAAsB,CAAA;IAC9B,eAAe,EAAE,2BAA2B,CAAA;IAC5C,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,EAAE,MAAM,CAAA;CACtB,CAAC,CAAA;AAEF,MAAM,MAAM,mBAAmB,GAAG,QAAQ,CAAC;IACzC,YAAY,EAAE,QAAQ,CAAA;IACtB,IAAI,EAAE,UAAU,CAAA;IAChB,KAAK,EAAE,SAAS,OAAO,EAAE,CAAA;CAC1B,CAAC,CAAA;AAEF,MAAM,MAAM,gCAAgC,GAAG,QAAQ,CAAC;IACtD,KAAK,EAAE,WAAW,GAAG,SAAS,GAAG,WAAW,GAAG,UAAU,CAAA;IACzD,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB,CAAC,CAAA;AAEF,MAAM,MAAM,6BAA6B,GAAG,QAAQ,CAAC;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,UAAU,EAAE,MAAM,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,0BAA0B,CAAA;CACnC,CAAC,CAAA;AAEF,MAAM,MAAM,8BAA8B,GAAG,QAAQ,CAAC;IACpD,OAAO,EAAE,SAAS,yBAAyB,EAAE,CAAA;IAC7C,gBAAgB,EAAE,gCAAgC,CAAA;IAClD,IAAI,EAAE,6BAA6B,CAAA;IACnC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAA;IACrC,iBAAiB,CAAC,EAAE,CAAC,KAAK,EAAE,yBAAyB,KAAK,OAAO,CAAC,SAAS,4BAA4B,EAAE,CAAC,CAAA;IAC1G,sBAAsB,CAAC,EAAE,+BAA+B,CAAA;IACxD,oGAAoG;IACpG,aAAa,CAAC,EAAE,mBAAmB,CAAA;IACnC,aAAa,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,OAAO,CAAC,gCAAgC,CAAC,CAAA;CAC1F,CAAC,CAAA;AAYF;;;;;;GAMG;AACH,wBAAgB,yBAAyB,CAAC,EACxC,OAAO,EACP,gBAAgB,EAChB,IAAI,EACJ,MAAa,EACb,QAAQ,EACR,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,aAAa,GACd,EAAE,8BAA8B,+BAgGhC"}
|
|
@@ -5,8 +5,10 @@ import { BundleEditor } from 'gdc-common-utils-ts/utils/bundle-editor-core';
|
|
|
5
5
|
import { BundleTypes } from 'gdc-common-utils-ts/models/bundle-editor-types';
|
|
6
6
|
import { HealthcareDocumentTypes } from 'gdc-common-utils-ts/constants/healthcare';
|
|
7
7
|
import { ClinicalResourceEntryEditor } from 'gdc-common-utils-ts/utils/clinical-resource-entry-editor';
|
|
8
|
+
import { buildDocumentReferenceFlatEntry } from 'fhir-data-utils-ts/flat-claim-resource-graph';
|
|
8
9
|
import 'gdc-common-utils-ts/utils/allergy-intolerance-entry-editor';
|
|
9
10
|
import 'gdc-common-utils-ts/utils/condition-entry-editor';
|
|
11
|
+
import 'gdc-common-utils-ts/utils/document-reference-entry-editor';
|
|
10
12
|
import 'gdc-common-utils-ts/utils/immunization-entry-editor';
|
|
11
13
|
import 'gdc-common-utils-ts/utils/medication-statement-entry-editor';
|
|
12
14
|
import 'gdc-common-utils-ts/utils/observation-entry-editor';
|
|
@@ -27,6 +29,10 @@ export function ClinicalBundleDraftEditor({ schemas, authoringContext, copy, loc
|
|
|
27
29
|
const [error, setError] = useState('');
|
|
28
30
|
const [submitting, setSubmitting] = useState(false);
|
|
29
31
|
const sections = useMemo(() => groupSchemas(schemas), [schemas]);
|
|
32
|
+
const [selectedSection, setSelectedSection] = useState(() => groupSchemas(schemas)[0]?.label ?? '');
|
|
33
|
+
const [selectedSchemaKey, setSelectedSchemaKey] = useState(() => schemas[0] ? schemaKey(schemas[0]) : '');
|
|
34
|
+
const selectedSectionSchemas = sections.find(section => section.label === selectedSection)?.schemas ?? [];
|
|
35
|
+
const selectedSchema = selectedSectionSchemas.find(candidate => schemaKey(candidate) === selectedSchemaKey) ?? selectedSectionSchemas[0];
|
|
30
36
|
function stageArtifact(draft) {
|
|
31
37
|
if (!editor)
|
|
32
38
|
throw new TypeError('clinical_bundle_draft_editor_schema_required');
|
|
@@ -62,9 +68,14 @@ export function ClinicalBundleDraftEditor({ schemas, authoringContext, copy, loc
|
|
|
62
68
|
setSubmitting(false);
|
|
63
69
|
}
|
|
64
70
|
}
|
|
65
|
-
return _jsxs("section", { className: "uhcp-clinical-bundle-draft", "data-clinical-bundle-draft": true, children: [_jsxs("header", { children: [_jsx("h2", { children: copy.title }), _jsx("p", { children: copy.description })] }), notice ? _jsx("p", { role: "status", children: notice }) : null, error ? _jsx("p", { role: "alert", className: "uhcp-clinical-editor-error", children: error }) : null, sections.
|
|
71
|
+
return _jsxs("section", { className: "uhcp-clinical-bundle-draft", "data-clinical-bundle-draft": true, children: [_jsxs("header", { children: [_jsx("h2", { children: copy.title }), _jsx("p", { children: copy.description })] }), notice ? _jsx("p", { role: "status", children: notice }) : null, error ? _jsx("p", { role: "alert", className: "uhcp-clinical-editor-error", children: error }) : null, sections.length ? _jsxs("div", { className: "uhcp-clinical-bundle-draft-create", children: [_jsxs("label", { children: [copy.section || 'Section', _jsx("select", { value: selectedSection, onChange: (event) => {
|
|
72
|
+
const nextSection = event.currentTarget.value;
|
|
73
|
+
const firstSchema = sections.find(section => section.label === nextSection)?.schemas[0];
|
|
74
|
+
setSelectedSection(nextSection);
|
|
75
|
+
setSelectedSchemaKey(firstSchema ? schemaKey(firstSchema) : '');
|
|
76
|
+
}, children: sections.map(section => _jsx("option", { value: section.label, children: section.label }, section.label)) })] }), _jsxs("label", { children: [copy.resourceType || 'Resource type', _jsx("select", { value: selectedSchema ? schemaKey(selectedSchema) : '', onChange: (event) => setSelectedSchemaKey(event.currentTarget.value), children: selectedSectionSchemas.map(candidate => _jsx("option", { value: schemaKey(candidate), children: candidate.artifactLabel }, schemaKey(candidate))) })] }), _jsxs("button", { type: "button", disabled: !selectedSchema, onClick: () => selectedSchema && setEditor({ schema: selectedSchema }), children: ["+ ", copy.addEntry || copy.add] })] }) : null, sections.map(({ label }) => {
|
|
66
77
|
const sectionArtifacts = artifacts.filter((artifact) => artifact.schema.sectionLabel === label);
|
|
67
|
-
return _jsxs("details", { open: true, children: [_jsxs("summary", { children: [label, " (", sectionArtifacts.length, ")"] }),
|
|
78
|
+
return _jsxs("details", { open: true, children: [_jsxs("summary", { children: [label, " (", sectionArtifacts.length, ")"] }), sectionArtifacts.length === 0 ? _jsx("p", { children: copy.empty }) : _jsx("ul", { children: sectionArtifacts.map((artifact) => {
|
|
68
79
|
const title = artifactTitle(artifact.draft);
|
|
69
80
|
return _jsxs("li", { children: [_jsxs("span", { children: [_jsx("strong", { children: title }), _jsx("small", { children: artifact.draft.resourceType })] }), _jsxs("span", { children: [_jsx(ClinicalActionButton, { kind: "edit", label: `${copy.edit} ${title}`, onClick: () => setEditor({ schema: artifact.schema, draft: artifact.draft }) }), _jsx(ClinicalActionButton, { kind: "delete", label: `${copy.remove} ${title}`, onClick: () => setArtifacts((current) => current.filter((candidate) => candidate.draft.id !== artifact.draft.id)) })] })] }, artifact.draft.id);
|
|
70
81
|
}) })] }, label);
|
|
@@ -75,7 +86,7 @@ function editorRequest(editor) {
|
|
|
75
86
|
resourceType: editor.schema.schema.resourceType,
|
|
76
87
|
sectionCode: editor.schema.schema.sectionCode ?? '',
|
|
77
88
|
mode: 'create',
|
|
78
|
-
...(editor.draft ? { artifactId: editor.draft.id, initialClaims: editor.draft.claims } : { initialClaims: editor.schema.schema.initialClaims }),
|
|
89
|
+
...(editor.draft ? { artifactId: editor.draft.id, initialClaims: editor.draft.claims, initialAttachments: editor.draft.attachments } : { initialClaims: editor.schema.schema.initialClaims }),
|
|
79
90
|
};
|
|
80
91
|
}
|
|
81
92
|
function combineDrafts(artifacts, authoringContext, documentTitle) {
|
|
@@ -97,13 +108,33 @@ function combineDrafts(artifacts, authoringContext, documentTitle) {
|
|
|
97
108
|
}]);
|
|
98
109
|
}
|
|
99
110
|
for (const { draft } of artifacts) {
|
|
111
|
+
const attachments = draft.attachments ?? [];
|
|
112
|
+
const claims = {
|
|
113
|
+
...operationClaims(draft),
|
|
114
|
+
...(attachments.length ? { [`${draft.resourceType}.contained-reference-list`]: attachments.map(attachment => `DocumentReference/${attachment.id}`).join(',') } : {}),
|
|
115
|
+
};
|
|
100
116
|
const entry = editor.newEntryAs(draft.resourceType, draft.id);
|
|
101
|
-
for (const [claim, value] of Object.entries(
|
|
117
|
+
for (const [claim, value] of Object.entries(claims))
|
|
102
118
|
entry.setClaim(claim, value);
|
|
103
119
|
if (!(entry instanceof ClinicalResourceEntryEditor)) {
|
|
104
120
|
throw new TypeError(`clinical_bundle_draft_resource_unsupported:${draft.resourceType}`);
|
|
105
121
|
}
|
|
106
122
|
entry.setSectionList([draft.sectionCode]);
|
|
123
|
+
for (const attachment of attachments) {
|
|
124
|
+
const document = buildDocumentReferenceFlatEntry({
|
|
125
|
+
entryId: attachment.id,
|
|
126
|
+
identifier: attachment.id,
|
|
127
|
+
contentType: attachment.contentType,
|
|
128
|
+
contentHash: attachment.contentHash,
|
|
129
|
+
title: attachment.name,
|
|
130
|
+
dataBase64: attachment.dataBase64,
|
|
131
|
+
});
|
|
132
|
+
const documentEntry = editor.newEntryAs(document.resourceType, document.entryId);
|
|
133
|
+
for (const [claim, value] of Object.entries(document.claims))
|
|
134
|
+
documentEntry.setClaim(claim, value);
|
|
135
|
+
documentEntry.setClaim('DocumentReference.subject', authoringContext.subjectReference);
|
|
136
|
+
documentEntry.setClaim('DocumentReference.author', authoringContext.dataAuthorReference);
|
|
137
|
+
}
|
|
107
138
|
}
|
|
108
139
|
return editor.buildDocument();
|
|
109
140
|
}
|
package/dist/styles.css
CHANGED
|
@@ -237,6 +237,15 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
|
|
|
237
237
|
.uhcp-terminology-results ul { display:grid; gap:.35rem; list-style:none; margin:.25rem 0 0; padding:0; }
|
|
238
238
|
.uhcp-terminology-results button { background:var(--uhcp-surface-muted); color:inherit; display:grid; text-align:start; width:100%; }
|
|
239
239
|
.uhcp-terminology-results small { color:var(--uhcp-muted); display:block; font-weight:400; }
|
|
240
|
+
.uhcp-terminology-source-picker { border:1px solid var(--uhcp-border); border-radius:.7rem; margin:.25rem 0; position:relative; }
|
|
241
|
+
.uhcp-terminology-source-picker summary { cursor:pointer; font-weight:750; list-style:none; padding:.7rem .8rem; }
|
|
242
|
+
.uhcp-terminology-source-picker summary::-webkit-details-marker { display:none; }
|
|
243
|
+
.uhcp-terminology-source-picker summary::after { content:'▾'; float:inline-end; }
|
|
244
|
+
.uhcp-terminology-source-picker[open] summary::after { content:'▴'; }
|
|
245
|
+
.uhcp-terminology-source-picker fieldset { background:var(--uhcp-panel); border:0; border-top:1px solid var(--uhcp-border); display:grid; gap:.45rem; margin:0; padding:.7rem .8rem; }
|
|
246
|
+
.uhcp-terminology-source-picker label { align-items:center; display:flex; gap:.55rem; }
|
|
247
|
+
.uhcp-terminology-source-picker input { margin:0; width:auto; }
|
|
248
|
+
.uhcp-sr-only { clip:rect(0,0,0,0); clip-path:inset(50%); height:1px; overflow:hidden; position:absolute; white-space:nowrap; width:1px; }
|
|
240
249
|
@media (max-width:44rem) { .uhcp-clinical-editor form,.uhcp-emergency-contact-editor { grid-template-columns:1fr; } .uhcp-emergency-contact-directory>ul>li { align-items:stretch; flex-direction:column; } .uhcp-emergency-contact-directory nav { justify-content:flex-start; } }
|
|
241
250
|
|
|
242
251
|
.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); }
|
|
@@ -469,7 +478,11 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
|
|
|
469
478
|
.uhcp-clinical-bundle-draft>header p,.uhcp-clinical-bundle-draft details>p { color:var(--uhcp-muted); }
|
|
470
479
|
.uhcp-clinical-bundle-draft details { background:var(--uhcp-panel-muted); border:1px solid var(--uhcp-border); border-radius:1rem; padding:.85rem 1rem; }
|
|
471
480
|
.uhcp-clinical-bundle-draft summary { cursor:pointer; font-weight:800; }
|
|
472
|
-
.uhcp-clinical-bundle-draft-
|
|
481
|
+
.uhcp-clinical-bundle-draft-create { align-items:end; background:var(--uhcp-panel-muted); border:1px solid var(--uhcp-border); border-radius:1rem; display:grid; gap:.8rem; grid-template-columns:minmax(10rem,1fr) minmax(10rem,1fr) auto; padding:1rem; }
|
|
482
|
+
.uhcp-clinical-bundle-draft-create label { display:grid; gap:.35rem; font-weight:700; }
|
|
483
|
+
.uhcp-clinical-bundle-draft-create select { background:var(--uhcp-panel); border:1px solid var(--uhcp-border); border-radius:.7rem; color:var(--uhcp-text); font:inherit; min-height:2.75rem; padding:.55rem .7rem; }
|
|
484
|
+
.uhcp-clinical-bundle-draft-create button { background:linear-gradient(135deg,var(--uhcp-action-start),var(--uhcp-action-end)); border:0; border-radius:.75rem; color:#fff; cursor:pointer; font:inherit; font-weight:800; min-height:2.75rem; padding:.65rem 1rem; }
|
|
485
|
+
.uhcp-clinical-bundle-draft-create button:disabled { cursor:not-allowed; opacity:.5; }
|
|
473
486
|
.uhcp-clinical-bundle-draft ul { display:grid; gap:.55rem; list-style:none; margin:.8rem 0 0; padding:0; }
|
|
474
487
|
.uhcp-clinical-bundle-draft li { align-items:center; background:var(--uhcp-panel); border:1px solid var(--uhcp-border); border-radius:.8rem; display:flex; gap:1rem; justify-content:space-between; padding:.7rem; }
|
|
475
488
|
.uhcp-clinical-bundle-draft li>span { display:flex; gap:.45rem; }
|
|
@@ -479,6 +492,13 @@ html[data-theme='dark'] .uhcp-brand-artwork-dark { display: block !important; }
|
|
|
479
492
|
.uhcp-clinical-bundle-draft>footer { display:flex; justify-content:flex-end; }
|
|
480
493
|
.uhcp-clinical-bundle-draft>footer button { background:linear-gradient(135deg,var(--uhcp-action-start),var(--uhcp-action-end)); border:0; border-radius:.75rem; color:#fff; cursor:pointer; font:inherit; font-weight:800; padding:.75rem 1rem; }
|
|
481
494
|
.uhcp-clinical-bundle-draft>footer button:disabled { cursor:not-allowed; opacity:.5; }
|
|
495
|
+
.uhcp-clinical-editor-attachments { border:1px solid var(--uhcp-border); border-radius:.85rem; display:grid; gap:.65rem; grid-column:1/-1; padding:.85rem; }
|
|
496
|
+
.uhcp-clinical-editor-attachments label { display:grid; gap:.35rem; }
|
|
497
|
+
.uhcp-clinical-editor-attachments input[type=file] { border:1px dashed var(--uhcp-border); border-radius:.7rem; padding:.65rem; }
|
|
498
|
+
.uhcp-clinical-editor-attachments ul { display:grid; gap:.4rem; list-style:none; margin:0; padding:0; }
|
|
499
|
+
.uhcp-clinical-editor-attachments li { align-items:center; background:var(--uhcp-panel-muted); border-radius:.65rem; display:flex; justify-content:space-between; padding:.5rem .65rem; }
|
|
500
|
+
.uhcp-clinical-editor-attachments li button { background:transparent; border:0; color:var(--uhcp-text); cursor:pointer; font-size:1.2rem; }
|
|
501
|
+
@media (max-width:720px) { .uhcp-clinical-bundle-draft-create { grid-template-columns:1fr; } }
|
|
482
502
|
.uhcp-clinical-title { font-weight: 800; margin: 0; }
|
|
483
503
|
.uhcp-clinical-type { color: var(--uhcp-muted); font-size: .72rem; font-weight: 800; letter-spacing: .06em; margin: .35rem 0 0; text-transform: uppercase; }
|
|
484
504
|
.uhcp-clinical-date, .uhcp-clinical-empty { color: var(--uhcp-muted); margin: .35rem 0 0; }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uhc-portal-components-react",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.46",
|
|
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",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"react-dom": ">=18.3.0"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"fhir-data-utils-ts": "0.6.
|
|
34
|
+
"fhir-data-utils-ts": "0.6.16",
|
|
35
35
|
"gdc-common-utils-ts": "2.9.30",
|
|
36
36
|
"sos-data-utils-ts": "0.6.3"
|
|
37
37
|
},
|