@eka-care/medical-records-ui 1.0.36 → 1.0.39
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/dist/{OriginalRecordPanel-IUZUPXY2.js → OriginalRecordPanel-PVNAZ5CR.js} +184 -78
- package/dist/OriginalRecordPanel-PVNAZ5CR.js.map +1 -0
- package/dist/{OriginalRecordPanel-GGRHXGWI.mjs → OriginalRecordPanel-W6FNO7U2.mjs} +176 -70
- package/dist/OriginalRecordPanel-W6FNO7U2.mjs.map +1 -0
- package/dist/VitalHistoryPanel-WI44AXJU.mjs +10 -0
- package/dist/VitalHistoryPanel-WKBIR2RD.js +10 -0
- package/dist/{VitalHistoryPanel-L4QTKZBC.js.map → VitalHistoryPanel-WKBIR2RD.js.map} +1 -1
- package/dist/{chunk-SO5RWBVJ.mjs → chunk-5TQ6OPAQ.mjs} +38 -73
- package/dist/chunk-5TQ6OPAQ.mjs.map +1 -0
- package/dist/{chunk-KWF6LUXK.js → chunk-GKREOUK2.js} +3 -3
- package/dist/{chunk-KWF6LUXK.js.map → chunk-GKREOUK2.js.map} +1 -1
- package/dist/{chunk-HNRF345J.mjs → chunk-LUH7D3K7.mjs} +33 -4
- package/dist/chunk-LUH7D3K7.mjs.map +1 -0
- package/dist/{chunk-32VKLNCO.mjs → chunk-MRQMRFWX.mjs} +2 -2
- package/dist/{chunk-LYPWE42A.js → chunk-VBMKRSTX.js} +40 -75
- package/dist/chunk-VBMKRSTX.js.map +1 -0
- package/dist/{chunk-TNTVD3TN.js → chunk-YT6OD4YU.js} +31 -2
- package/dist/chunk-YT6OD4YU.js.map +1 -0
- package/dist/index.css +150 -17
- package/dist/index.css.map +1 -1
- package/dist/index.js +80 -45
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +79 -44
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +150 -17
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/dist/OriginalRecordPanel-GGRHXGWI.mjs.map +0 -1
- package/dist/OriginalRecordPanel-IUZUPXY2.js.map +0 -1
- package/dist/VitalHistoryPanel-AQ6QVGCB.mjs +0 -10
- package/dist/VitalHistoryPanel-L4QTKZBC.js +0 -10
- package/dist/chunk-HNRF345J.mjs.map +0 -1
- package/dist/chunk-LYPWE42A.js.map +0 -1
- package/dist/chunk-SO5RWBVJ.mjs.map +0 -1
- package/dist/chunk-TNTVD3TN.js.map +0 -1
- /package/dist/{VitalHistoryPanel-AQ6QVGCB.mjs.map → VitalHistoryPanel-WI44AXJU.mjs.map} +0 -0
- /package/dist/{chunk-32VKLNCO.mjs.map → chunk-MRQMRFWX.mjs.map} +0 -0
|
@@ -2,11 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
-
var
|
|
5
|
+
var _chunkGKREOUK2js = require('./chunk-GKREOUK2.js');
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
|
|
10
|
+
var _chunkYT6OD4YUjs = require('./chunk-YT6OD4YU.js');
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
|
|
12
14
|
|
|
@@ -39,14 +41,18 @@ function OriginalRecordPanel({
|
|
|
39
41
|
const { store } = _chunk57BG7LVPjs.useSdk.call(void 0, );
|
|
40
42
|
const record = _zustand.useStore.call(void 0, store, (s) => s.records.byId[recordId]);
|
|
41
43
|
const recordsById = _zustand.useStore.call(void 0, store, (s) => s.records.byId);
|
|
42
|
-
const preview =
|
|
43
|
-
const {
|
|
44
|
-
const { status: vitalsStatus, table } =
|
|
44
|
+
const preview = _chunkYT6OD4YUjs.useRecordPreview.call(void 0, recordId);
|
|
45
|
+
const { replaceOriginal, onCopyToNote, onCopyVitalsToNote, hasCopyToNote } = _chunkYT6OD4YUjs.useSmartRecordsActions.call(void 0, );
|
|
46
|
+
const { status: vitalsStatus, table } = _chunkGKREOUK2js.useRecordPanelTable.call(void 0,
|
|
45
47
|
_optionalChain([record, 'optionalAccess', _3 => _3.isSmart]) ? recordId : null
|
|
46
48
|
);
|
|
47
49
|
const [smartPanelOpen, setSmartPanelOpen] = _react.useState.call(void 0, true);
|
|
48
50
|
const [srSearch, setSrSearch] = _react.useState.call(void 0, "");
|
|
49
51
|
const [srTab, setSrTab] = _react.useState.call(void 0, "all");
|
|
52
|
+
const [expandedVital, setExpandedVital] = _react.useState.call(void 0, null);
|
|
53
|
+
const toggleExpand = _react.useCallback.call(void 0, (key) => {
|
|
54
|
+
setExpandedVital((prev) => prev === key ? null : key);
|
|
55
|
+
}, []);
|
|
50
56
|
const [srSelected, setSrSelected] = _react.useState.call(void 0, /* @__PURE__ */ new Set());
|
|
51
57
|
const srCopyBtnRef = _react.useRef.call(void 0, null);
|
|
52
58
|
const [dropdownOpen, setDropdownOpen] = _react.useState.call(void 0, false);
|
|
@@ -70,10 +76,16 @@ function OriginalRecordPanel({
|
|
|
70
76
|
const goTo = _react.useCallback.call(void 0,
|
|
71
77
|
(r) => {
|
|
72
78
|
setDropdownOpen(false);
|
|
73
|
-
|
|
79
|
+
replaceOriginal(r.id, caseId);
|
|
74
80
|
},
|
|
75
|
-
[
|
|
81
|
+
[replaceOriginal, caseId]
|
|
76
82
|
);
|
|
83
|
+
const goPrev = _react.useCallback.call(void 0, () => {
|
|
84
|
+
if (currentIndex > 0) goTo(caseRecords[currentIndex - 1]);
|
|
85
|
+
}, [currentIndex, caseRecords, goTo]);
|
|
86
|
+
const goNext = _react.useCallback.call(void 0, () => {
|
|
87
|
+
if (currentIndex < total - 1) goTo(caseRecords[currentIndex + 1]);
|
|
88
|
+
}, [currentIndex, total, caseRecords, goTo]);
|
|
77
89
|
const showNavPicker = caseId && total > 0;
|
|
78
90
|
const allRows = table.rows;
|
|
79
91
|
const oorRows = _react.useMemo.call(void 0,
|
|
@@ -102,6 +114,10 @@ function OriginalRecordPanel({
|
|
|
102
114
|
_react.useEffect.call(void 0, () => {
|
|
103
115
|
setSrSelected(/* @__PURE__ */ new Set());
|
|
104
116
|
}, [srTab, srSearch]);
|
|
117
|
+
_react.useEffect.call(void 0, () => {
|
|
118
|
+
if (srTab === "oor" && oorRows.length === 0) setSrTab("all");
|
|
119
|
+
if (srTab === "none" && noInterpRows.length === 0) setSrTab("all");
|
|
120
|
+
}, [srTab, oorRows.length, noInterpRows.length]);
|
|
105
121
|
const srAllSelected = filteredRows.length > 0 && filteredRows.every((r) => srSelected.has(r.key));
|
|
106
122
|
const srSomeSelected = srSelected.size > 0;
|
|
107
123
|
const toggleSrRow = _react.useCallback.call(void 0, (key) => {
|
|
@@ -130,7 +146,32 @@ function OriginalRecordPanel({
|
|
|
130
146
|
);
|
|
131
147
|
}
|
|
132
148
|
}, [filteredRows, srSelected, onCopyVitalsToNote, onCopyToNote]);
|
|
133
|
-
const
|
|
149
|
+
const htmlCopyBtnRef = _react.useRef.call(void 0, null);
|
|
150
|
+
const [isHtmlCopying, setIsHtmlCopying] = _react.useState.call(void 0, false);
|
|
151
|
+
const handleHtmlCopyToNote = _react.useCallback.call(void 0, async () => {
|
|
152
|
+
const url = _optionalChain([preview, 'access', _7 => _7.files, 'access', _8 => _8[0], 'optionalAccess', _9 => _9.url]);
|
|
153
|
+
if (!url) return;
|
|
154
|
+
setIsHtmlCopying(true);
|
|
155
|
+
try {
|
|
156
|
+
const res = await fetch(url);
|
|
157
|
+
const html = await res.text();
|
|
158
|
+
const doc = new DOMParser().parseFromString(html, "text/html");
|
|
159
|
+
const text = _nullishCoalesce(_optionalChain([doc, 'access', _10 => _10.body, 'access', _11 => _11.textContent, 'optionalAccess', _12 => _12.trim, 'call', _13 => _13()]), () => ( ""));
|
|
160
|
+
if (!text) return;
|
|
161
|
+
if (onCopyVitalsToNote) {
|
|
162
|
+
void onCopyVitalsToNote(text);
|
|
163
|
+
} else if (onCopyToNote) {
|
|
164
|
+
const rect = _optionalChain([htmlCopyBtnRef, 'access', _14 => _14.current, 'optionalAccess', _15 => _15.getBoundingClientRect, 'call', _16 => _16()]);
|
|
165
|
+
void onCopyToNote(
|
|
166
|
+
text,
|
|
167
|
+
rect ? { x: rect.left, y: rect.bottom } : void 0
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
} finally {
|
|
171
|
+
setIsHtmlCopying(false);
|
|
172
|
+
}
|
|
173
|
+
}, [preview.files, onCopyVitalsToNote, onCopyToNote]);
|
|
174
|
+
const isSmart = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _17 => _17.isSmart]), () => ( false));
|
|
134
175
|
const hasPreview = preview.status === "loaded" && preview.files.length > 0;
|
|
135
176
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-sv__panel", children: [
|
|
136
177
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-sv__panel-header", children: [
|
|
@@ -166,14 +207,15 @@ function OriginalRecordPanel({
|
|
|
166
207
|
className: "mr-orig__nav-chevron",
|
|
167
208
|
onClick: (e) => {
|
|
168
209
|
e.stopPropagation();
|
|
169
|
-
|
|
210
|
+
goPrev();
|
|
170
211
|
},
|
|
171
|
-
"aria-label": "
|
|
212
|
+
"aria-label": "Previous record",
|
|
213
|
+
disabled: currentIndex <= 0,
|
|
172
214
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronLeft, { size: 14, "aria-hidden": true })
|
|
173
215
|
}
|
|
174
216
|
),
|
|
175
217
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__nav-text", children: [
|
|
176
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__nav-title", children: _nullishCoalesce(_optionalChain([record, 'optionalAccess',
|
|
218
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__nav-title", children: _nullishCoalesce(_optionalChain([record, 'optionalAccess', _18 => _18.title]), () => ( "Record")) }),
|
|
177
219
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mr-orig__nav-counter", children: [
|
|
178
220
|
currentIndex + 1,
|
|
179
221
|
" of ",
|
|
@@ -187,9 +229,10 @@ function OriginalRecordPanel({
|
|
|
187
229
|
className: "mr-orig__nav-chevron",
|
|
188
230
|
onClick: (e) => {
|
|
189
231
|
e.stopPropagation();
|
|
190
|
-
|
|
232
|
+
goNext();
|
|
191
233
|
},
|
|
192
|
-
"aria-label": "
|
|
234
|
+
"aria-label": "Next record",
|
|
235
|
+
disabled: currentIndex >= total - 1,
|
|
193
236
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronRight, { size: 14, "aria-hidden": true })
|
|
194
237
|
}
|
|
195
238
|
)
|
|
@@ -215,7 +258,7 @@ function OriginalRecordPanel({
|
|
|
215
258
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__dropdown-icon", children: [
|
|
216
259
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.File, { size: 16, "aria-hidden": true }),
|
|
217
260
|
r.isSmart && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
218
|
-
|
|
261
|
+
_chunkGKREOUK2js.SmartSparkles_default,
|
|
219
262
|
{
|
|
220
263
|
className: "mr-orig__dropdown-smart-dot",
|
|
221
264
|
"aria-label": "Smart report"
|
|
@@ -226,7 +269,7 @@ function OriginalRecordPanel({
|
|
|
226
269
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__dropdown-title-row", children: [
|
|
227
270
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__dropdown-title", children: r.title }),
|
|
228
271
|
r.isSmart && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mr-orig__dropdown-smart-badge", children: [
|
|
229
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
272
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGKREOUK2js.SmartSparkles_default, { "aria-hidden": true }),
|
|
230
273
|
"Smart Report"
|
|
231
274
|
] })
|
|
232
275
|
] }),
|
|
@@ -274,11 +317,25 @@ function OriginalRecordPanel({
|
|
|
274
317
|
className: "mr-orig__show-smart-btn",
|
|
275
318
|
onClick: () => setSmartPanelOpen(true),
|
|
276
319
|
children: [
|
|
277
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
320
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkGKREOUK2js.SmartSparkles_default, { "aria-hidden": true }),
|
|
278
321
|
"Smart Report"
|
|
279
322
|
]
|
|
280
323
|
}
|
|
281
324
|
),
|
|
325
|
+
preview.isHtml && hasCopyToNote && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
326
|
+
"button",
|
|
327
|
+
{
|
|
328
|
+
ref: htmlCopyBtnRef,
|
|
329
|
+
type: "button",
|
|
330
|
+
className: "mr-orig__html-copy-btn",
|
|
331
|
+
onClick: handleHtmlCopyToNote,
|
|
332
|
+
disabled: isHtmlCopying,
|
|
333
|
+
children: [
|
|
334
|
+
isHtmlCopying && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { size: 12, className: "mr-sv__loading-spinner", "aria-hidden": true }),
|
|
335
|
+
"Copy to note"
|
|
336
|
+
]
|
|
337
|
+
}
|
|
338
|
+
),
|
|
282
339
|
hasPreview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
283
340
|
_chunk57BG7LVPjs.IconButton,
|
|
284
341
|
{
|
|
@@ -320,7 +377,7 @@ function OriginalRecordPanel({
|
|
|
320
377
|
DocumentViewer,
|
|
321
378
|
{
|
|
322
379
|
files: preview.files,
|
|
323
|
-
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess',
|
|
380
|
+
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess', _19 => _19.title]), () => ( "")),
|
|
324
381
|
isHtml: preview.isHtml
|
|
325
382
|
}
|
|
326
383
|
) })
|
|
@@ -331,7 +388,7 @@ function OriginalRecordPanel({
|
|
|
331
388
|
DocumentViewer,
|
|
332
389
|
{
|
|
333
390
|
files: preview.files,
|
|
334
|
-
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess',
|
|
391
|
+
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess', _20 => _20.title]), () => ( "")),
|
|
335
392
|
isHtml: preview.isHtml
|
|
336
393
|
}
|
|
337
394
|
) }) }),
|
|
@@ -349,20 +406,19 @@ function OriginalRecordPanel({
|
|
|
349
406
|
}
|
|
350
407
|
)
|
|
351
408
|
] }),
|
|
352
|
-
/* @__PURE__ */ _jsxruntime.
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
"
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
)
|
|
364
|
-
|
|
365
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-tabs-wrap", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-tabs", children: ["all", "oor", "none"].map((tab) => {
|
|
409
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
410
|
+
_chunk57BG7LVPjs.SearchInput_default,
|
|
411
|
+
{
|
|
412
|
+
className: "mr-orig__smart-search",
|
|
413
|
+
iconSize: 16,
|
|
414
|
+
placeholder: "Search vitals",
|
|
415
|
+
value: srSearch,
|
|
416
|
+
onChange: setSrSearch
|
|
417
|
+
}
|
|
418
|
+
),
|
|
419
|
+
(oorRows.length > 0 || noInterpRows.length > 0) && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-tabs-wrap", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-tabs", children: ["all", "oor", "none"].map((tab) => {
|
|
420
|
+
if (tab === "oor" && oorRows.length === 0) return null;
|
|
421
|
+
if (tab === "none" && noInterpRows.length === 0) return null;
|
|
366
422
|
const count = tab === "all" ? tabCounts.all : tab === "oor" ? tabCounts.oor : tabCounts.none;
|
|
367
423
|
const label = tab === "all" ? "All" : tab === "oor" ? "Out of range" : "No interpretation";
|
|
368
424
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
@@ -396,63 +452,79 @@ function OriginalRecordPanel({
|
|
|
396
452
|
const isOor = row.latestStatus === "high" || row.latestStatus === "low";
|
|
397
453
|
const isSelected = srSelected.has(row.key);
|
|
398
454
|
const isLast = idx === filteredRows.length - 1;
|
|
399
|
-
return /* @__PURE__ */ _jsxruntime.
|
|
455
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
400
456
|
"div",
|
|
401
457
|
{
|
|
402
458
|
className: `mr-orig__vital-item${isLast ? " mr-orig__vital-item--last" : ""}`,
|
|
403
|
-
children:
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
"span",
|
|
411
|
-
{
|
|
412
|
-
className: `mr-sv__checkbox mr-cc-table__row-check${isSelected ? " mr-sv__checkbox--checked" : ""}`,
|
|
413
|
-
role: "checkbox",
|
|
414
|
-
"aria-checked": isSelected,
|
|
415
|
-
tabIndex: 0,
|
|
416
|
-
onClick: (e) => {
|
|
417
|
-
e.stopPropagation();
|
|
418
|
-
toggleSrRow(row.key);
|
|
419
|
-
},
|
|
420
|
-
onKeyDown: (e) => {
|
|
421
|
-
if (e.key === " " || e.key === "Enter") {
|
|
422
|
-
e.preventDefault();
|
|
423
|
-
e.stopPropagation();
|
|
424
|
-
toggleSrRow(row.key);
|
|
425
|
-
}
|
|
426
|
-
},
|
|
427
|
-
children: isSelected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Check, { size: 10, strokeWidth: 3 })
|
|
428
|
-
}
|
|
429
|
-
),
|
|
430
|
-
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-info", children: [
|
|
431
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__vital-name", children: row.name }),
|
|
432
|
-
row.refRange && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mr-orig__vital-ref", children: [
|
|
433
|
-
"Ref ",
|
|
434
|
-
row.refRange
|
|
435
|
-
] })
|
|
436
|
-
] }),
|
|
437
|
-
cell && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-value", children: [
|
|
459
|
+
children: [
|
|
460
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
461
|
+
"div",
|
|
462
|
+
{
|
|
463
|
+
className: `mr-orig__vital-row mr-orig__vital-row--selectable${isSelected ? " mr-orig__vital-row--selected" : ""}`,
|
|
464
|
+
onClick: () => toggleSrRow(row.key),
|
|
465
|
+
children: [
|
|
438
466
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
439
467
|
"span",
|
|
440
468
|
{
|
|
441
|
-
className: `mr-
|
|
442
|
-
|
|
469
|
+
className: `mr-sv__checkbox mr-cc-table__row-check${isSelected ? " mr-sv__checkbox--checked" : ""}`,
|
|
470
|
+
role: "checkbox",
|
|
471
|
+
"aria-checked": isSelected,
|
|
472
|
+
tabIndex: 0,
|
|
473
|
+
onClick: (e) => {
|
|
474
|
+
e.stopPropagation();
|
|
475
|
+
toggleSrRow(row.key);
|
|
476
|
+
},
|
|
477
|
+
onKeyDown: (e) => {
|
|
478
|
+
if (e.key === " " || e.key === "Enter") {
|
|
479
|
+
e.preventDefault();
|
|
480
|
+
e.stopPropagation();
|
|
481
|
+
toggleSrRow(row.key);
|
|
482
|
+
}
|
|
483
|
+
},
|
|
484
|
+
children: isSelected && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Check, { size: 10, strokeWidth: 3 })
|
|
443
485
|
}
|
|
444
486
|
),
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
487
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-info", children: [
|
|
488
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__vital-name", children: row.name }),
|
|
489
|
+
row.refRange && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mr-orig__vital-ref", children: [
|
|
490
|
+
"Ref ",
|
|
491
|
+
row.refRange
|
|
492
|
+
] })
|
|
493
|
+
] }),
|
|
494
|
+
cell && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-value", children: [
|
|
495
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
496
|
+
"span",
|
|
497
|
+
{
|
|
498
|
+
className: `mr-orig__vital-val${isOor ? " mr-orig__vital-val--oor" : ""}`,
|
|
499
|
+
children: cell.value
|
|
500
|
+
}
|
|
501
|
+
),
|
|
502
|
+
cell.unit && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__vital-unit", children: cell.unit })
|
|
503
|
+
] }),
|
|
504
|
+
row.ekaId && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
505
|
+
"button",
|
|
506
|
+
{
|
|
507
|
+
type: "button",
|
|
508
|
+
className: `mr-orig__vital-expand-btn${expandedVital === row.key ? " mr-orig__vital-expand-btn--open" : ""}`,
|
|
509
|
+
onClick: (e) => {
|
|
510
|
+
e.stopPropagation();
|
|
511
|
+
toggleExpand(row.key);
|
|
512
|
+
},
|
|
513
|
+
"aria-label": expandedVital === row.key ? "Collapse readings" : "Show latest readings",
|
|
514
|
+
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ChevronDown, { size: 13, "aria-hidden": true })
|
|
515
|
+
}
|
|
516
|
+
)
|
|
517
|
+
]
|
|
518
|
+
}
|
|
519
|
+
),
|
|
520
|
+
expandedVital === row.key && row.ekaId && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, VitalReadingsExpanded, { vitalName: row.name, ekaId: row.ekaId })
|
|
521
|
+
]
|
|
450
522
|
},
|
|
451
523
|
row.key
|
|
452
524
|
);
|
|
453
525
|
})
|
|
454
526
|
] }),
|
|
455
|
-
|
|
527
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-cc-table__footer", children: [
|
|
456
528
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
457
529
|
"span",
|
|
458
530
|
{
|
|
@@ -483,7 +555,7 @@ function OriginalRecordPanel({
|
|
|
483
555
|
ref: srCopyBtnRef,
|
|
484
556
|
type: "button",
|
|
485
557
|
className: "mr-cc-table__copy-note-btn",
|
|
486
|
-
disabled: !hasCopyToNote,
|
|
558
|
+
disabled: !srSomeSelected || !hasCopyToNote,
|
|
487
559
|
onClick: handleSrCopyToNote,
|
|
488
560
|
children: "Copy to note"
|
|
489
561
|
}
|
|
@@ -496,7 +568,41 @@ function OriginalRecordPanel({
|
|
|
496
568
|
)
|
|
497
569
|
] });
|
|
498
570
|
}
|
|
571
|
+
function VitalReadingsExpanded({ vitalName, ekaId }) {
|
|
572
|
+
const { store } = _chunk57BG7LVPjs.useSdk.call(void 0, );
|
|
573
|
+
const recordsById = _zustand.useStore.call(void 0, store, (s) => s.records.byId);
|
|
574
|
+
const { data: trendData, status } = _chunkYT6OD4YUjs.useParameterTrend.call(void 0, ekaId);
|
|
575
|
+
const readings = _react.useMemo.call(void 0, () => {
|
|
576
|
+
const trend = trendData;
|
|
577
|
+
if (!_optionalChain([trend, 'optionalAccess', _21 => _21.vitals_info, 'optionalAccess', _22 => _22.length])) return [];
|
|
578
|
+
return [...trend.vitals_info].sort((a, b) => (_nullishCoalesce(b.date, () => ( 0))) - (_nullishCoalesce(a.date, () => ( 0)))).slice(0, 3).map((info) => {
|
|
579
|
+
const dr = (_nullishCoalesce(info.display_result, () => ( ""))).toLowerCase();
|
|
580
|
+
const isOor = dr.includes("high") || dr.includes("above") || dr.includes("abnormal_high") || dr.includes("low") || dr.includes("below") || dr.includes("abnormal_low");
|
|
581
|
+
return {
|
|
582
|
+
value: info.val != null ? String(info.val) : _nullishCoalesce(info.val_string, () => ( "\u2014")),
|
|
583
|
+
date: _chunk57BG7LVPjs.epochToDisplay.call(void 0, _nullishCoalesce(_optionalChain([recordsById, 'access', _23 => _23[info.document_id], 'optionalAccess', _24 => _24.createdAtEpoch]), () => ( 0))),
|
|
584
|
+
isOor
|
|
585
|
+
};
|
|
586
|
+
});
|
|
587
|
+
}, [trendData, recordsById]);
|
|
588
|
+
if (status === "loading") {
|
|
589
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__vital-readings mr-orig__vital-readings--loading", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { size: 16, className: "mr-sv__loading-spinner", "aria-hidden": true }) });
|
|
590
|
+
}
|
|
591
|
+
if (status === "error" || !readings.length) {
|
|
592
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__vital-readings", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunk57BG7LVPjs.Typography, { variant: "muted", className: "mr-orig__vital-readings-empty", children: "No readings available" }) });
|
|
593
|
+
}
|
|
594
|
+
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-readings", children: [
|
|
595
|
+
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-readings-title", children: [
|
|
596
|
+
"LATEST READINGS FOR ",
|
|
597
|
+
vitalName.toUpperCase()
|
|
598
|
+
] }),
|
|
599
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__vital-readings-grid", children: readings.map((r, i) => /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-reading-item", children: [
|
|
600
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: `mr-orig__vital-reading-value${r.isOor ? " mr-orig__vital-reading-value--oor" : ""}`, children: r.value }),
|
|
601
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__vital-reading-date", children: r.date })
|
|
602
|
+
] }, i)) })
|
|
603
|
+
] });
|
|
604
|
+
}
|
|
499
605
|
|
|
500
606
|
|
|
501
607
|
exports.OriginalRecordPanel = OriginalRecordPanel;
|
|
502
|
-
//# sourceMappingURL=OriginalRecordPanel-
|
|
608
|
+
//# sourceMappingURL=OriginalRecordPanel-PVNAZ5CR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/medical-records-ui/medical-records-ui/dist/OriginalRecordPanel-PVNAZ5CR.js","../src/views/components/shared/OriginalRecordPanel.tsx"],"names":[],"mappings":"AAAA,+8BAAY;AACZ;AACE;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACF,sDAA4B;AAC5B;AACE;AACA;AACA;AACA;AACA;AACF,sDAA4B;AAC5B;AACA;AChBA,8BAAkF;AAClF,2CAAgG;AAChG,kCAAyB;AAmNT,+CAAA;AAtMhB,IAAM,eAAA,EAAiB,yBAAA;AAAA,EAAK,CAAA,EAAA,GAC1B,4DAAA,CAAO,8BAAoC,GAAA,CAAE,IAAA,CAAK,CAAC,CAAA,EAAA,GAAA,CAAO;AAAA,IACxD,OAAA,EAAS,CAAA,CAAE;AAAA,EACb,CAAA,CAAE;AACJ,CAAA;AAUA,SAAS,eAAA,CAAgB,IAAA,EAA0B;AACjD,EAAA,OAAO,IAAA,CACJ,GAAA,CAAI,CAAC,CAAA,EAAA,GAAM;AACV,IAAA,MAAM,KAAA,EAAO,CAAA,CAAE,KAAA,CAAM,CAAC,CAAA;AACtB,IAAA,MAAM,IAAA,kBAAM,IAAA,2BAAM,WAAA,EAAW,CAAA,OAAA,EAAU,IAAA,CAAK,QAAQ,CAAA,CAAA,EAAA,EAAM,EAAA;AAC1D,IAAA,OAAO,CAAA,EAAA;AAEH,EAAA;AACV;AAEgB;AACd,EAAA;AACA,EAAA;AACA,EAAA;AAC2B;AACnB,EAAA;AACF,EAAA;AACA,EAAA;AACA,EAAA;AACE,EAAA;AAIA,EAAA;AACE,oBAAA;AACV,EAAA;AACO,EAAA;AACA,EAAA;AACA,EAAA;AACA,EAAA;AACD,EAAA;AACJ,IAAA;AACG,EAAA;AACE,EAAA;AACD,EAAA;AAGC,EAAA;AACD,EAAA;AAEI,EAAA;AACH,IAAA;AACC,IAAA;AACA,MAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACA,IAAA;AACO,IAAA;AACL,EAAA;AAEE,EAAA;AACC,IAAA;AACE,IAAA;AAGL,EAAA;AAEE,EAAA;AACA,EAAA;AAEA,EAAA;AACe,IAAA;AACjB,MAAA;AACA,MAAA;AACF,IAAA;AACC,IAAA;AACH,EAAA;AAEM,EAAA;AACA,IAAA;AACF,EAAA;AAEE,EAAA;AACA,IAAA;AACF,EAAA;AAEE,EAAA;AAGA,EAAA;AACA,EAAA;AACE,IAAA;AACE,IAAA;AACV,EAAA;AACM,EAAA;AACE,IAAA;AACE,IAAA;AACV,EAAA;AAEM,EAAA;AAEA,EAAA;AACC,IAAA;AACC,IAAA;AACC,IAAA;AACL,EAAA;AAEE,EAAA;AACC,IAAA;AACC,IAAA;AACC,IAAA;AACA,MAAA;AACA,MAAA;AACC,MAAA;AACR,IAAA;AACE,EAAA;AAEM,EAAA;AACR,IAAA;AACE,EAAA;AAEM,EAAA;AACJ,IAAA;AACA,IAAA;AACF,EAAA;AAEE,EAAA;AAEA,EAAA;AAEA,EAAA;AACJ,IAAA;AACQ,MAAA;AACD,MAAA;AACL,MAAA;AACD,IAAA;AACE,EAAA;AAEC,EAAA;AACJ,IAAA;AACE,MAAA;AACF,IAAA;AACE,EAAA;AAEE,EAAA;AACE,IAAA;AACD,IAAA;AACC,IAAA;AACF,IAAA;AACG,MAAA;AACP,IAAA;AACQ,MAAA;AACD,MAAA;AACH,QAAA;AACA,QAAA;AACF,MAAA;AACF,IAAA;AACE,EAAA;AAEE,EAAA;AACC,EAAA;AAED,EAAA;AACE,IAAA;AACD,IAAA;AACL,IAAA;AACI,IAAA;AACI,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACD,MAAA;AACD,MAAA;AACF,QAAA;AACF,MAAA;AACE,QAAA;AACA,QAAA;AACE,UAAA;AACA,UAAA;AACF,QAAA;AACF,MAAA;AACF,IAAA;AACE,MAAA;AACF,IAAA;AACE,EAAA;AAEE,EAAA;AACA,EAAA;AAGJ,EAAA;AACE,oBAAA;AACE,sBAAA;AAAC,QAAA;AAAA,QAAA;AACC,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AACA,UAAA;AAAS,QAAA;AACX,MAAA;AAEC,MAAA;AAEG,wBAAA;AAAC,UAAA;AAAA,UAAA;AACC,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACE,cAAA;AACE,gBAAA;AACA,gBAAA;AAAyB,cAAA;AAE7B,YAAA;AAEA,YAAA;AAAA,8BAAA;AAAA,gBAAA;AAAC,gBAAA;AAAA,kBAAA;AACM,kBAAA;AACK,kBAAA;AACQ,oBAAA;AAAqB,oBAAA;AAAO,kBAAA;AAAG,kBAAA;AACtC,kBAAA;AACe,kBAAA;AAES,gBAAA;AAAA,cAAA;AACrC,8BAAA;AAEE,gCAAA;AAAgE,gCAAA;AAE7D,kBAAA;AAAe,kBAAA;AAAE,kBAAA;AAAK,gBAAA;AACzB,cAAA;AACF,8BAAA;AACA,gBAAA;AAAC,gBAAA;AAAA,kBAAA;AACM,kBAAA;AACK,kBAAA;AACQ,oBAAA;AAAqB,oBAAA;AAAO,kBAAA;AAAG,kBAAA;AACtC,kBAAA;AACuB,kBAAA;AAEE,gBAAA;AAAA,cAAA;AACtC,YAAA;AAAA,UAAA;AACF,QAAA;AAEC,QAAA;AAEG,0BAAA;AACG,YAAA;AAAM,YAAA;AAAQ,YAAA;AAAuB,YAAA;AAAA,UAAA;AAExC,0BAAA;AAEI,YAAA;AACA,YAAA;AACE,cAAA;AAAC,cAAA;AAAA,gBAAA;AAEM,gBAAA;AACgF,gBAAA;AAChE,gBAAA;AAErB,kCAAA;AACE,oCAAA;AAA4B,oBAAA;AAE1B,sBAAA;AAAC,sBAAA;AAAA,wBAAA;AACW,wBAAA;AACC,sBAAA;AAAA,oBAAA;AACb,kBAAA;AAEJ,kCAAA;AAEE,oCAAA;AACE,sCAAA;AAAmD,sBAAA;AAG/C,wCAAA;AAA2B,wBAAA;AAAE,sBAAA;AAE/B,oBAAA;AAEJ,oCAAA;AAEE,sCAAA;AAAwC,sBAAA;AAGpC,wCAAA;AAAyC,wCAAA;AAClC,0BAAA;AAAE,0BAAA;AAAY,wBAAA;AAAO,sBAAA;AAC9B,sBAAA;AAIE,wCAAA;AAAyC,wCAAA;AAEtC,0BAAA;AAAE,0BAAA;AAAiB,wBAAA;AACtB,sBAAA;AACF,oBAAA;AAEJ,kBAAA;AACF,kBAAA;AAEE,oBAAA;AAAC,oBAAA;AAAA,sBAAA;AACO,sBAAA;AACI,sBAAA;AACC,oBAAA;AAAA,kBAAA;AACb,gBAAA;AAAA,cAAA;AAAA,cAAA;AAEJ,YAAA;AAEH,UAAA;AAEL,QAAA;AAEJ,MAAA;AAGE,wBAAA;AAGA,wBAAA;AAGF,MAAA;AAGF,sBAAA;AACG,QAAA;AACE,UAAA;AAAA,UAAA;AACC,YAAA;AACA,YAAA;AACA,YAAA;AAEA,YAAA;AAAA,8BAAA;AAA2B,cAAA;AAAE,YAAA;AAAA,UAAA;AAE/B,QAAA;AAED,QAAA;AACE,UAAA;AAAA,UAAA;AACC,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AAEC,YAAA;AAAA,cAAA;AAAwF,cAAA;AAAG,YAAA;AAAA,UAAA;AAE9F,QAAA;AAED,QAAA;AACE,UAAA;AAAA,UAAA;AACC,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACA,YAAA;AACmE,UAAA;AAErE,QAAA;AAEJ,MAAA;AACF,IAAA;AAEA,oBAAA;AAAC,MAAA;AAAA,MAAA;AACC,QAAA;AACA,QAAA;AAEC,QAAA;AAAA,UAAA;AACE,YAAA;AAAA,YAAA;AAAA,cAAA;AACQ,gBAAA;AACI,gBAAA;AACG,gBAAA;AACI,gBAAA;AACR,cAAA;AACV,cAAA;AAEuE,YAAA;AACzE,UAAA;AAED,UAAA;AAKA,UAAA;AAOA,UAAA;AACE,YAAA;AAAA,YAAA;AAAA,cAAA;AACW,cAAA;AAC4C,cAAA;AAGpD,gBAAA;AAAC,gBAAA;AAAA,kBAAA;AACgB,kBAAA;AACS,kBAAA;AACR,gBAAA;AAAA,cAAA;AAEpB,YAAA;AACF,UAAA;AAID,UAAA;AAEG,4BAAA;AAEI,cAAA;AAAC,cAAA;AAAA,gBAAA;AACgB,gBAAA;AACS,gBAAA;AACR,cAAA;AAClB,YAAA;AAIH,YAAA;AAGG,8BAAA;AACE,gCAAA;AAAmD,gCAAA;AACnD,kBAAA;AAAC,kBAAA;AAAA,oBAAA;AACM,oBAAA;AACK,oBAAA;AACC,oBAAA;AAC2B,oBAAA;AAEF,kBAAA;AAAA,gBAAA;AACtC,cAAA;AACF,8BAAA;AAGA,gBAAA;AAAC,gBAAA;AAAA,kBAAA;AACW,kBAAA;AACA,kBAAA;AACE,kBAAA;AACL,kBAAA;AACG,gBAAA;AAAA,cAAA;AACZ,cAAA;AAOQ,gBAAA;AACA,gBAAA;AACA,gBAAA;AAMA,gBAAA;AAMA,gBAAA;AACE,kBAAA;AAAC,kBAAA;AAAA,oBAAA;AAEM,oBAAA;AAC6E,oBAAA;AACvD,oBAAA;AAE1B,sBAAA;AAAA,sBAAA;AAAM,sBAAA;AAAG,sBAAA;AAAM,oBAAA;AAAA,kBAAA;AAAA,kBAAA;AALX,gBAAA;AAMP,cAAA;AAIR,8BAAA;AAKC,gBAAA;AAEG,kBAAA;AAAC,kBAAA;AAAA,oBAAA;AACO,oBAAA;AACI,oBAAA;AACC,kBAAA;AAAA,gBAAA;AAEf,gBAAA;AAKA,gBAAA;AAIE,kBAAA;AACA,kBAAA;AAEA,kBAAA;AACA,kBAAA;AACA,kBAAA;AACE,oBAAA;AAAC,oBAAA;AAAA,sBAAA;AAE4E,sBAAA;AAE3E,wCAAA;AAAA,0BAAA;AAAC,0BAAA;AAAA,4BAAA;AACiH,4BAAA;AAC9E,4BAAA;AAElC,8CAAA;AAAA,gCAAA;AAAC,gCAAA;AAAA,kCAAA;AACkG,kCAAA;AAC5F,kCAAA;AACS,kCAAA;AACJ,kCAAA;AAER,oCAAA;AACA,oCAAA;AAAmB,kCAAA;AACrB,kCAAA;AAEE,oCAAA;AACE,sCAAA;AACA,sCAAA;AACA,sCAAA;AAAmB,oCAAA;AACrB,kCAAA;AACF,kCAAA;AAEgD,gCAAA;AAAA,8BAAA;AAClD,8CAAA;AAEE,gDAAA;AAAgD,gCAAA;AAET,kCAAA;AAAA,kCAAA;AAC1B,gCAAA;AACX,8BAAA;AAEJ,8BAAA;AAGI,gDAAA;AAAA,kCAAA;AAAC,kCAAA;AAAA,oCAAA;AACwE,oCAAA;AAEjE,kCAAA;AAAA,gCAAA;AACR,gCAAA;AAEmD,8BAAA;AAErD,8BAAA;AAGA,gCAAA;AAAC,gCAAA;AAAA,kCAAA;AACM,kCAAA;AACqG,kCAAA;AACxF,oCAAA;AAAqB,oCAAA;AAAoB,kCAAA;AAAG,kCAAA;AACA,kCAAA;AAE3B,gCAAA;AAAA,8BAAA;AACrC,4BAAA;AAAA,0BAAA;AAAA,wBAAA;AAEJ,wBAAA;AAEgE,sBAAA;AAAA,oBAAA;AAAA,oBAAA;AA1DvD,kBAAA;AA4DX,gBAAA;AAEH,cAAA;AACL,8BAAA;AAIE,gCAAA;AAAA,kBAAA;AAAC,kBAAA;AAAA,oBAAA;AACwG,oBAAA;AAClG,oBAAA;AACS,oBAAA;AACJ,oBAAA;AACD,oBAAA;AAEP,sBAAA;AACE,wBAAA;AACA,wBAAA;AAAY,sBAAA;AACd,oBAAA;AACF,oBAAA;AAEmD,kBAAA;AAAA,gBAAA;AACrD,gCAAA;AACsD,gCAAA;AAEnD,kBAAA;AAAW,kBAAA;AAAK,kBAAA;AAAkB,kBAAA;AAAO,gBAAA;AAC5C,gCAAA;AACA,kBAAA;AAAC,kBAAA;AAAA,oBAAA;AACM,oBAAA;AACA,oBAAA;AACK,oBAAA;AACoB,oBAAA;AACrB,oBAAA;AACV,kBAAA;AAAA,gBAAA;AAED,cAAA;AACF,YAAA;AACF,UAAA;AAEJ,QAAA;AAAA,MAAA;AAEJ,IAAA;AACF,EAAA;AAEJ;AAES;AACC,EAAA;AACF,EAAA;AACE,EAAA;AAEF,EAAA;AACE,IAAA;AACD,IAAA;AACG,IAAA;AAIE,MAAA;AACA,MAAA;AAEN,MAAA;AACE,QAAA;AACA,QAAA;AACA,QAAA;AACF,MAAA;AACD,IAAA;AACD,EAAA;AAEA,EAAA;AAEA,IAAA;AAIJ,EAAA;AAEI,EAAA;AAEA,IAAA;AAMJ,EAAA;AAGE,EAAA;AACE,oBAAA;AAA+C,MAAA;AACxB,MAAA;AACvB,IAAA;AACA,oBAAA;AAGM,sBAAA;AACA,sBAAA;AAEH,IAAA;AAEL,EAAA;AAEJ;ADxEY;AACA;AACA","file":"/home/runner/work/medical-records-ui/medical-records-ui/dist/OriginalRecordPanel-PVNAZ5CR.js","sourcesContent":[null,"\"use client\";\n\nimport { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport { ChevronLeft, ChevronRight, ChevronDown, ExternalLink, Check, File, LoaderCircle } from \"lucide-react\";\nimport { useStore } from \"zustand\";\nimport { useSdk } from \"../../../connection/useSdk\";\nimport { useRecordPreview } from \"../../../connection/useRecordPreview\";\nimport { useRecordPanelTable } from \"../../hooks/care-panel/useRecordPanelTable\";\nimport { useParameterTrend } from \"../../hooks/care-panel/useParameterTrend\";\nimport { epochToDisplay } from \"../../../helpers/formatters\";\nimport type { ParameterTrendResponse } from \"@eka-care/medical-records-ts-sdk\";\nimport { useSmartRecordsActions } from \"../../context/SmartRecordsActionsContext\";\nimport { IconButton, Typography, SearchInput } from \"widgets\";\nimport type { RecordItem } from \"../../../helpers\";\nimport type { PanelRow } from \"../../../helpers/vitalsPanel\";\nimport SmartSparkles from \"icons/SmartSparkles\";\n\nconst DocumentViewer = lazy(() =>\n import(\"../../RecordPreview/DocumentViewer\").then((m) => ({\n default: m.DocumentViewer,\n })),\n);\n\ninterface OriginalRecordPanelProps {\n recordId: string;\n caseId?: string;\n onBack: () => void;\n}\n\ntype SrTab = \"all\" | \"oor\" | \"none\";\n\nfunction buildVitalsText(rows: PanelRow[]): string {\n return rows\n .map((r) => {\n const cell = r.cells[0];\n const ref = cell?.refRange ? ` (Ref: ${cell.refRange})` : \"\";\n return `${r.name}: ${cell?.value ?? \"—\"} ${r.unit}${ref}`;\n })\n .join(\"\\n\");\n}\n\nexport function OriginalRecordPanel({\n recordId,\n caseId,\n onBack,\n}: OriginalRecordPanelProps) {\n const { store } = useSdk();\n const record = useStore(store, (s) => s.records.byId[recordId]);\n const recordsById = useStore(store, (s) => s.records.byId);\n const preview = useRecordPreview(recordId);\n const { replaceOriginal, onCopyToNote, onCopyVitalsToNote, hasCopyToNote } =\n useSmartRecordsActions();\n\n // Smart report vitals (only fetched when record.isSmart)\n const { status: vitalsStatus, table } = useRecordPanelTable(\n record?.isSmart ? recordId : null,\n );\n const [smartPanelOpen, setSmartPanelOpen] = useState(true);\n const [srSearch, setSrSearch] = useState(\"\");\n const [srTab, setSrTab] = useState<SrTab>(\"all\");\n const [expandedVital, setExpandedVital] = useState<string | null>(null);\n const toggleExpand = useCallback((key: string) => {\n setExpandedVital((prev) => (prev === key ? null : key));\n }, []);\n const [srSelected, setSrSelected] = useState<Set<string>>(new Set());\n const srCopyBtnRef = useRef<HTMLButtonElement>(null);\n\n // Dropdown state\n const [dropdownOpen, setDropdownOpen] = useState(false);\n const dropdownRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n if (!dropdownOpen) return;\n const handler = (e: MouseEvent) => {\n if (dropdownRef.current && !dropdownRef.current.contains(e.target as Node)) {\n setDropdownOpen(false);\n }\n };\n document.addEventListener(\"mousedown\", handler);\n return () => document.removeEventListener(\"mousedown\", handler);\n }, [dropdownOpen]);\n\n const caseRecords = useMemo<RecordItem[]>(() => {\n if (!caseId) return [];\n return Object.values(recordsById)\n .filter((r): r is RecordItem => r != null && r.cases.includes(caseId))\n .sort((a, b) => b.createdAtEpoch - a.createdAtEpoch);\n }, [recordsById, caseId]);\n\n const currentIndex = caseRecords.findIndex((r) => r.id === recordId);\n const total = caseRecords.length;\n\n const goTo = useCallback(\n (r: RecordItem) => {\n setDropdownOpen(false);\n replaceOriginal(r.id, caseId);\n },\n [replaceOriginal, caseId],\n );\n\n const goPrev = useCallback(() => {\n if (currentIndex > 0) goTo(caseRecords[currentIndex - 1]);\n }, [currentIndex, caseRecords, goTo]);\n\n const goNext = useCallback(() => {\n if (currentIndex < total - 1) goTo(caseRecords[currentIndex + 1]);\n }, [currentIndex, total, caseRecords, goTo]);\n\n const showNavPicker = caseId && total > 0;\n\n // Smart report vitals filtering\n const allRows = table.rows;\n const oorRows = useMemo(\n () => allRows.filter((r) => r.latestStatus === \"high\" || r.latestStatus === \"low\"),\n [allRows],\n );\n const noInterpRows = useMemo(\n () => allRows.filter((r) => r.latestStatus === \"unknown\"),\n [allRows],\n );\n\n const baseRows = srTab === \"oor\" ? oorRows : srTab === \"none\" ? noInterpRows : allRows;\n\n const filteredRows = useMemo(() => {\n if (!srSearch) return baseRows;\n const q = srSearch.toLowerCase();\n return baseRows.filter((r) => r.name.toLowerCase().includes(q));\n }, [baseRows, srSearch]);\n\n const tabCounts = useMemo(() => {\n if (!srSearch) return { all: allRows.length, oor: oorRows.length, none: noInterpRows.length };\n const q = srSearch.toLowerCase();\n return {\n all: allRows.filter((r) => r.name.toLowerCase().includes(q)).length,\n oor: oorRows.filter((r) => r.name.toLowerCase().includes(q)).length,\n none: noInterpRows.filter((r) => r.name.toLowerCase().includes(q)).length,\n };\n }, [srSearch, allRows, oorRows, noInterpRows]);\n\n useEffect(() => {\n setSrSelected(new Set());\n }, [srTab, srSearch]);\n\n useEffect(() => {\n if (srTab === \"oor\" && oorRows.length === 0) setSrTab(\"all\");\n if (srTab === \"none\" && noInterpRows.length === 0) setSrTab(\"all\");\n }, [srTab, oorRows.length, noInterpRows.length]);\n\n const srAllSelected =\n filteredRows.length > 0 && filteredRows.every((r) => srSelected.has(r.key));\n const srSomeSelected = srSelected.size > 0;\n\n const toggleSrRow = useCallback((key: string) => {\n setSrSelected((prev) => {\n const next = new Set(prev);\n next.has(key) ? next.delete(key) : next.add(key);\n return next;\n });\n }, []);\n\n const toggleSrAll = useCallback(() => {\n setSrSelected(\n srAllSelected ? new Set() : new Set(filteredRows.map((r) => r.key)),\n );\n }, [srAllSelected, filteredRows]);\n\n const handleSrCopyToNote = useCallback(() => {\n const selectedRows = filteredRows.filter((r) => srSelected.has(r.key));\n if (!selectedRows.length) return;\n const text = buildVitalsText(selectedRows);\n if (onCopyVitalsToNote) {\n void onCopyVitalsToNote(text);\n } else if (onCopyToNote) {\n const rect = srCopyBtnRef.current?.getBoundingClientRect();\n void onCopyToNote(\n text,\n rect ? { x: rect.left + rect.width / 2, y: rect.bottom } : undefined,\n );\n }\n }, [filteredRows, srSelected, onCopyVitalsToNote, onCopyToNote]);\n\n const htmlCopyBtnRef = useRef<HTMLButtonElement>(null);\n const [isHtmlCopying, setIsHtmlCopying] = useState(false);\n\n const handleHtmlCopyToNote = useCallback(async () => {\n const url = preview.files[0]?.url;\n if (!url) return;\n setIsHtmlCopying(true);\n try {\n const res = await fetch(url);\n const html = await res.text();\n const doc = new DOMParser().parseFromString(html, \"text/html\");\n const text = doc.body.textContent?.trim() ?? \"\";\n if (!text) return;\n if (onCopyVitalsToNote) {\n void onCopyVitalsToNote(text);\n } else if (onCopyToNote) {\n const rect = htmlCopyBtnRef.current?.getBoundingClientRect();\n void onCopyToNote(\n text,\n rect ? { x: rect.left, y: rect.bottom } : undefined,\n );\n }\n } finally {\n setIsHtmlCopying(false);\n }\n }, [preview.files, onCopyVitalsToNote, onCopyToNote]);\n\n const isSmart = record?.isSmart ?? false;\n const hasPreview = preview.status === \"loaded\" && preview.files.length > 0;\n\n return (\n <div className=\"mr-sv__panel\">\n <div className=\"mr-sv__panel-header\">\n <IconButton\n icon={<ChevronLeft size={16} aria-hidden />}\n label=\"Back\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={onBack}\n />\n\n {showNavPicker ? (\n <div className=\"mr-orig__nav-wrap\" ref={dropdownRef}>\n <div\n className={`mr-orig__nav-pill${dropdownOpen ? \" mr-orig__nav-pill--open\" : \"\"}`}\n role=\"button\"\n tabIndex={0}\n onClick={() => setDropdownOpen((v) => !v)}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n setDropdownOpen((v) => !v);\n }\n }}\n >\n <button\n type=\"button\"\n className=\"mr-orig__nav-chevron\"\n onClick={(e) => { e.stopPropagation(); goPrev(); }}\n aria-label=\"Previous record\"\n disabled={currentIndex <= 0}\n >\n <ChevronLeft size={14} aria-hidden />\n </button>\n <div className=\"mr-orig__nav-text\">\n <span className=\"mr-orig__nav-title\">{record?.title ?? \"Record\"}</span>\n <span className=\"mr-orig__nav-counter\">\n {currentIndex + 1} of {total}\n </span>\n </div>\n <button\n type=\"button\"\n className=\"mr-orig__nav-chevron\"\n onClick={(e) => { e.stopPropagation(); goNext(); }}\n aria-label=\"Next record\"\n disabled={currentIndex >= total - 1}\n >\n <ChevronRight size={14} aria-hidden />\n </button>\n </div>\n\n {dropdownOpen && (\n <div className=\"mr-orig__dropdown\">\n <div className=\"mr-orig__dropdown-eyebrow\">\n {total} RECORD{total !== 1 ? \"S\" : \"\"} FOUND IN THIS ENCOUNTER\n </div>\n <div className=\"mr-orig__dropdown-list\">\n {caseRecords.map((r) => {\n const isActive = r.id === recordId;\n return (\n <button\n key={r.id}\n type=\"button\"\n className={`mr-orig__dropdown-item${isActive ? \" mr-orig__dropdown-item--active\" : \"\"}`}\n onClick={() => goTo(r)}\n >\n <div className=\"mr-orig__dropdown-icon\">\n <File size={16} aria-hidden />\n {r.isSmart && (\n <SmartSparkles\n className=\"mr-orig__dropdown-smart-dot\"\n aria-label=\"Smart report\"\n />\n )}\n </div>\n <div className=\"mr-orig__dropdown-info\">\n <div className=\"mr-orig__dropdown-title-row\">\n <span className=\"mr-orig__dropdown-title\">{r.title}</span>\n {r.isSmart && (\n <span className=\"mr-orig__dropdown-smart-badge\">\n <SmartSparkles aria-hidden />\n Smart Report\n </span>\n )}\n </div>\n <div className=\"mr-orig__dropdown-meta\">\n <span>{epochToDisplay(r.createdAtEpoch)}</span>\n {r.isSmart && r.totalVitals > 0 && (\n <>\n <span className=\"mr-orig__dropdown-dot\">·</span>\n <span>{r.totalVitals} vitals</span>\n </>\n )}\n {r.isSmart && r.outOfRangeVitals > 0 && (\n <>\n <span className=\"mr-orig__dropdown-dot\">·</span>\n <span className=\"mr-orig__dropdown-oor\">\n {r.outOfRangeVitals} out of range\n </span>\n </>\n )}\n </div>\n </div>\n {isActive && (\n <Check\n size={14}\n className=\"mr-orig__dropdown-check\"\n aria-hidden\n />\n )}\n </button>\n );\n })}\n </div>\n </div>\n )}\n </div>\n ) : record ? (\n <div className=\"mr-sv__panel-info\">\n <Typography variant=\"label\" as=\"span\" className=\"mr-sv__panel-name\">\n {record.title}\n </Typography>\n <Typography variant=\"hint\" as=\"span\" className=\"mr-sv__panel-meta-text\">\n {epochToDisplay(record.createdAtEpoch)}\n </Typography>\n </div>\n ) : null}\n\n <div className=\"mr-orig__header-actions\">\n {isSmart && !smartPanelOpen && (\n <button\n type=\"button\"\n className=\"mr-orig__show-smart-btn\"\n onClick={() => setSmartPanelOpen(true)}\n >\n <SmartSparkles aria-hidden />\n Smart Report\n </button>\n )}\n {preview.isHtml && hasCopyToNote && (\n <button\n ref={htmlCopyBtnRef}\n type=\"button\"\n className=\"mr-orig__html-copy-btn\"\n onClick={handleHtmlCopyToNote}\n disabled={isHtmlCopying}\n >\n {isHtmlCopying && <LoaderCircle size={12} className=\"mr-sv__loading-spinner\" aria-hidden />}\n Copy to note\n </button>\n )}\n {hasPreview && (\n <IconButton\n icon={<ExternalLink size={16} aria-hidden />}\n label=\"Open in new tab\"\n variant=\"ghost\"\n size=\"sm\"\n onClick={() =>\n window.open(preview.files[0].url, \"_blank\", \"noopener,noreferrer\")\n }\n />\n )}\n </div>\n </div>\n\n <div\n className=\"mr-sv__panel-body\"\n style={{ flex: 1, display: \"flex\", flexDirection: \"column\", overflow: \"hidden\" }}\n >\n {preview.status === \"loading\" && (\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n height: \"100%\",\n }}\n >\n <LoaderCircle size={44} className=\"mr-sv__loading-spinner\" aria-hidden />\n </div>\n )}\n {preview.status === \"error\" && (\n <Typography variant=\"muted\" className=\"mr-sv__panel-empty\">\n Failed to load document preview.\n </Typography>\n )}\n {preview.status === \"loaded\" && preview.files.length === 0 && (\n <Typography variant=\"muted\" className=\"mr-sv__panel-empty\">\n No preview available for this record.\n </Typography>\n )}\n\n {/* Non-smart: full-width PDF */}\n {hasPreview && !isSmart && (\n <div\n className=\"mr-record-preview__body\"\n style={{ flex: 1, display: \"flex\", overflow: \"hidden\" }}\n >\n <Suspense fallback={null}>\n <DocumentViewer\n files={preview.files}\n title={record?.title ?? \"\"}\n isHtml={preview.isHtml}\n />\n </Suspense>\n </div>\n )}\n\n {/* Smart: split view — PDF left, smart report panel right */}\n {hasPreview && isSmart && (\n <div className=\"mr-orig__split\">\n <div className=\"mr-orig__pdf-side\">\n <Suspense fallback={null}>\n <DocumentViewer\n files={preview.files}\n title={record?.title ?? \"\"}\n isHtml={preview.isHtml}\n />\n </Suspense>\n </div>\n\n {smartPanelOpen && (\n <div className=\"mr-orig__smart-side\">\n {/* Header */}\n <div className=\"mr-orig__smart-hdr\">\n <span className=\"mr-orig__smart-title\">Smart Report</span>\n <button\n type=\"button\"\n className=\"mr-orig__smart-collapse-btn\"\n aria-label=\"Collapse smart report panel\"\n onClick={() => setSmartPanelOpen(false)}\n >\n <ChevronRight size={16} aria-hidden />\n </button>\n </div>\n\n {/* Search */}\n <SearchInput\n className=\"mr-orig__smart-search\"\n iconSize={16}\n placeholder=\"Search vitals\"\n value={srSearch}\n onChange={setSrSearch}\n />\n\n {/* Filter tabs — only when at least one sub-category has data */}\n {(oorRows.length > 0 || noInterpRows.length > 0) && (\n <div className=\"mr-orig__smart-tabs-wrap\">\n <div className=\"mr-orig__smart-tabs\">\n {([\"all\", \"oor\", \"none\"] as SrTab[]).map((tab) => {\n if (tab === \"oor\" && oorRows.length === 0) return null;\n if (tab === \"none\" && noInterpRows.length === 0) return null;\n const count =\n tab === \"all\"\n ? tabCounts.all\n : tab === \"oor\"\n ? tabCounts.oor\n : tabCounts.none;\n const label =\n tab === \"all\"\n ? \"All\"\n : tab === \"oor\"\n ? \"Out of range\"\n : \"No interpretation\";\n return (\n <button\n key={tab}\n type=\"button\"\n className={`mr-orig__smart-tab${srTab === tab ? \" mr-orig__smart-tab--active\" : \"\"}`}\n onClick={() => setSrTab(tab)}\n >\n {label} ({count})\n </button>\n );\n })}\n </div>\n </div>\n )}\n\n {/* Vital list */}\n <div className=\"mr-orig__smart-list\">\n {vitalsStatus === \"loading\" && (\n <div className=\"mr-orig__smart-loading\">\n <LoaderCircle\n size={20}\n className=\"mr-sv__loading-spinner\"\n aria-hidden\n />\n </div>\n )}\n {vitalsStatus === \"loaded\" && filteredRows.length === 0 && (\n <Typography variant=\"muted\" className=\"mr-orig__smart-empty\">\n No vitals match.\n </Typography>\n )}\n {vitalsStatus === \"loaded\" &&\n filteredRows.map((row, idx) => {\n const cell = row.cells[0];\n const isOor =\n row.latestStatus === \"high\" || row.latestStatus === \"low\";\n const isSelected = srSelected.has(row.key);\n const isLast = idx === filteredRows.length - 1;\n return (\n <div\n key={row.key}\n className={`mr-orig__vital-item${isLast ? \" mr-orig__vital-item--last\" : \"\"}`}\n >\n <div\n className={`mr-orig__vital-row mr-orig__vital-row--selectable${isSelected ? \" mr-orig__vital-row--selected\" : \"\"}`}\n onClick={() => toggleSrRow(row.key)}\n >\n <span\n className={`mr-sv__checkbox mr-cc-table__row-check${isSelected ? \" mr-sv__checkbox--checked\" : \"\"}`}\n role=\"checkbox\"\n aria-checked={isSelected}\n tabIndex={0}\n onClick={(e) => {\n e.stopPropagation();\n toggleSrRow(row.key);\n }}\n onKeyDown={(e) => {\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault();\n e.stopPropagation();\n toggleSrRow(row.key);\n }\n }}\n >\n {isSelected && <Check size={10} strokeWidth={3} />}\n </span>\n <div className=\"mr-orig__vital-info\">\n <span className=\"mr-orig__vital-name\">{row.name}</span>\n {row.refRange && (\n <span className=\"mr-orig__vital-ref\">\n Ref {row.refRange}\n </span>\n )}\n </div>\n {cell && (\n <div className=\"mr-orig__vital-value\">\n <span\n className={`mr-orig__vital-val${isOor ? \" mr-orig__vital-val--oor\" : \"\"}`}\n >\n {cell.value}\n </span>\n {cell.unit && (\n <span className=\"mr-orig__vital-unit\">{cell.unit}</span>\n )}\n </div>\n )}\n {row.ekaId && (\n <button\n type=\"button\"\n className={`mr-orig__vital-expand-btn${expandedVital === row.key ? \" mr-orig__vital-expand-btn--open\" : \"\"}`}\n onClick={(e) => { e.stopPropagation(); toggleExpand(row.key); }}\n aria-label={expandedVital === row.key ? \"Collapse readings\" : \"Show latest readings\"}\n >\n <ChevronDown size={13} aria-hidden />\n </button>\n )}\n </div>\n {expandedVital === row.key && row.ekaId && (\n <VitalReadingsExpanded vitalName={row.name} ekaId={row.ekaId} />\n )}\n </div>\n );\n })}\n </div>\n\n {/* Footer */}\n <div className=\"mr-cc-table__footer\">\n <span\n className={`mr-sv__checkbox mr-cc-table__footer-check${srAllSelected ? \" mr-sv__checkbox--checked\" : \"\"}`}\n role=\"checkbox\"\n aria-checked={srAllSelected}\n tabIndex={0}\n onClick={toggleSrAll}\n onKeyDown={(e) => {\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault();\n toggleSrAll();\n }\n }}\n >\n {srAllSelected && <Check size={10} strokeWidth={3} />}\n </span>\n <span className=\"mr-cc-table__footer-label\">Select all</span>\n <span className=\"mr-cc-table__footer-count\">\n {srSelected.size} of {filteredRows.length} selected\n </span>\n <button\n ref={srCopyBtnRef}\n type=\"button\"\n className=\"mr-cc-table__copy-note-btn\"\n disabled={!srSomeSelected || !hasCopyToNote}\n onClick={handleSrCopyToNote}\n >\n Copy to note\n </button>\n </div>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction VitalReadingsExpanded({ vitalName, ekaId }: { vitalName: string; ekaId: string }) {\n const { store } = useSdk();\n const recordsById = useStore(store, (s) => s.records.byId);\n const { data: trendData, status } = useParameterTrend(ekaId);\n\n const readings = useMemo(() => {\n const trend = trendData as ParameterTrendResponse | null;\n if (!trend?.vitals_info?.length) return [];\n return [...trend.vitals_info]\n .sort((a, b) => (b.date ?? 0) - (a.date ?? 0))\n .slice(0, 3)\n .map((info) => {\n const dr = (info.display_result ?? \"\").toLowerCase();\n const isOor = dr.includes(\"high\") || dr.includes(\"above\") || dr.includes(\"abnormal_high\") ||\n dr.includes(\"low\") || dr.includes(\"below\") || dr.includes(\"abnormal_low\");\n return {\n value: info.val != null ? String(info.val) : ((info as any).val_string ?? \"—\"),\n date: epochToDisplay(recordsById[info.document_id]?.createdAtEpoch ?? 0),\n isOor,\n };\n });\n }, [trendData, recordsById]);\n\n if (status === \"loading\") {\n return (\n <div className=\"mr-orig__vital-readings mr-orig__vital-readings--loading\">\n <LoaderCircle size={16} className=\"mr-sv__loading-spinner\" aria-hidden />\n </div>\n );\n }\n\n if (status === \"error\" || !readings.length) {\n return (\n <div className=\"mr-orig__vital-readings\">\n <Typography variant=\"muted\" className=\"mr-orig__vital-readings-empty\">\n No readings available\n </Typography>\n </div>\n );\n }\n\n return (\n <div className=\"mr-orig__vital-readings\">\n <div className=\"mr-orig__vital-readings-title\">\n LATEST READINGS FOR {vitalName.toUpperCase()}\n </div>\n <div className=\"mr-orig__vital-readings-grid\">\n {readings.map((r, i) => (\n <div key={i} className=\"mr-orig__vital-reading-item\">\n <span className={`mr-orig__vital-reading-value${r.isOor ? \" mr-orig__vital-reading-value--oor\" : \"\"}`}>{r.value}</span>\n <span className=\"mr-orig__vital-reading-date\">{r.date}</span>\n </div>\n ))}\n </div>\n </div>\n );\n}\n"]}
|