@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.
Files changed (37) hide show
  1. package/dist/{OriginalRecordPanel-IUZUPXY2.js → OriginalRecordPanel-PVNAZ5CR.js} +184 -78
  2. package/dist/OriginalRecordPanel-PVNAZ5CR.js.map +1 -0
  3. package/dist/{OriginalRecordPanel-GGRHXGWI.mjs → OriginalRecordPanel-W6FNO7U2.mjs} +176 -70
  4. package/dist/OriginalRecordPanel-W6FNO7U2.mjs.map +1 -0
  5. package/dist/VitalHistoryPanel-WI44AXJU.mjs +10 -0
  6. package/dist/VitalHistoryPanel-WKBIR2RD.js +10 -0
  7. package/dist/{VitalHistoryPanel-L4QTKZBC.js.map → VitalHistoryPanel-WKBIR2RD.js.map} +1 -1
  8. package/dist/{chunk-SO5RWBVJ.mjs → chunk-5TQ6OPAQ.mjs} +38 -73
  9. package/dist/chunk-5TQ6OPAQ.mjs.map +1 -0
  10. package/dist/{chunk-KWF6LUXK.js → chunk-GKREOUK2.js} +3 -3
  11. package/dist/{chunk-KWF6LUXK.js.map → chunk-GKREOUK2.js.map} +1 -1
  12. package/dist/{chunk-HNRF345J.mjs → chunk-LUH7D3K7.mjs} +33 -4
  13. package/dist/chunk-LUH7D3K7.mjs.map +1 -0
  14. package/dist/{chunk-32VKLNCO.mjs → chunk-MRQMRFWX.mjs} +2 -2
  15. package/dist/{chunk-LYPWE42A.js → chunk-VBMKRSTX.js} +40 -75
  16. package/dist/chunk-VBMKRSTX.js.map +1 -0
  17. package/dist/{chunk-TNTVD3TN.js → chunk-YT6OD4YU.js} +31 -2
  18. package/dist/chunk-YT6OD4YU.js.map +1 -0
  19. package/dist/index.css +150 -17
  20. package/dist/index.css.map +1 -1
  21. package/dist/index.js +80 -45
  22. package/dist/index.js.map +1 -1
  23. package/dist/index.mjs +79 -44
  24. package/dist/index.mjs.map +1 -1
  25. package/dist/styles.css +150 -17
  26. package/dist/styles.css.map +1 -1
  27. package/package.json +1 -1
  28. package/dist/OriginalRecordPanel-GGRHXGWI.mjs.map +0 -1
  29. package/dist/OriginalRecordPanel-IUZUPXY2.js.map +0 -1
  30. package/dist/VitalHistoryPanel-AQ6QVGCB.mjs +0 -10
  31. package/dist/VitalHistoryPanel-L4QTKZBC.js +0 -10
  32. package/dist/chunk-HNRF345J.mjs.map +0 -1
  33. package/dist/chunk-LYPWE42A.js.map +0 -1
  34. package/dist/chunk-SO5RWBVJ.mjs.map +0 -1
  35. package/dist/chunk-TNTVD3TN.js.map +0 -1
  36. /package/dist/{VitalHistoryPanel-AQ6QVGCB.mjs.map → VitalHistoryPanel-WI44AXJU.mjs.map} +0 -0
  37. /package/dist/{chunk-32VKLNCO.mjs.map → chunk-MRQMRFWX.mjs.map} +0 -0
@@ -2,11 +2,13 @@
2
2
 
3
3
 
4
4
 
5
- var _chunkKWF6LUXKjs = require('./chunk-KWF6LUXK.js');
5
+ var _chunkGKREOUK2js = require('./chunk-GKREOUK2.js');
6
6
 
7
7
 
8
8
 
9
- var _chunkTNTVD3TNjs = require('./chunk-TNTVD3TN.js');
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 = _chunkTNTVD3TNjs.useRecordPreview.call(void 0, recordId);
43
- const { openOriginal, onCopyToNote, onCopyVitalsToNote, hasCopyToNote } = _chunkTNTVD3TNjs.useSmartRecordsActions.call(void 0, );
44
- const { status: vitalsStatus, table } = _chunkKWF6LUXKjs.useRecordPanelTable.call(void 0,
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
- openOriginal(r.id, "smart", void 0, caseId);
79
+ replaceOriginal(r.id, caseId);
74
80
  },
75
- [openOriginal, caseId]
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 isSmart = _nullishCoalesce(_optionalChain([record, 'optionalAccess', _7 => _7.isSmart]), () => ( false));
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
- setDropdownOpen((v) => !v);
210
+ goPrev();
170
211
  },
171
- "aria-label": "Show records",
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', _8 => _8.title]), () => ( "Record")) }),
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
- setDropdownOpen((v) => !v);
232
+ goNext();
191
233
  },
192
- "aria-label": "Show records",
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
- _chunkKWF6LUXKjs.SmartSparkles_default,
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, _chunkKWF6LUXKjs.SmartSparkles_default, { "aria-hidden": true }),
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, _chunkKWF6LUXKjs.SmartSparkles_default, { "aria-hidden": true }),
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', _9 => _9.title]), () => ( "")),
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', _10 => _10.title]), () => ( "")),
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.jsxs.call(void 0, "div", { className: "mr-orig__smart-search", children: [
353
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.Search, { size: 14, "aria-hidden": true, className: "mr-orig__smart-search-icon" }),
354
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
355
- "input",
356
- {
357
- type: "text",
358
- className: "mr-orig__smart-search-input",
359
- placeholder: "Search vitals",
360
- value: srSearch,
361
- onChange: (e) => setSrSearch(e.target.value)
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.jsx.call(void 0,
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: /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
404
- "div",
405
- {
406
- className: `mr-orig__vital-row${srSomeSelected ? " mr-orig__vital-row--selectable" : ""}${isSelected ? " mr-orig__vital-row--selected" : ""}`,
407
- onClick: srSomeSelected ? () => toggleSrRow(row.key) : void 0,
408
- children: [
409
- /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
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-orig__vital-val${isOor ? " mr-orig__vital-val--oor" : ""}`,
442
- children: cell.value
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
- cell.unit && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__vital-unit", children: cell.unit })
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
- srSomeSelected && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-cc-table__footer", children: [
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-IUZUPXY2.js.map
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":"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","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"]}