@eka-care/medical-records-ui 1.0.41 → 1.0.45
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/{DocumentViewer-OM6D4CSI.mjs → DocumentViewer-5AXKL75U.mjs} +2 -2
- package/dist/{DocumentViewer-D7OJVVZM.js → DocumentViewer-Y3SQ2BMS.js} +2 -2
- package/dist/{DocumentViewer-D7OJVVZM.js.map → DocumentViewer-Y3SQ2BMS.js.map} +1 -1
- package/dist/{OriginalRecordPanel-NSQMZFMV.js → OriginalRecordPanel-SJIBGHYZ.js} +30 -25
- package/dist/OriginalRecordPanel-SJIBGHYZ.js.map +1 -0
- package/dist/{OriginalRecordPanel-CVRKPYKT.mjs → OriginalRecordPanel-UM74PRBO.mjs} +12 -7
- package/dist/OriginalRecordPanel-UM74PRBO.mjs.map +1 -0
- package/dist/{PdfViewer-WIV5AUJB.mjs → PdfViewer-CG2577E4.mjs} +10 -1
- package/dist/PdfViewer-CG2577E4.mjs.map +1 -0
- package/dist/{PdfViewer-EAN6EQAB.js → PdfViewer-GIWRL6FQ.js} +12 -3
- package/dist/PdfViewer-GIWRL6FQ.js.map +1 -0
- package/dist/SmartUploadModal-4NFBULTI.js +9 -0
- package/dist/{SmartUploadModal-WNG252SR.js.map → SmartUploadModal-4NFBULTI.js.map} +1 -1
- package/dist/SmartUploadModal-II4GAIZO.mjs +9 -0
- package/dist/VitalHistoryPanel-2ZH4QOAP.mjs +10 -0
- package/dist/VitalHistoryPanel-VNSNMPBP.js +10 -0
- package/dist/{VitalHistoryPanel-COG2QEMQ.js.map → VitalHistoryPanel-VNSNMPBP.js.map} +1 -1
- package/dist/{chunk-6DJNAJYX.mjs → chunk-2QLZBSDH.mjs} +3 -7
- package/dist/chunk-2QLZBSDH.mjs.map +1 -0
- package/dist/{chunk-QSHHTVRB.js → chunk-APAMRQEM.js} +14 -14
- package/dist/{chunk-QSHHTVRB.js.map → chunk-APAMRQEM.js.map} +1 -1
- package/dist/{chunk-KRJUK644.js → chunk-BUBHVTFB.js} +21 -21
- package/dist/{chunk-KRJUK644.js.map → chunk-BUBHVTFB.js.map} +1 -1
- package/dist/{chunk-4RV67VS2.mjs → chunk-GDGLQD4W.mjs} +3 -3
- package/dist/{chunk-6Q22OJIY.mjs → chunk-KFSHL25P.mjs} +5 -2
- package/dist/chunk-KFSHL25P.mjs.map +1 -0
- package/dist/{chunk-VCLXS52U.js → chunk-OIN3TV63.js} +10 -14
- package/dist/chunk-OIN3TV63.js.map +1 -0
- package/dist/{chunk-6HMB6X7X.js → chunk-P7LLGYUQ.js} +5 -2
- package/dist/chunk-P7LLGYUQ.js.map +1 -0
- package/dist/{chunk-CUB3CD2F.mjs → chunk-RXQLS6QF.mjs} +2 -2
- package/dist/index.css +6 -0
- package/dist/index.css.map +1 -1
- package/dist/index.js +128 -128
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +45 -45
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +6 -0
- package/dist/styles.css.map +1 -1
- package/dist/{widgets-W4GSPSJ5.mjs → widgets-4KYAUU6R.mjs} +2 -2
- package/dist/widgets-WAYNWNMG.js +43 -0
- package/dist/{widgets-FMDKF5F3.js.map → widgets-WAYNWNMG.js.map} +1 -1
- package/package.json +4 -1
- package/dist/OriginalRecordPanel-CVRKPYKT.mjs.map +0 -1
- package/dist/OriginalRecordPanel-NSQMZFMV.js.map +0 -1
- package/dist/PdfViewer-EAN6EQAB.js.map +0 -1
- package/dist/PdfViewer-WIV5AUJB.mjs.map +0 -1
- package/dist/SmartUploadModal-ALIJ3RLP.mjs +0 -9
- package/dist/SmartUploadModal-WNG252SR.js +0 -9
- package/dist/VitalHistoryPanel-BWNSQYGJ.mjs +0 -10
- package/dist/VitalHistoryPanel-COG2QEMQ.js +0 -10
- package/dist/chunk-6DJNAJYX.mjs.map +0 -1
- package/dist/chunk-6HMB6X7X.js.map +0 -1
- package/dist/chunk-6Q22OJIY.mjs.map +0 -1
- package/dist/chunk-VCLXS52U.js.map +0 -1
- package/dist/widgets-FMDKF5F3.js +0 -43
- /package/dist/{DocumentViewer-OM6D4CSI.mjs.map → DocumentViewer-5AXKL75U.mjs.map} +0 -0
- /package/dist/{SmartUploadModal-ALIJ3RLP.mjs.map → SmartUploadModal-II4GAIZO.mjs.map} +0 -0
- /package/dist/{VitalHistoryPanel-BWNSQYGJ.mjs.map → VitalHistoryPanel-2ZH4QOAP.mjs.map} +0 -0
- /package/dist/{chunk-4RV67VS2.mjs.map → chunk-GDGLQD4W.mjs.map} +0 -0
- /package/dist/{chunk-CUB3CD2F.mjs.map → chunk-RXQLS6QF.mjs.map} +0 -0
- /package/dist/{widgets-W4GSPSJ5.mjs.map → widgets-4KYAUU6R.mjs.map} +0 -0
|
@@ -59,7 +59,7 @@ function TextViewer({ url }) {
|
|
|
59
59
|
|
|
60
60
|
// src/views/RecordPreview/DocumentViewer.tsx
|
|
61
61
|
import { jsx as jsx2, jsxs } from "react/jsx-runtime";
|
|
62
|
-
var PdfViewer = lazy(() => import("./PdfViewer-
|
|
62
|
+
var PdfViewer = lazy(() => import("./PdfViewer-CG2577E4.mjs").then((m) => ({ default: m.PdfViewer })));
|
|
63
63
|
var PAGE_WIDTH = 595;
|
|
64
64
|
var ZOOM_STEP = 0.25;
|
|
65
65
|
var ZOOM_MIN = 0.5;
|
|
@@ -195,4 +195,4 @@ function DocumentViewer({ files, title, isHtml }) {
|
|
|
195
195
|
export {
|
|
196
196
|
DocumentViewer
|
|
197
197
|
};
|
|
198
|
-
//# sourceMappingURL=DocumentViewer-
|
|
198
|
+
//# sourceMappingURL=DocumentViewer-5AXKL75U.mjs.map
|
|
@@ -59,7 +59,7 @@ function TextViewer({ url }) {
|
|
|
59
59
|
|
|
60
60
|
// src/views/RecordPreview/DocumentViewer.tsx
|
|
61
61
|
|
|
62
|
-
var PdfViewer = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./PdfViewer-
|
|
62
|
+
var PdfViewer = _react.lazy.call(void 0, () => Promise.resolve().then(() => _interopRequireWildcard(require("./PdfViewer-GIWRL6FQ.js"))).then((m) => ({ default: m.PdfViewer })));
|
|
63
63
|
var PAGE_WIDTH = 595;
|
|
64
64
|
var ZOOM_STEP = 0.25;
|
|
65
65
|
var ZOOM_MIN = 0.5;
|
|
@@ -195,4 +195,4 @@ function DocumentViewer({ files, title, isHtml }) {
|
|
|
195
195
|
|
|
196
196
|
|
|
197
197
|
exports.DocumentViewer = DocumentViewer;
|
|
198
|
-
//# sourceMappingURL=DocumentViewer-
|
|
198
|
+
//# sourceMappingURL=DocumentViewer-Y3SQ2BMS.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["/home/runner/work/medical-records-ui/medical-records-ui/dist/DocumentViewer-D7OJVVZM.js","../src/views/RecordPreview/DocumentViewer.tsx","../src/views/RecordPreview/TextViewer.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/medical-records-ui/medical-records-ui/dist/DocumentViewer-D7OJVVZM.js","sourcesContent":[null,"import { lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n ChevronLeft,\n ChevronRight,\n Minus,\n Plus,\n Download,\n Maximize,\n Minimize,\n Globe,\n} from 'lucide-react';\nimport { TextViewer } from './TextViewer';\nimport type { PreviewFile } from '../../connection';\n\nconst PdfViewer = lazy(() => import('./PdfViewer').then((m) => ({ default: m.PdfViewer })));\n\nexport interface DocumentViewerProps {\n files: PreviewFile[];\n title: string;\n isHtml?: boolean;\n}\n\nconst PAGE_WIDTH = 595; \nconst ZOOM_STEP = 0.25;\nconst ZOOM_MIN = 0.5;\nconst ZOOM_MAX = 3;\n\nexport function DocumentViewer({ files, title, isHtml }: DocumentViewerProps) {\n const [zoom, setZoom] = useState(1);\n const [pageInfo, setPageInfo] = useState({ current: 1, total: 0 });\n const [scrollToPage, setScrollToPage] = useState(1);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current);\n document.addEventListener('fullscreenchange', onChange);\n return () => document.removeEventListener('fullscreenchange', onChange);\n }, []);\n\n const toggleFullscreen = () => {\n if (document.fullscreenElement) void document.exitFullscreen();\n else void rootRef.current?.requestFullscreen?.();\n };\n\n const primary = files[0] ?? null;\n const isPdf = primary?.kind === 'pdf';\n const images = files.filter((f) => f.kind === 'image');\n const isZoomable = isPdf || images.length > 0;\n\n const zoomOut = () => setZoom((z) => Math.max(ZOOM_MIN, +(z - ZOOM_STEP).toFixed(2)));\n const zoomIn = () => setZoom((z) => Math.min(ZOOM_MAX, +(z + ZOOM_STEP).toFixed(2)));\n\n const prevPage = () => setScrollToPage(Math.max(1, pageInfo.current - 1));\n const nextPage = () => setScrollToPage(Math.min(pageInfo.total, pageInfo.current + 1));\n\n // Download / print fetch the file into a blob URL rather than re-opening the\n // signed URL directly, so it works even when the document is already loaded.\n const withBlobUrl = useCallback(async (fn: (objUrl: string) => void) => {\n if (!primary) return;\n try {\n const res = await fetch(primary.url);\n const blob = await res.blob();\n const objUrl = URL.createObjectURL(blob);\n fn(objUrl);\n // Revoke after the consumer has had a chance to use it.\n setTimeout(() => URL.revokeObjectURL(objUrl), 120_000);\n } catch {\n // Fall back to opening the original URL.\n fn(primary.url);\n }\n }, [primary]);\n\n const handleDownload = () =>\n withBlobUrl((objUrl) => {\n const a = document.createElement('a');\n a.href = objUrl;\n a.download = title || 'document';\n a.click();\n });\n\n return (\n <div className={`mr-doc-viewer${isHtml ? ' mr-doc-viewer--html' : ''}`} ref={rootRef}>\n {!isHtml && <div className=\"mr-doc-viewer__toolbar\">\n <span className=\"mr-doc-viewer__filename\">{title}</span>\n {isPdf && (\n <div className=\"mr-doc-viewer__pages\">\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n onClick={prevPage}\n disabled={pageInfo.current <= 1}\n >\n <ChevronLeft size={18} aria-hidden />\n </button>\n <span className=\"mr-doc-viewer__page-badge\">{pageInfo.current}</span>\n <span>/</span>\n <span>{pageInfo.total || '—'}</span>\n <button\n type=\"button\"\n aria-label=\"Next page\"\n onClick={nextPage}\n disabled={pageInfo.current >= pageInfo.total}\n >\n <ChevronRight size={18} aria-hidden />\n </button>\n </div>\n )}\n {isZoomable && (\n <div className=\"mr-doc-viewer__zoom\">\n <button type=\"button\" aria-label=\"Zoom out\" onClick={zoomOut} disabled={zoom <= ZOOM_MIN}>\n <Minus size={20} aria-hidden />\n </button>\n <span className=\"mr-doc-viewer__zoom-badge\">{Math.round(zoom * 100)}%</span>\n <button type=\"button\" aria-label=\"Zoom in\" onClick={zoomIn} disabled={zoom >= ZOOM_MAX}>\n <Plus size={20} aria-hidden />\n </button>\n </div>\n )}\n <div className=\"mr-doc-viewer__actions\">\n <button type=\"button\" aria-label=\"Download\" onClick={handleDownload} disabled={!primary}>\n <Download size={20} aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label={isFullscreen ? 'Exit full screen' : 'Full screen'}\n onClick={toggleFullscreen}\n >\n {isFullscreen ? <Minimize size={20} aria-hidden /> : <Maximize size={20} aria-hidden />}\n </button>\n </div>\n </div>}\n\n {isHtml && (\n <div className=\"mr-doc-viewer__html-bar\">\n <div className=\"mr-doc-viewer__html-bar-left\">\n <Globe size={12} aria-hidden />\n <span>Previewing HTML file – you can copy to a note and edit this file. The original record that you are viewing now will not be affected.</span>\n </div>\n <button\n type=\"button\"\n className=\"mr-doc-viewer__html-download\"\n aria-label=\"Download\"\n onClick={handleDownload}\n disabled={!primary}\n >\n <Download size={16} aria-hidden />\n </button>\n </div>\n )}\n\n <div className=\"mr-doc-viewer__canvas\">\n {!primary ? (\n <div className=\"mr-doc-viewer__status\">No preview available for this record.</div>\n ) : isPdf ? (\n <Suspense fallback={<div className=\"mr-doc-viewer__status\">Loading viewer…</div>}>\n <PdfViewer\n url={primary.url}\n baseWidth={PAGE_WIDTH}\n scale={zoom}\n scrollToPage={scrollToPage}\n onPageInfo={setPageInfo}\n />\n </Suspense>\n ) : images.length > 0 ? (\n images.map((img, i) => (\n <img\n key={i}\n className=\"mr-doc-viewer__image\"\n src={img.url}\n alt={`${title} ${i + 1}`}\n style={{ transform: `scale(${zoom})`, transformOrigin: 'top center' }}\n />\n ))\n ) : (\n <TextViewer url={primary.url} />\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useState } from 'react';\n\nexport interface TextViewerProps {\n url: string;\n}\n\nexport function TextViewer({ url }: TextViewerProps) {\n const [state, setState] = useState<{ status: 'loading' | 'loaded' | 'error'; text: string }>({\n status: 'loading',\n text: '',\n });\n\n useEffect(() => {\n let cancelled = false;\n setState({ status: 'loading', text: '' });\n (async () => {\n try {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fetch ${res.status}`);\n const text = await res.text();\n if (text.trimStart().startsWith('%PDF')) throw new Error('binary');\n if (!cancelled) setState({ status: 'loaded', text });\n } catch {\n if (!cancelled) setState({ status: 'error', text: '' });\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [url]);\n\n if (state.status === 'loading') {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>Loading document...</div>;\n }\n if (state.status === 'error') {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>Couldn't load this document.</div>;\n }\n if (!state.text.trim()) {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>This record appears to be empty.</div>;\n }\n return (\n <iframe\n className=\"mr-doc-viewer__html-frame\"\n srcDoc={state.text}\n sandbox=\"allow-same-origin\"\n title=\"HTML preview\"\n />\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/medical-records-ui/medical-records-ui/dist/DocumentViewer-Y3SQ2BMS.js","../src/views/RecordPreview/DocumentViewer.tsx","../src/views/RecordPreview/TextViewer.tsx"],"names":["jsx"],"mappings":"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","file":"/home/runner/work/medical-records-ui/medical-records-ui/dist/DocumentViewer-Y3SQ2BMS.js","sourcesContent":[null,"import { lazy, Suspense, useCallback, useEffect, useRef, useState } from 'react';\nimport {\n ChevronLeft,\n ChevronRight,\n Minus,\n Plus,\n Download,\n Maximize,\n Minimize,\n Globe,\n} from 'lucide-react';\nimport { TextViewer } from './TextViewer';\nimport type { PreviewFile } from '../../connection';\n\nconst PdfViewer = lazy(() => import('./PdfViewer').then((m) => ({ default: m.PdfViewer })));\n\nexport interface DocumentViewerProps {\n files: PreviewFile[];\n title: string;\n isHtml?: boolean;\n}\n\nconst PAGE_WIDTH = 595; \nconst ZOOM_STEP = 0.25;\nconst ZOOM_MIN = 0.5;\nconst ZOOM_MAX = 3;\n\nexport function DocumentViewer({ files, title, isHtml }: DocumentViewerProps) {\n const [zoom, setZoom] = useState(1);\n const [pageInfo, setPageInfo] = useState({ current: 1, total: 0 });\n const [scrollToPage, setScrollToPage] = useState(1);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const rootRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current);\n document.addEventListener('fullscreenchange', onChange);\n return () => document.removeEventListener('fullscreenchange', onChange);\n }, []);\n\n const toggleFullscreen = () => {\n if (document.fullscreenElement) void document.exitFullscreen();\n else void rootRef.current?.requestFullscreen?.();\n };\n\n const primary = files[0] ?? null;\n const isPdf = primary?.kind === 'pdf';\n const images = files.filter((f) => f.kind === 'image');\n const isZoomable = isPdf || images.length > 0;\n\n const zoomOut = () => setZoom((z) => Math.max(ZOOM_MIN, +(z - ZOOM_STEP).toFixed(2)));\n const zoomIn = () => setZoom((z) => Math.min(ZOOM_MAX, +(z + ZOOM_STEP).toFixed(2)));\n\n const prevPage = () => setScrollToPage(Math.max(1, pageInfo.current - 1));\n const nextPage = () => setScrollToPage(Math.min(pageInfo.total, pageInfo.current + 1));\n\n // Download / print fetch the file into a blob URL rather than re-opening the\n // signed URL directly, so it works even when the document is already loaded.\n const withBlobUrl = useCallback(async (fn: (objUrl: string) => void) => {\n if (!primary) return;\n try {\n const res = await fetch(primary.url);\n const blob = await res.blob();\n const objUrl = URL.createObjectURL(blob);\n fn(objUrl);\n // Revoke after the consumer has had a chance to use it.\n setTimeout(() => URL.revokeObjectURL(objUrl), 120_000);\n } catch {\n // Fall back to opening the original URL.\n fn(primary.url);\n }\n }, [primary]);\n\n const handleDownload = () =>\n withBlobUrl((objUrl) => {\n const a = document.createElement('a');\n a.href = objUrl;\n a.download = title || 'document';\n a.click();\n });\n\n return (\n <div className={`mr-doc-viewer${isHtml ? ' mr-doc-viewer--html' : ''}`} ref={rootRef}>\n {!isHtml && <div className=\"mr-doc-viewer__toolbar\">\n <span className=\"mr-doc-viewer__filename\">{title}</span>\n {isPdf && (\n <div className=\"mr-doc-viewer__pages\">\n <button\n type=\"button\"\n aria-label=\"Previous page\"\n onClick={prevPage}\n disabled={pageInfo.current <= 1}\n >\n <ChevronLeft size={18} aria-hidden />\n </button>\n <span className=\"mr-doc-viewer__page-badge\">{pageInfo.current}</span>\n <span>/</span>\n <span>{pageInfo.total || '—'}</span>\n <button\n type=\"button\"\n aria-label=\"Next page\"\n onClick={nextPage}\n disabled={pageInfo.current >= pageInfo.total}\n >\n <ChevronRight size={18} aria-hidden />\n </button>\n </div>\n )}\n {isZoomable && (\n <div className=\"mr-doc-viewer__zoom\">\n <button type=\"button\" aria-label=\"Zoom out\" onClick={zoomOut} disabled={zoom <= ZOOM_MIN}>\n <Minus size={20} aria-hidden />\n </button>\n <span className=\"mr-doc-viewer__zoom-badge\">{Math.round(zoom * 100)}%</span>\n <button type=\"button\" aria-label=\"Zoom in\" onClick={zoomIn} disabled={zoom >= ZOOM_MAX}>\n <Plus size={20} aria-hidden />\n </button>\n </div>\n )}\n <div className=\"mr-doc-viewer__actions\">\n <button type=\"button\" aria-label=\"Download\" onClick={handleDownload} disabled={!primary}>\n <Download size={20} aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label={isFullscreen ? 'Exit full screen' : 'Full screen'}\n onClick={toggleFullscreen}\n >\n {isFullscreen ? <Minimize size={20} aria-hidden /> : <Maximize size={20} aria-hidden />}\n </button>\n </div>\n </div>}\n\n {isHtml && (\n <div className=\"mr-doc-viewer__html-bar\">\n <div className=\"mr-doc-viewer__html-bar-left\">\n <Globe size={12} aria-hidden />\n <span>Previewing HTML file – you can copy to a note and edit this file. The original record that you are viewing now will not be affected.</span>\n </div>\n <button\n type=\"button\"\n className=\"mr-doc-viewer__html-download\"\n aria-label=\"Download\"\n onClick={handleDownload}\n disabled={!primary}\n >\n <Download size={16} aria-hidden />\n </button>\n </div>\n )}\n\n <div className=\"mr-doc-viewer__canvas\">\n {!primary ? (\n <div className=\"mr-doc-viewer__status\">No preview available for this record.</div>\n ) : isPdf ? (\n <Suspense fallback={<div className=\"mr-doc-viewer__status\">Loading viewer…</div>}>\n <PdfViewer\n url={primary.url}\n baseWidth={PAGE_WIDTH}\n scale={zoom}\n scrollToPage={scrollToPage}\n onPageInfo={setPageInfo}\n />\n </Suspense>\n ) : images.length > 0 ? (\n images.map((img, i) => (\n <img\n key={i}\n className=\"mr-doc-viewer__image\"\n src={img.url}\n alt={`${title} ${i + 1}`}\n style={{ transform: `scale(${zoom})`, transformOrigin: 'top center' }}\n />\n ))\n ) : (\n <TextViewer url={primary.url} />\n )}\n </div>\n </div>\n );\n}\n","import { useEffect, useState } from 'react';\n\nexport interface TextViewerProps {\n url: string;\n}\n\nexport function TextViewer({ url }: TextViewerProps) {\n const [state, setState] = useState<{ status: 'loading' | 'loaded' | 'error'; text: string }>({\n status: 'loading',\n text: '',\n });\n\n useEffect(() => {\n let cancelled = false;\n setState({ status: 'loading', text: '' });\n (async () => {\n try {\n const res = await fetch(url);\n if (!res.ok) throw new Error(`fetch ${res.status}`);\n const text = await res.text();\n if (text.trimStart().startsWith('%PDF')) throw new Error('binary');\n if (!cancelled) setState({ status: 'loaded', text });\n } catch {\n if (!cancelled) setState({ status: 'error', text: '' });\n }\n })();\n return () => {\n cancelled = true;\n };\n }, [url]);\n\n if (state.status === 'loading') {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>Loading document...</div>;\n }\n if (state.status === 'error') {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>Couldn't load this document.</div>;\n }\n if (!state.text.trim()) {\n return <div className=\"mr-doc-viewer__status\" style={{ color: 'var(--mr-muted-foreground)' }}>This record appears to be empty.</div>;\n }\n return (\n <iframe\n className=\"mr-doc-viewer__html-frame\"\n srcDoc={state.text}\n sandbox=\"allow-same-origin\"\n title=\"HTML preview\"\n />\n );\n}\n"]}
|
|
@@ -7,7 +7,7 @@ var _chunkLV7EI4MZjs = require('./chunk-LV7EI4MZ.js');
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var _chunkOIN3TV63js = require('./chunk-OIN3TV63.js');
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
@@ -15,7 +15,7 @@ var _chunkVCLXS52Ujs = require('./chunk-VCLXS52U.js');
|
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
var
|
|
18
|
+
var _chunkP7LLGYUQjs = require('./chunk-P7LLGYUQ.js');
|
|
19
19
|
|
|
20
20
|
// src/views/components/shared/OriginalRecordPanel.tsx
|
|
21
21
|
var _react = require('react');
|
|
@@ -23,7 +23,7 @@ var _lucidereact = require('lucide-react');
|
|
|
23
23
|
var _zustand = require('zustand');
|
|
24
24
|
var _jsxruntime = require('react/jsx-runtime');
|
|
25
25
|
var DocumentViewer = _react.lazy.call(void 0,
|
|
26
|
-
() => Promise.resolve().then(() => _interopRequireWildcard(require("./DocumentViewer-
|
|
26
|
+
() => Promise.resolve().then(() => _interopRequireWildcard(require("./DocumentViewer-Y3SQ2BMS.js"))).then((m) => ({
|
|
27
27
|
default: m.DocumentViewer
|
|
28
28
|
}))
|
|
29
29
|
);
|
|
@@ -39,12 +39,12 @@ function OriginalRecordPanel({
|
|
|
39
39
|
caseId,
|
|
40
40
|
onBack
|
|
41
41
|
}) {
|
|
42
|
-
const { store } =
|
|
42
|
+
const { store } = _chunkP7LLGYUQjs.useSdk.call(void 0, );
|
|
43
43
|
const record = _zustand.useStore.call(void 0, store, (s) => s.records.byId[recordId]);
|
|
44
44
|
const recordsById = _zustand.useStore.call(void 0, store, (s) => s.records.byId);
|
|
45
|
-
const preview =
|
|
46
|
-
const { replaceOriginal, onCopyToNote, onCopyVitalsToNote, hasCopyToNote, onToast } =
|
|
47
|
-
const { status: vitalsStatus, table } =
|
|
45
|
+
const preview = _chunkOIN3TV63js.useRecordPreview.call(void 0, recordId);
|
|
46
|
+
const { replaceOriginal, onCopyToNote, onCopyVitalsToNote, hasCopyToNote, onToast } = _chunkOIN3TV63js.useSmartRecordsActions.call(void 0, );
|
|
47
|
+
const { status: vitalsStatus, table } = _chunkOIN3TV63js.useRecordPanelTable.call(void 0,
|
|
48
48
|
_optionalChain([record, 'optionalAccess', _3 => _3.isSmart]) ? recordId : null
|
|
49
49
|
);
|
|
50
50
|
const [smartPanelOpen, setSmartPanelOpen] = _react.useState.call(void 0, true);
|
|
@@ -70,10 +70,13 @@ function OriginalRecordPanel({
|
|
|
70
70
|
}, [dropdownOpen]);
|
|
71
71
|
const caseRecords = _react.useMemo.call(void 0, () => {
|
|
72
72
|
if (!caseId) return [];
|
|
73
|
-
return Object.values(recordsById).filter(
|
|
73
|
+
return Object.values(recordsById).filter(
|
|
74
|
+
(r) => r != null && (caseId === "__ungrouped__" ? r.cases.length === 0 : r.cases.includes(caseId))
|
|
75
|
+
).sort((a, b) => b.createdAtEpoch - a.createdAtEpoch);
|
|
74
76
|
}, [recordsById, caseId]);
|
|
75
77
|
const currentIndex = caseRecords.findIndex((r) => r.id === recordId);
|
|
76
78
|
const total = caseRecords.length;
|
|
79
|
+
const isUngrouped = caseId === "__ungrouped__";
|
|
77
80
|
const goTo = _react.useCallback.call(void 0,
|
|
78
81
|
(r) => {
|
|
79
82
|
setDropdownOpen(false);
|
|
@@ -241,7 +244,8 @@ function OriginalRecordPanel({
|
|
|
241
244
|
total,
|
|
242
245
|
" RECORD",
|
|
243
246
|
total !== 1 ? "S" : "",
|
|
244
|
-
"
|
|
247
|
+
" ",
|
|
248
|
+
isUngrouped ? "WITH NO CARE CONTEXT" : "FOUND IN THIS ENCOUNTER"
|
|
245
249
|
] }),
|
|
246
250
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__dropdown-list", children: caseRecords.map((r) => {
|
|
247
251
|
const isActive = r.id === recordId;
|
|
@@ -268,10 +272,11 @@ function OriginalRecordPanel({
|
|
|
268
272
|
r.isSmart && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { className: "mr-orig__dropdown-smart-badge", children: [
|
|
269
273
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkLV7EI4MZjs.SmartSparkles_default, { "aria-hidden": true }),
|
|
270
274
|
"Smart Report"
|
|
271
|
-
] })
|
|
275
|
+
] }),
|
|
276
|
+
_optionalChain([r, 'access', _20 => _20.fileType, 'optionalAccess', _21 => _21.toUpperCase, 'call', _22 => _22()]) === "HTML" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-tag-chip mr-tag-chip--html", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-tag-chip__label", children: "HTML" }) })
|
|
272
277
|
] }),
|
|
273
278
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__dropdown-meta", children: [
|
|
274
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children:
|
|
279
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { children: _chunkP7LLGYUQjs.epochToDisplay.call(void 0, r.createdAtEpoch) }),
|
|
275
280
|
r.isSmart && r.totalVitals > 0 && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, _jsxruntime.Fragment, { children: [
|
|
276
281
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, "span", { className: "mr-orig__dropdown-dot", children: "\xB7" }),
|
|
277
282
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "span", { children: [
|
|
@@ -303,8 +308,8 @@ function OriginalRecordPanel({
|
|
|
303
308
|
}) })
|
|
304
309
|
] })
|
|
305
310
|
] }) : record ? /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-sv__panel-info", children: [
|
|
306
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
307
|
-
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
311
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "label", as: "span", className: "mr-sv__panel-name", children: record.title }),
|
|
312
|
+
/* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "hint", as: "span", className: "mr-sv__panel-meta-text", children: _chunkP7LLGYUQjs.epochToDisplay.call(void 0, record.createdAtEpoch) })
|
|
308
313
|
] }) : null,
|
|
309
314
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__header-actions", children: [
|
|
310
315
|
preview.isHtml && hasCopyToNote && /* @__PURE__ */ _jsxruntime.jsxs.call(void 0,
|
|
@@ -322,7 +327,7 @@ function OriginalRecordPanel({
|
|
|
322
327
|
}
|
|
323
328
|
),
|
|
324
329
|
hasPreview && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
325
|
-
|
|
330
|
+
_chunkP7LLGYUQjs.IconButton,
|
|
326
331
|
{
|
|
327
332
|
icon: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.ExternalLink, { size: 16, "aria-hidden": true }),
|
|
328
333
|
label: "Open in new tab",
|
|
@@ -351,8 +356,8 @@ function OriginalRecordPanel({
|
|
|
351
356
|
children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _lucidereact.LoaderCircle, { size: 44, className: "mr-sv__loading-spinner", "aria-hidden": true })
|
|
352
357
|
}
|
|
353
358
|
),
|
|
354
|
-
preview.status === "error" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
355
|
-
preview.status === "loaded" && preview.files.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
359
|
+
preview.status === "error" && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "muted", className: "mr-sv__panel-empty", children: "Failed to load document preview." }),
|
|
360
|
+
preview.status === "loaded" && preview.files.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "muted", className: "mr-sv__panel-empty", children: "No preview available for this record." }),
|
|
356
361
|
hasPreview && !isSmart && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
357
362
|
"div",
|
|
358
363
|
{
|
|
@@ -362,7 +367,7 @@ function OriginalRecordPanel({
|
|
|
362
367
|
DocumentViewer,
|
|
363
368
|
{
|
|
364
369
|
files: preview.files,
|
|
365
|
-
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess',
|
|
370
|
+
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess', _23 => _23.title]), () => ( "")),
|
|
366
371
|
isHtml: preview.isHtml
|
|
367
372
|
}
|
|
368
373
|
) })
|
|
@@ -373,7 +378,7 @@ function OriginalRecordPanel({
|
|
|
373
378
|
DocumentViewer,
|
|
374
379
|
{
|
|
375
380
|
files: preview.files,
|
|
376
|
-
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess',
|
|
381
|
+
title: _nullishCoalesce(_optionalChain([record, 'optionalAccess', _24 => _24.title]), () => ( "")),
|
|
377
382
|
isHtml: preview.isHtml
|
|
378
383
|
}
|
|
379
384
|
) }) }),
|
|
@@ -396,7 +401,7 @@ function OriginalRecordPanel({
|
|
|
396
401
|
)
|
|
397
402
|
] }),
|
|
398
403
|
/* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
399
|
-
|
|
404
|
+
_chunkP7LLGYUQjs.SearchInput_default,
|
|
400
405
|
{
|
|
401
406
|
className: "mr-orig__smart-search",
|
|
402
407
|
iconSize: 16,
|
|
@@ -435,7 +440,7 @@ function OriginalRecordPanel({
|
|
|
435
440
|
"aria-hidden": true
|
|
436
441
|
}
|
|
437
442
|
) }),
|
|
438
|
-
vitalsStatus === "loaded" && filteredRows.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
443
|
+
vitalsStatus === "loaded" && filteredRows.length === 0 && /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "muted", className: "mr-orig__smart-empty", children: "No vitals match." }),
|
|
439
444
|
vitalsStatus === "loaded" && filteredRows.map((row, idx) => {
|
|
440
445
|
const cell = row.cells[0];
|
|
441
446
|
const isOor = row.latestStatus === "high" || row.latestStatus === "low";
|
|
@@ -550,7 +555,7 @@ function OriginalRecordPanel({
|
|
|
550
555
|
}
|
|
551
556
|
)
|
|
552
557
|
] })
|
|
553
|
-
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-side mr-orig__smart-side--collapsed", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
558
|
+
] }) : /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__smart-side mr-orig__smart-side--collapsed", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Tooltip, { content: "Show smart report", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
554
559
|
"button",
|
|
555
560
|
{
|
|
556
561
|
type: "button",
|
|
@@ -568,10 +573,10 @@ function OriginalRecordPanel({
|
|
|
568
573
|
] });
|
|
569
574
|
}
|
|
570
575
|
function VitalReadingsExpanded({ vitalName, ekaId }) {
|
|
571
|
-
const { data: trendData, status } =
|
|
576
|
+
const { data: trendData, status } = _chunkOIN3TV63js.useParameterTrend.call(void 0, ekaId);
|
|
572
577
|
const readings = _react.useMemo.call(void 0, () => {
|
|
573
578
|
const trend = trendData;
|
|
574
|
-
if (!_optionalChain([trend, 'optionalAccess',
|
|
579
|
+
if (!_optionalChain([trend, 'optionalAccess', _25 => _25.vitals_info, 'optionalAccess', _26 => _26.length])) return [];
|
|
575
580
|
return [...trend.vitals_info].sort((a, b) => (_nullishCoalesce(b.date, () => ( 0))) - (_nullishCoalesce(a.date, () => ( 0)))).slice(0, 3).map((info) => {
|
|
576
581
|
const dr = (_nullishCoalesce(info.display_result, () => ( ""))).toLowerCase();
|
|
577
582
|
const isOor = dr.includes("high") || dr.includes("above") || dr.includes("abnormal_high") || dr.includes("low") || dr.includes("below") || dr.includes("abnormal_low");
|
|
@@ -586,7 +591,7 @@ function VitalReadingsExpanded({ vitalName, ekaId }) {
|
|
|
586
591
|
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 }) });
|
|
587
592
|
}
|
|
588
593
|
if (status === "error" || !readings.length) {
|
|
589
|
-
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__vital-readings", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0,
|
|
594
|
+
return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, "div", { className: "mr-orig__vital-readings", children: /* @__PURE__ */ _jsxruntime.jsx.call(void 0, _chunkP7LLGYUQjs.Typography, { variant: "muted", className: "mr-orig__vital-readings-empty", children: "No readings available" }) });
|
|
590
595
|
}
|
|
591
596
|
return /* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-readings", children: [
|
|
592
597
|
/* @__PURE__ */ _jsxruntime.jsxs.call(void 0, "div", { className: "mr-orig__vital-readings-title", children: [
|
|
@@ -602,4 +607,4 @@ function VitalReadingsExpanded({ vitalName, ekaId }) {
|
|
|
602
607
|
|
|
603
608
|
|
|
604
609
|
exports.OriginalRecordPanel = OriginalRecordPanel;
|
|
605
|
-
//# sourceMappingURL=OriginalRecordPanel-
|
|
610
|
+
//# sourceMappingURL=OriginalRecordPanel-SJIBGHYZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["/home/runner/work/medical-records-ui/medical-records-ui/dist/OriginalRecordPanel-SJIBGHYZ.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-SJIBGHYZ.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, Tooltip } 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, onToast } =\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(\n (r): r is RecordItem =>\n r != null &&\n (caseId === \"__ungrouped__\" ? r.cases.length === 0 : r.cases.includes(caseId)),\n )\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 const isUngrouped = caseId === \"__ungrouped__\";\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 } catch {\n onToast?.(\"Failed to copy document text\", \"error\");\n } finally {\n setIsHtmlCopying(false);\n }\n }, [preview.files, onCopyVitalsToNote, onCopyToNote, onToast]);\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 <button type=\"button\" className=\"mr-sv__back-btn\" onClick={onBack}>\n <ChevronLeft size={16} aria-hidden />\n Back\n </button>\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\" : \"\"}{\" \"}\n {isUngrouped ? \"WITH NO CARE CONTEXT\" : \"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 {r.fileType?.toUpperCase() === \"HTML\" && (\n <span className=\"mr-tag-chip mr-tag-chip--html\">\n <span className=\"mr-tag-chip__label\">HTML</span>\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 {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-row\">\n <span className=\"mr-orig__smart-title\">Smart Report</span>\n <SmartSparkles className=\"mr-orig__smart-title-icon\" aria-hidden />\n </span>\n <button\n type=\"button\"\n className=\"mr-sv__sidebar-collapse-btn mr-orig__smart-expanded-btn\"\n aria-label=\"Collapse smart report panel\"\n aria-expanded={true}\n onClick={() => setSmartPanelOpen(false)}\n >\n <ChevronRight size={14} 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\" onClick={toggleSrAll}>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 className=\"mr-orig__smart-side mr-orig__smart-side--collapsed\">\n <Tooltip content=\"Show smart report\">\n <button\n type=\"button\"\n className=\"mr-sv__sidebar-collapse-btn mr-orig__smart-collapsed-btn\"\n aria-label=\"Expand smart report panel\"\n aria-expanded={false}\n onClick={() => setSmartPanelOpen(true)}\n >\n <span className=\"mr-orig__smart-collapsed-icon-wrap\">\n <SmartSparkles className=\"mr-orig__smart-collapsed-icon\" aria-hidden />\n </span>\n </button>\n </Tooltip>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction VitalReadingsExpanded({ vitalName, ekaId }: { vitalName: string; ekaId: string }) {\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: info.display_time || \"\",\n isOor,\n };\n });\n }, [trendData]);\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"]}
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
useRecordPanelTable,
|
|
8
8
|
useRecordPreview,
|
|
9
9
|
useSmartRecordsActions
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2QLZBSDH.mjs";
|
|
11
11
|
import {
|
|
12
12
|
IconButton,
|
|
13
13
|
SearchInput_default,
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
Typography,
|
|
16
16
|
epochToDisplay,
|
|
17
17
|
useSdk
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-KFSHL25P.mjs";
|
|
19
19
|
|
|
20
20
|
// src/views/components/shared/OriginalRecordPanel.tsx
|
|
21
21
|
import { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
@@ -23,7 +23,7 @@ import { ChevronLeft, ChevronRight, ChevronDown, ExternalLink, Check, File, Load
|
|
|
23
23
|
import { useStore } from "zustand";
|
|
24
24
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
25
25
|
var DocumentViewer = lazy(
|
|
26
|
-
() => import("./DocumentViewer-
|
|
26
|
+
() => import("./DocumentViewer-5AXKL75U.mjs").then((m) => ({
|
|
27
27
|
default: m.DocumentViewer
|
|
28
28
|
}))
|
|
29
29
|
);
|
|
@@ -70,10 +70,13 @@ function OriginalRecordPanel({
|
|
|
70
70
|
}, [dropdownOpen]);
|
|
71
71
|
const caseRecords = useMemo(() => {
|
|
72
72
|
if (!caseId) return [];
|
|
73
|
-
return Object.values(recordsById).filter(
|
|
73
|
+
return Object.values(recordsById).filter(
|
|
74
|
+
(r) => r != null && (caseId === "__ungrouped__" ? r.cases.length === 0 : r.cases.includes(caseId))
|
|
75
|
+
).sort((a, b) => b.createdAtEpoch - a.createdAtEpoch);
|
|
74
76
|
}, [recordsById, caseId]);
|
|
75
77
|
const currentIndex = caseRecords.findIndex((r) => r.id === recordId);
|
|
76
78
|
const total = caseRecords.length;
|
|
79
|
+
const isUngrouped = caseId === "__ungrouped__";
|
|
77
80
|
const goTo = useCallback(
|
|
78
81
|
(r) => {
|
|
79
82
|
setDropdownOpen(false);
|
|
@@ -241,7 +244,8 @@ function OriginalRecordPanel({
|
|
|
241
244
|
total,
|
|
242
245
|
" RECORD",
|
|
243
246
|
total !== 1 ? "S" : "",
|
|
244
|
-
"
|
|
247
|
+
" ",
|
|
248
|
+
isUngrouped ? "WITH NO CARE CONTEXT" : "FOUND IN THIS ENCOUNTER"
|
|
245
249
|
] }),
|
|
246
250
|
/* @__PURE__ */ jsx("div", { className: "mr-orig__dropdown-list", children: caseRecords.map((r) => {
|
|
247
251
|
const isActive = r.id === recordId;
|
|
@@ -268,7 +272,8 @@ function OriginalRecordPanel({
|
|
|
268
272
|
r.isSmart && /* @__PURE__ */ jsxs("span", { className: "mr-orig__dropdown-smart-badge", children: [
|
|
269
273
|
/* @__PURE__ */ jsx(SmartSparkles_default, { "aria-hidden": true }),
|
|
270
274
|
"Smart Report"
|
|
271
|
-
] })
|
|
275
|
+
] }),
|
|
276
|
+
r.fileType?.toUpperCase() === "HTML" && /* @__PURE__ */ jsx("span", { className: "mr-tag-chip mr-tag-chip--html", children: /* @__PURE__ */ jsx("span", { className: "mr-tag-chip__label", children: "HTML" }) })
|
|
272
277
|
] }),
|
|
273
278
|
/* @__PURE__ */ jsxs("div", { className: "mr-orig__dropdown-meta", children: [
|
|
274
279
|
/* @__PURE__ */ jsx("span", { children: epochToDisplay(r.createdAtEpoch) }),
|
|
@@ -602,4 +607,4 @@ function VitalReadingsExpanded({ vitalName, ekaId }) {
|
|
|
602
607
|
export {
|
|
603
608
|
OriginalRecordPanel
|
|
604
609
|
};
|
|
605
|
-
//# sourceMappingURL=OriginalRecordPanel-
|
|
610
|
+
//# sourceMappingURL=OriginalRecordPanel-UM74PRBO.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/views/components/shared/OriginalRecordPanel.tsx"],"sourcesContent":["\"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, Tooltip } 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, onToast } =\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(\n (r): r is RecordItem =>\n r != null &&\n (caseId === \"__ungrouped__\" ? r.cases.length === 0 : r.cases.includes(caseId)),\n )\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 const isUngrouped = caseId === \"__ungrouped__\";\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 } catch {\n onToast?.(\"Failed to copy document text\", \"error\");\n } finally {\n setIsHtmlCopying(false);\n }\n }, [preview.files, onCopyVitalsToNote, onCopyToNote, onToast]);\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 <button type=\"button\" className=\"mr-sv__back-btn\" onClick={onBack}>\n <ChevronLeft size={16} aria-hidden />\n Back\n </button>\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\" : \"\"}{\" \"}\n {isUngrouped ? \"WITH NO CARE CONTEXT\" : \"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 {r.fileType?.toUpperCase() === \"HTML\" && (\n <span className=\"mr-tag-chip mr-tag-chip--html\">\n <span className=\"mr-tag-chip__label\">HTML</span>\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 {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-row\">\n <span className=\"mr-orig__smart-title\">Smart Report</span>\n <SmartSparkles className=\"mr-orig__smart-title-icon\" aria-hidden />\n </span>\n <button\n type=\"button\"\n className=\"mr-sv__sidebar-collapse-btn mr-orig__smart-expanded-btn\"\n aria-label=\"Collapse smart report panel\"\n aria-expanded={true}\n onClick={() => setSmartPanelOpen(false)}\n >\n <ChevronRight size={14} 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\" onClick={toggleSrAll}>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 className=\"mr-orig__smart-side mr-orig__smart-side--collapsed\">\n <Tooltip content=\"Show smart report\">\n <button\n type=\"button\"\n className=\"mr-sv__sidebar-collapse-btn mr-orig__smart-collapsed-btn\"\n aria-label=\"Expand smart report panel\"\n aria-expanded={false}\n onClick={() => setSmartPanelOpen(true)}\n >\n <span className=\"mr-orig__smart-collapsed-icon-wrap\">\n <SmartSparkles className=\"mr-orig__smart-collapsed-icon\" aria-hidden />\n </span>\n </button>\n </Tooltip>\n </div>\n )}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nfunction VitalReadingsExpanded({ vitalName, ekaId }: { vitalName: string; ekaId: string }) {\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: info.display_time || \"\",\n isOor,\n };\n });\n }, [trendData]);\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"],"mappings":"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","names":[]}
|
|
@@ -33,6 +33,7 @@ function PdfViewer({ url, baseWidth, scale, scrollToPage, onPageInfo }) {
|
|
|
33
33
|
const [current, setCurrent] = useState(1);
|
|
34
34
|
const containerRef = useRef(null);
|
|
35
35
|
const pageRefs = useRef([]);
|
|
36
|
+
const pdfRef = useRef(null);
|
|
36
37
|
useEffect(() => {
|
|
37
38
|
let cancelled = false;
|
|
38
39
|
setStatus("loading");
|
|
@@ -42,6 +43,11 @@ function PdfViewer({ url, baseWidth, scale, scrollToPage, onPageInfo }) {
|
|
|
42
43
|
await ensurePdfjs();
|
|
43
44
|
const pdfjs = window.pdfjsLib;
|
|
44
45
|
const pdf = await pdfjs.getDocument(url).promise;
|
|
46
|
+
if (cancelled) {
|
|
47
|
+
pdf.destroy();
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
pdfRef.current = pdf;
|
|
45
51
|
const numPages = pdf.numPages;
|
|
46
52
|
const rendered = [];
|
|
47
53
|
for (let i = 1; i <= numPages; i++) {
|
|
@@ -56,6 +62,7 @@ function PdfViewer({ url, baseWidth, scale, scrollToPage, onPageInfo }) {
|
|
|
56
62
|
ctx.scale(dpr, dpr);
|
|
57
63
|
await page.render({ canvasContext: ctx, canvas, viewport }).promise;
|
|
58
64
|
rendered.push({ pageNum: i, dataUrl: canvas.toDataURL(), width: viewport.width, height: viewport.height });
|
|
65
|
+
page.cleanup();
|
|
59
66
|
if (!cancelled) setPages([...rendered]);
|
|
60
67
|
}
|
|
61
68
|
if (!cancelled) setStatus("done");
|
|
@@ -65,6 +72,8 @@ function PdfViewer({ url, baseWidth, scale, scrollToPage, onPageInfo }) {
|
|
|
65
72
|
})();
|
|
66
73
|
return () => {
|
|
67
74
|
cancelled = true;
|
|
75
|
+
pdfRef.current?.destroy();
|
|
76
|
+
pdfRef.current = null;
|
|
68
77
|
};
|
|
69
78
|
}, [url, baseWidth]);
|
|
70
79
|
useEffect(() => {
|
|
@@ -138,4 +147,4 @@ function PdfViewer({ url, baseWidth, scale, scrollToPage, onPageInfo }) {
|
|
|
138
147
|
export {
|
|
139
148
|
PdfViewer
|
|
140
149
|
};
|
|
141
|
-
//# sourceMappingURL=PdfViewer-
|
|
150
|
+
//# sourceMappingURL=PdfViewer-CG2577E4.mjs.map
|