@eka-care/medical-records-ui 1.0.3
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/README.md +151 -0
- package/dist/DocumentViewer-WXL7OZXK.mjs +197 -0
- package/dist/DocumentViewer-WXL7OZXK.mjs.map +1 -0
- package/dist/DocumentViewer-Z3GOU5NU.js +197 -0
- package/dist/DocumentViewer-Z3GOU5NU.js.map +1 -0
- package/dist/PdfViewer-EAN6EQAB.js +141 -0
- package/dist/PdfViewer-EAN6EQAB.js.map +1 -0
- package/dist/PdfViewer-WIV5AUJB.mjs +141 -0
- package/dist/PdfViewer-WIV5AUJB.mjs.map +1 -0
- package/dist/index.css +3869 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +390 -0
- package/dist/index.d.ts +390 -0
- package/dist/index.js +4796 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +4796 -0
- package/dist/index.mjs.map +1 -0
- package/dist/styles.css +3869 -0
- package/dist/styles.css.map +1 -0
- package/dist/styles.d.mts +2 -0
- package/dist/styles.d.ts +2 -0
- package/package.json +57 -0
- package/src/index.ts +40 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,4796 @@
|
|
|
1
|
+
// src/connection/SdkProvider.tsx
|
|
2
|
+
import { useEffect, useMemo } from "react";
|
|
3
|
+
|
|
4
|
+
// src/workers/shared/coreTypes.ts
|
|
5
|
+
import {
|
|
6
|
+
MedicalRecordsClient,
|
|
7
|
+
EkaCareApiError,
|
|
8
|
+
UploadFailedError,
|
|
9
|
+
UPLOAD_CONSTRAINTS
|
|
10
|
+
} from "@eka-care/medical-records-ts-sdk";
|
|
11
|
+
var DOCUMENT_TYPE_LABELS = {
|
|
12
|
+
ps: "Prescription",
|
|
13
|
+
lr: "Lab Report",
|
|
14
|
+
dc: "Discharge Summary",
|
|
15
|
+
vc: "Vaccine Certificate",
|
|
16
|
+
in: "Insurance",
|
|
17
|
+
iv: "Invoice",
|
|
18
|
+
sc: "Scan",
|
|
19
|
+
op: "Other"
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// src/connection/workerClient.ts
|
|
23
|
+
var core = null;
|
|
24
|
+
var CORE_SDK_AVAILABLE = true;
|
|
25
|
+
function initWorkerClient(config, oid) {
|
|
26
|
+
if (core) {
|
|
27
|
+
if (config.accessToken) core.setAuthToken(config.accessToken);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
const resolvedOid = oid ?? config.oid;
|
|
31
|
+
core = new MedicalRecordsClient({
|
|
32
|
+
environment: config.environment,
|
|
33
|
+
baseUrl: config.baseUrl,
|
|
34
|
+
defaultHeaders: config.defaultHeaders,
|
|
35
|
+
onError: config.onError,
|
|
36
|
+
onUnauthorized: config.onUnauthorized,
|
|
37
|
+
transport: config.transport,
|
|
38
|
+
cache: resolvedOid ? { oid: resolvedOid } : void 0
|
|
39
|
+
});
|
|
40
|
+
if (config.accessToken) core.setAuthToken(config.accessToken);
|
|
41
|
+
}
|
|
42
|
+
function getCore() {
|
|
43
|
+
if (!core) {
|
|
44
|
+
throw new Error("SDK not initialised \u2014 wrap your tree in <SdkProvider>");
|
|
45
|
+
}
|
|
46
|
+
return core;
|
|
47
|
+
}
|
|
48
|
+
function teardownWorkerClient() {
|
|
49
|
+
core = null;
|
|
50
|
+
}
|
|
51
|
+
async function logoutMedicalRecords(bid) {
|
|
52
|
+
if (bid && core) {
|
|
53
|
+
try {
|
|
54
|
+
await core.clearDbForBid(bid);
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
core = null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/stores/createPatientStore.ts
|
|
62
|
+
import { createStore } from "zustand/vanilla";
|
|
63
|
+
import { subscribeWithSelector } from "zustand/middleware";
|
|
64
|
+
|
|
65
|
+
// src/stores/slices/recordsSlice.ts
|
|
66
|
+
function sameRecord(a, b) {
|
|
67
|
+
return a.id === b.id && a.title === b.title && a.type === b.type && a.typeCode === b.typeCode && a.thumbnailUrl === b.thumbnailUrl && a.createdAtEpoch === b.createdAtEpoch && a.updatedAtEpoch === b.updatedAtEpoch && a.syncState === b.syncState && a.fileType === b.fileType && a.isSmart === b.isSmart && a.isAnalysing === b.isAnalysing && a.tags.length === b.tags.length && a.tags.every((t, i) => t === b.tags[i]) && a.cases.length === b.cases.length && a.cases.every((c, i) => c === b.cases[i]);
|
|
68
|
+
}
|
|
69
|
+
var createRecordsSlice = (set) => ({
|
|
70
|
+
records: {
|
|
71
|
+
byId: {},
|
|
72
|
+
ids: [],
|
|
73
|
+
status: "idle",
|
|
74
|
+
error: null,
|
|
75
|
+
pendingIds: /* @__PURE__ */ new Set(),
|
|
76
|
+
setAll: (records) => set((state) => {
|
|
77
|
+
const prev = state.records.byId;
|
|
78
|
+
const byId = {};
|
|
79
|
+
let changed = records.length !== state.records.ids.length;
|
|
80
|
+
for (const r of records) {
|
|
81
|
+
const existing = prev[r.id];
|
|
82
|
+
byId[r.id] = existing && sameRecord(existing, r) ? existing : r;
|
|
83
|
+
if (!existing || byId[r.id] !== existing) changed = true;
|
|
84
|
+
}
|
|
85
|
+
const nextIds = records.map((r) => r.id).sort((a, b) => byId[b].createdAtEpoch - byId[a].createdAtEpoch);
|
|
86
|
+
const sameIds = nextIds.length === state.records.ids.length && nextIds.every((id, i) => id === state.records.ids[i]);
|
|
87
|
+
const ids = sameIds ? state.records.ids : nextIds;
|
|
88
|
+
if (!changed && sameIds) return state;
|
|
89
|
+
return { records: { ...state.records, byId, ids } };
|
|
90
|
+
}),
|
|
91
|
+
upsert: (record) => set((state) => {
|
|
92
|
+
const byId = { ...state.records.byId, [record.id]: record };
|
|
93
|
+
const ids = record.id in state.records.byId ? state.records.ids : [record.id, ...state.records.ids];
|
|
94
|
+
return { records: { ...state.records, byId, ids } };
|
|
95
|
+
}),
|
|
96
|
+
remove: (id) => set((state) => {
|
|
97
|
+
const { [id]: _removed, ...byId } = state.records.byId;
|
|
98
|
+
return {
|
|
99
|
+
records: {
|
|
100
|
+
...state.records,
|
|
101
|
+
byId,
|
|
102
|
+
ids: state.records.ids.filter((i) => i !== id)
|
|
103
|
+
}
|
|
104
|
+
};
|
|
105
|
+
}),
|
|
106
|
+
markPending: (id) => set((state) => {
|
|
107
|
+
const pendingIds = new Set(state.records.pendingIds);
|
|
108
|
+
pendingIds.add(id);
|
|
109
|
+
return { records: { ...state.records, pendingIds } };
|
|
110
|
+
}),
|
|
111
|
+
unmarkPending: (id) => set((state) => {
|
|
112
|
+
const pendingIds = new Set(state.records.pendingIds);
|
|
113
|
+
pendingIds.delete(id);
|
|
114
|
+
return { records: { ...state.records, pendingIds } };
|
|
115
|
+
}),
|
|
116
|
+
setStatus: (status) => set((state) => ({ records: { ...state.records, status } })),
|
|
117
|
+
setError: (error) => set((state) => ({ records: { ...state.records, error, status: "error" } }))
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
// src/stores/slices/casesSlice.ts
|
|
122
|
+
var createCasesSlice = (set) => ({
|
|
123
|
+
cases: {
|
|
124
|
+
byId: {},
|
|
125
|
+
ids: [],
|
|
126
|
+
status: "idle",
|
|
127
|
+
error: null,
|
|
128
|
+
setAll: (cases) => set((state) => {
|
|
129
|
+
const byId = {};
|
|
130
|
+
for (const c of cases) byId[c.id] = c;
|
|
131
|
+
const ids = cases.map((c) => c.id).sort((a, b) => byId[b].createdAtEpoch - byId[a].createdAtEpoch);
|
|
132
|
+
return { cases: { ...state.cases, byId, ids } };
|
|
133
|
+
}),
|
|
134
|
+
upsert: (caseItem) => set((state) => {
|
|
135
|
+
const byId = { ...state.cases.byId, [caseItem.id]: caseItem };
|
|
136
|
+
const ids = caseItem.id in state.cases.byId ? state.cases.ids : [caseItem.id, ...state.cases.ids];
|
|
137
|
+
return { cases: { ...state.cases, byId, ids } };
|
|
138
|
+
}),
|
|
139
|
+
remove: (id) => set((state) => {
|
|
140
|
+
const { [id]: _removed, ...byId } = state.cases.byId;
|
|
141
|
+
return {
|
|
142
|
+
cases: { ...state.cases, byId, ids: state.cases.ids.filter((i) => i !== id) }
|
|
143
|
+
};
|
|
144
|
+
}),
|
|
145
|
+
setStatus: (status) => set((state) => ({ cases: { ...state.cases, status } })),
|
|
146
|
+
setError: (error) => set((state) => ({ cases: { ...state.cases, error, status: "error" } }))
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// src/stores/slices/uploadSlice.ts
|
|
151
|
+
var createUploadSlice = (set) => ({
|
|
152
|
+
uploadQueue: {
|
|
153
|
+
queue: [],
|
|
154
|
+
add: (item) => set((state) => ({
|
|
155
|
+
uploadQueue: { ...state.uploadQueue, queue: [...state.uploadQueue.queue, item] }
|
|
156
|
+
})),
|
|
157
|
+
updateProgress: (id, progress) => set((state) => ({
|
|
158
|
+
uploadQueue: {
|
|
159
|
+
...state.uploadQueue,
|
|
160
|
+
queue: state.uploadQueue.queue.map(
|
|
161
|
+
(q) => q.id === id ? { ...q, progress, status: "uploading" } : q
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
})),
|
|
165
|
+
markCompleted: (id, documentId) => set((state) => ({
|
|
166
|
+
uploadQueue: {
|
|
167
|
+
...state.uploadQueue,
|
|
168
|
+
queue: state.uploadQueue.queue.map(
|
|
169
|
+
(q) => q.id === id ? { ...q, status: "completed", progress: 100, documentId } : q
|
|
170
|
+
)
|
|
171
|
+
}
|
|
172
|
+
})),
|
|
173
|
+
markFailed: (id) => set((state) => ({
|
|
174
|
+
uploadQueue: {
|
|
175
|
+
...state.uploadQueue,
|
|
176
|
+
queue: state.uploadQueue.queue.map(
|
|
177
|
+
(q) => q.id === id ? { ...q, status: "upload_failure" } : q
|
|
178
|
+
)
|
|
179
|
+
}
|
|
180
|
+
})),
|
|
181
|
+
remove: (id) => set((state) => ({
|
|
182
|
+
uploadQueue: {
|
|
183
|
+
...state.uploadQueue,
|
|
184
|
+
queue: state.uploadQueue.queue.filter((q) => q.id !== id)
|
|
185
|
+
}
|
|
186
|
+
}))
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
// src/stores/slices/selectionSlice.ts
|
|
191
|
+
var createSelectionSlice = (set) => ({
|
|
192
|
+
selection: {
|
|
193
|
+
recordIds: /* @__PURE__ */ new Set(),
|
|
194
|
+
openDetailId: null,
|
|
195
|
+
toggleRecord: (id, max) => set((state) => {
|
|
196
|
+
const recordIds = new Set(state.selection.recordIds);
|
|
197
|
+
if (recordIds.has(id)) {
|
|
198
|
+
recordIds.delete(id);
|
|
199
|
+
} else {
|
|
200
|
+
if (max !== void 0 && recordIds.size >= max) return state;
|
|
201
|
+
recordIds.add(id);
|
|
202
|
+
}
|
|
203
|
+
return { selection: { ...state.selection, recordIds } };
|
|
204
|
+
}),
|
|
205
|
+
clearSelection: () => set((state) => {
|
|
206
|
+
if (state.selection.recordIds.size === 0) return state;
|
|
207
|
+
return { selection: { ...state.selection, recordIds: /* @__PURE__ */ new Set() } };
|
|
208
|
+
}),
|
|
209
|
+
openDetail: (id) => set((state) => ({ selection: { ...state.selection, openDetailId: id } }))
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
// src/stores/slices/filtersSlice.ts
|
|
214
|
+
var EMPTY_POPOVER = {
|
|
215
|
+
documentDateFrom: null,
|
|
216
|
+
documentDateTo: null,
|
|
217
|
+
uploadDateFrom: null,
|
|
218
|
+
uploadDateTo: null,
|
|
219
|
+
documentDatePreset: "anytime",
|
|
220
|
+
uploadDatePreset: "anytime",
|
|
221
|
+
tags: []
|
|
222
|
+
};
|
|
223
|
+
var INITIAL = {
|
|
224
|
+
type: null,
|
|
225
|
+
search: "",
|
|
226
|
+
...EMPTY_POPOVER,
|
|
227
|
+
sortBy: "date",
|
|
228
|
+
sortDir: "desc"
|
|
229
|
+
};
|
|
230
|
+
var createFiltersSlice = (set) => ({
|
|
231
|
+
filters: {
|
|
232
|
+
...INITIAL,
|
|
233
|
+
setType: (type) => set((state) => ({ filters: { ...state.filters, type } })),
|
|
234
|
+
setSearch: (search) => set((state) => ({ filters: { ...state.filters, search } })),
|
|
235
|
+
applyPopoverFilters: (f) => set((state) => ({ filters: { ...state.filters, ...f } })),
|
|
236
|
+
setSortBy: (sortBy) => set((state) => ({ filters: { ...state.filters, sortBy } })),
|
|
237
|
+
setSortDir: (sortDir) => set((state) => ({ filters: { ...state.filters, sortDir } })),
|
|
238
|
+
clearPopoverFilters: () => set((state) => ({ filters: { ...state.filters, ...EMPTY_POPOVER } })),
|
|
239
|
+
reset: () => set((state) => ({ filters: { ...state.filters, ...INITIAL } }))
|
|
240
|
+
}
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
// src/stores/slices/syncSlice.ts
|
|
244
|
+
var createSyncSlice = (set) => ({
|
|
245
|
+
sync: {
|
|
246
|
+
status: "online",
|
|
247
|
+
pendingSyncCount: 0,
|
|
248
|
+
setStatus: (status) => set((state) => ({ sync: { ...state.sync, status } })),
|
|
249
|
+
incrementPending: () => set((state) => ({
|
|
250
|
+
sync: { ...state.sync, pendingSyncCount: state.sync.pendingSyncCount + 1 }
|
|
251
|
+
})),
|
|
252
|
+
decrementPending: () => set((state) => ({
|
|
253
|
+
sync: {
|
|
254
|
+
...state.sync,
|
|
255
|
+
pendingSyncCount: Math.max(0, state.sync.pendingSyncCount - 1)
|
|
256
|
+
}
|
|
257
|
+
}))
|
|
258
|
+
}
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
// src/stores/slices/detailsSlice.ts
|
|
262
|
+
var createDetailsSlice = (set) => ({
|
|
263
|
+
details: {
|
|
264
|
+
byId: {},
|
|
265
|
+
setDetailLoading: (id) => set((state) => {
|
|
266
|
+
if (state.details.byId[id]?.status === "loading") return state;
|
|
267
|
+
return {
|
|
268
|
+
details: {
|
|
269
|
+
...state.details,
|
|
270
|
+
byId: {
|
|
271
|
+
...state.details.byId,
|
|
272
|
+
[id]: { status: "loading", isSmart: false, smartText: "" }
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}),
|
|
277
|
+
setDetail: (id, { isSmart, smartText }) => set((state) => ({
|
|
278
|
+
details: {
|
|
279
|
+
...state.details,
|
|
280
|
+
byId: {
|
|
281
|
+
...state.details.byId,
|
|
282
|
+
[id]: { status: "loaded", isSmart, smartText }
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
})),
|
|
286
|
+
setDetailError: (id) => set((state) => ({
|
|
287
|
+
details: {
|
|
288
|
+
...state.details,
|
|
289
|
+
byId: {
|
|
290
|
+
...state.details.byId,
|
|
291
|
+
[id]: { status: "error", isSmart: false, smartText: "" }
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
}))
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
// src/stores/createPatientStore.ts
|
|
299
|
+
function createPatientStore(bid, patientId) {
|
|
300
|
+
return createStore()(
|
|
301
|
+
subscribeWithSelector((...a) => ({
|
|
302
|
+
bid,
|
|
303
|
+
patientId,
|
|
304
|
+
...createRecordsSlice(...a),
|
|
305
|
+
...createCasesSlice(...a),
|
|
306
|
+
...createDetailsSlice(...a),
|
|
307
|
+
...createUploadSlice(...a),
|
|
308
|
+
...createSelectionSlice(...a),
|
|
309
|
+
...createFiltersSlice(...a),
|
|
310
|
+
...createSyncSlice(...a),
|
|
311
|
+
__cleanup: () => {
|
|
312
|
+
}
|
|
313
|
+
}))
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/connection/SdkContext.ts
|
|
318
|
+
import { createContext } from "react";
|
|
319
|
+
var SdkContext = createContext(null);
|
|
320
|
+
|
|
321
|
+
// src/helpers/documentTypeLabels.ts
|
|
322
|
+
var STATIC_LABELS = DOCUMENT_TYPE_LABELS ?? {};
|
|
323
|
+
function createDocumentTypeLabelResolver(types) {
|
|
324
|
+
const fromConfig = /* @__PURE__ */ new Map();
|
|
325
|
+
for (const t of types ?? []) {
|
|
326
|
+
if (t.id && t.display_name) fromConfig.set(t.id, t.display_name);
|
|
327
|
+
}
|
|
328
|
+
return (code) => fromConfig.get(code) ?? STATIC_LABELS[code] ?? code;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// src/components/icons/EmptyRecordsIcon.tsx
|
|
332
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
333
|
+
function EmptyRecordsIcon({ size = 96 }) {
|
|
334
|
+
return /* @__PURE__ */ jsxs(
|
|
335
|
+
"svg",
|
|
336
|
+
{
|
|
337
|
+
width: size,
|
|
338
|
+
height: size,
|
|
339
|
+
viewBox: "0 0 96 96",
|
|
340
|
+
fill: "none",
|
|
341
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
342
|
+
"aria-hidden": true,
|
|
343
|
+
children: [
|
|
344
|
+
/* @__PURE__ */ jsxs("g", { clipPath: "url(#mr-empty-clip)", children: [
|
|
345
|
+
/* @__PURE__ */ jsx(
|
|
346
|
+
"path",
|
|
347
|
+
{
|
|
348
|
+
d: "M73.92 0H22.08C9.88555 0 0 9.88555 0 22.08V73.92C0 86.1144 9.88555 96 22.08 96H73.92C86.1144 96 96 86.1144 96 73.92V22.08C96 9.88555 86.1144 0 73.92 0Z",
|
|
349
|
+
fill: "#E8F0FF"
|
|
350
|
+
}
|
|
351
|
+
),
|
|
352
|
+
/* @__PURE__ */ jsx("g", { opacity: "0.75", filter: "url(#mr-empty-f0)", children: /* @__PURE__ */ jsx(
|
|
353
|
+
"path",
|
|
354
|
+
{
|
|
355
|
+
d: "M73.0797 17.5H29.8797C25.9032 17.5 22.6797 20.7235 22.6797 24.7V61.18C22.6797 65.1565 25.9032 68.38 29.8797 68.38H73.0797C77.0561 68.38 80.2797 65.1565 80.2797 61.18V24.7C80.2797 20.7235 77.0561 17.5 73.0797 17.5Z",
|
|
356
|
+
fill: "white"
|
|
357
|
+
}
|
|
358
|
+
) }),
|
|
359
|
+
/* @__PURE__ */ jsx("g", { filter: "url(#mr-empty-f1)", children: /* @__PURE__ */ jsx(
|
|
360
|
+
"path",
|
|
361
|
+
{
|
|
362
|
+
d: "M65.4 25.1797H22.2C18.2235 25.1797 15 28.4032 15 32.3797V68.8597C15 72.8361 18.2235 76.0597 22.2 76.0597H65.4C69.3764 76.0597 72.6 72.8361 72.6 68.8597V32.3797C72.6 28.4032 69.3764 25.1797 65.4 25.1797Z",
|
|
363
|
+
fill: "white"
|
|
364
|
+
}
|
|
365
|
+
) }),
|
|
366
|
+
/* @__PURE__ */ jsx(
|
|
367
|
+
"path",
|
|
368
|
+
{
|
|
369
|
+
d: "M50.2802 40.54H37.3202C36.1272 40.54 35.1602 41.5071 35.1602 42.7C35.1602 43.893 36.1272 44.86 37.3202 44.86H50.2802C51.4731 44.86 52.4402 43.893 52.4402 42.7C52.4402 41.5071 51.4731 40.54 50.2802 40.54Z",
|
|
370
|
+
fill: "#93B8DA"
|
|
371
|
+
}
|
|
372
|
+
),
|
|
373
|
+
/* @__PURE__ */ jsx(
|
|
374
|
+
"path",
|
|
375
|
+
{
|
|
376
|
+
d: "M45.7204 36.4598C45.7204 35.2669 44.7533 34.2998 43.5604 34.2998C42.3675 34.2998 41.4004 35.2669 41.4004 36.4598V49.4198C41.4004 50.6127 42.3675 51.5798 43.5604 51.5798C44.7533 51.5798 45.7204 50.6127 45.7204 49.4198V36.4598Z",
|
|
377
|
+
fill: "#93B8DA"
|
|
378
|
+
}
|
|
379
|
+
),
|
|
380
|
+
/* @__PURE__ */ jsx(
|
|
381
|
+
"path",
|
|
382
|
+
{
|
|
383
|
+
d: "M63.7197 59.7402H23.8797C23.2169 59.7402 22.6797 60.2775 22.6797 60.9402C22.6797 61.603 23.2169 62.1402 23.8797 62.1402H63.7197C64.3824 62.1402 64.9197 61.603 64.9197 60.9402C64.9197 60.2775 64.3824 59.7402 63.7197 59.7402Z",
|
|
384
|
+
fill: "#C2D9EE"
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
/* @__PURE__ */ jsx(
|
|
388
|
+
"path",
|
|
389
|
+
{
|
|
390
|
+
d: "M52.1997 65.5H23.8797C23.2169 65.5 22.6797 66.0373 22.6797 66.7C22.6797 67.3627 23.2169 67.9 23.8797 67.9H52.1997C52.8624 67.9 53.3997 67.3627 53.3997 66.7C53.3997 66.0373 52.8624 65.5 52.1997 65.5Z",
|
|
391
|
+
fill: "#C2D9EE"
|
|
392
|
+
}
|
|
393
|
+
),
|
|
394
|
+
/* @__PURE__ */ jsx("g", { filter: "url(#mr-empty-f2)", children: /* @__PURE__ */ jsx(
|
|
395
|
+
"path",
|
|
396
|
+
{
|
|
397
|
+
d: "M65.8799 84.2198C73.0375 84.2198 78.8399 78.4174 78.8399 71.2598C78.8399 64.1022 73.0375 58.2998 65.8799 58.2998C58.7223 58.2998 52.9199 64.1022 52.9199 71.2598C52.9199 78.4174 58.7223 84.2198 65.8799 84.2198Z",
|
|
398
|
+
fill: "#2563EB"
|
|
399
|
+
}
|
|
400
|
+
) }),
|
|
401
|
+
/* @__PURE__ */ jsx("path", { d: "M65.8789 66.46V76.06", stroke: "white", strokeWidth: "1.68", strokeLinecap: "round" }),
|
|
402
|
+
/* @__PURE__ */ jsx("path", { d: "M61.0801 71.2598H70.6801", stroke: "white", strokeWidth: "1.68", strokeLinecap: "round" })
|
|
403
|
+
] }),
|
|
404
|
+
/* @__PURE__ */ jsxs("defs", { children: [
|
|
405
|
+
/* @__PURE__ */ jsxs(
|
|
406
|
+
"filter",
|
|
407
|
+
{
|
|
408
|
+
id: "mr-empty-f0",
|
|
409
|
+
x: "19.6797",
|
|
410
|
+
y: "15.5",
|
|
411
|
+
width: "63.6",
|
|
412
|
+
height: "56.8799",
|
|
413
|
+
filterUnits: "userSpaceOnUse",
|
|
414
|
+
colorInterpolationFilters: "sRGB",
|
|
415
|
+
children: [
|
|
416
|
+
/* @__PURE__ */ jsx("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
|
|
417
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
418
|
+
/* @__PURE__ */ jsx("feMorphology", { radius: "1", operator: "erode", in: "SourceAlpha", result: "effect1" }),
|
|
419
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
420
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1" }),
|
|
421
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
422
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
423
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1" }),
|
|
424
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
425
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
426
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1.5" }),
|
|
427
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
428
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
429
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "effect1", result: "effect2" }),
|
|
430
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect2", result: "shape" })
|
|
431
|
+
]
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
/* @__PURE__ */ jsxs(
|
|
435
|
+
"filter",
|
|
436
|
+
{
|
|
437
|
+
id: "mr-empty-f1",
|
|
438
|
+
x: "12",
|
|
439
|
+
y: "23.1797",
|
|
440
|
+
width: "63.6",
|
|
441
|
+
height: "56.8799",
|
|
442
|
+
filterUnits: "userSpaceOnUse",
|
|
443
|
+
colorInterpolationFilters: "sRGB",
|
|
444
|
+
children: [
|
|
445
|
+
/* @__PURE__ */ jsx("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
|
|
446
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
447
|
+
/* @__PURE__ */ jsx("feMorphology", { radius: "1", operator: "erode", in: "SourceAlpha", result: "effect1" }),
|
|
448
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
449
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1" }),
|
|
450
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
451
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
452
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1" }),
|
|
453
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
454
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
455
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1.5" }),
|
|
456
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
457
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
458
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "effect1", result: "effect2" }),
|
|
459
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect2", result: "shape" })
|
|
460
|
+
]
|
|
461
|
+
}
|
|
462
|
+
),
|
|
463
|
+
/* @__PURE__ */ jsxs(
|
|
464
|
+
"filter",
|
|
465
|
+
{
|
|
466
|
+
id: "mr-empty-f2",
|
|
467
|
+
x: "49.9199",
|
|
468
|
+
y: "56.2998",
|
|
469
|
+
width: "31.92",
|
|
470
|
+
height: "31.9199",
|
|
471
|
+
filterUnits: "userSpaceOnUse",
|
|
472
|
+
colorInterpolationFilters: "sRGB",
|
|
473
|
+
children: [
|
|
474
|
+
/* @__PURE__ */ jsx("feFlood", { floodOpacity: "0", result: "BackgroundImageFix" }),
|
|
475
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
476
|
+
/* @__PURE__ */ jsx("feMorphology", { radius: "1", operator: "erode", in: "SourceAlpha", result: "effect1" }),
|
|
477
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
478
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1" }),
|
|
479
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
480
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
481
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "BackgroundImageFix", result: "effect1" }),
|
|
482
|
+
/* @__PURE__ */ jsx("feColorMatrix", { in: "SourceAlpha", type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0", result: "hardAlpha" }),
|
|
483
|
+
/* @__PURE__ */ jsx("feOffset", { dy: "1" }),
|
|
484
|
+
/* @__PURE__ */ jsx("feGaussianBlur", { stdDeviation: "1.5" }),
|
|
485
|
+
/* @__PURE__ */ jsx("feComposite", { in2: "hardAlpha", operator: "out" }),
|
|
486
|
+
/* @__PURE__ */ jsx("feColorMatrix", { type: "matrix", values: "0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.1 0" }),
|
|
487
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in2: "effect1", result: "effect2" }),
|
|
488
|
+
/* @__PURE__ */ jsx("feBlend", { mode: "normal", in: "SourceGraphic", in2: "effect2", result: "shape" })
|
|
489
|
+
]
|
|
490
|
+
}
|
|
491
|
+
),
|
|
492
|
+
/* @__PURE__ */ jsx("clipPath", { id: "mr-empty-clip", children: /* @__PURE__ */ jsx("rect", { width: "96", height: "96", fill: "white" }) })
|
|
493
|
+
] })
|
|
494
|
+
]
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// src/connection/SdkProvider.tsx
|
|
500
|
+
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
501
|
+
function RecordsPlaceholder() {
|
|
502
|
+
return /* @__PURE__ */ jsxs2("div", { className: "mr-records-view__empty", children: [
|
|
503
|
+
/* @__PURE__ */ jsx2(EmptyRecordsIcon, { size: 96 }),
|
|
504
|
+
/* @__PURE__ */ jsx2("p", { className: "mr-records-view__empty-title", children: "No records yet" }),
|
|
505
|
+
/* @__PURE__ */ jsx2("p", { className: "mr-records-view__empty-desc", children: "Browse and attach the patient's medical records here." })
|
|
506
|
+
] });
|
|
507
|
+
}
|
|
508
|
+
function SdkProviderInner({ config, bid, patientId, documentTypes, children }) {
|
|
509
|
+
useEffect(() => {
|
|
510
|
+
initWorkerClient(config, patientId);
|
|
511
|
+
}, []);
|
|
512
|
+
initWorkerClient(config, patientId);
|
|
513
|
+
const store = useMemo(() => createPatientStore(bid, patientId), [bid, patientId]);
|
|
514
|
+
useEffect(() => () => store.getState().__cleanup(), [store]);
|
|
515
|
+
useEffect(() => {
|
|
516
|
+
const handleOnline = () => {
|
|
517
|
+
void getCore().sync();
|
|
518
|
+
};
|
|
519
|
+
window.addEventListener("online", handleOnline);
|
|
520
|
+
return () => window.removeEventListener("online", handleOnline);
|
|
521
|
+
}, []);
|
|
522
|
+
const labelOf = useMemo(
|
|
523
|
+
() => createDocumentTypeLabelResolver(documentTypes),
|
|
524
|
+
[documentTypes]
|
|
525
|
+
);
|
|
526
|
+
const docTypes = useMemo(
|
|
527
|
+
() => documentTypes ?? Object.entries(DOCUMENT_TYPE_LABELS).map(([id, display_name]) => ({ id, display_name })),
|
|
528
|
+
[documentTypes]
|
|
529
|
+
);
|
|
530
|
+
const value = useMemo(
|
|
531
|
+
() => ({ bid, patientId, store, ready: true, labelOf, documentTypes: docTypes }),
|
|
532
|
+
[bid, patientId, store, labelOf, docTypes]
|
|
533
|
+
);
|
|
534
|
+
return /* @__PURE__ */ jsx2(SdkContext.Provider, { value, children });
|
|
535
|
+
}
|
|
536
|
+
function SdkProvider({ config, bid, patientId, documentTypes, children }) {
|
|
537
|
+
if (!bid || !patientId) return /* @__PURE__ */ jsx2(RecordsPlaceholder, {});
|
|
538
|
+
return /* @__PURE__ */ jsx2(SdkProviderInner, { config, bid, patientId, documentTypes, children });
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
// src/connection/useSdk.ts
|
|
542
|
+
import { useContext } from "react";
|
|
543
|
+
function useSdk() {
|
|
544
|
+
const ctx = useContext(SdkContext);
|
|
545
|
+
if (!ctx) {
|
|
546
|
+
throw new Error("useSdk must be used within <SdkProvider>");
|
|
547
|
+
}
|
|
548
|
+
return ctx;
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// src/views/RecordsView/RecordsView.tsx
|
|
552
|
+
import { TriangleAlert, RefreshCcw as RefreshCcw2, Upload as Upload3 } from "lucide-react";
|
|
553
|
+
|
|
554
|
+
// src/components/icons/FilteredEmptyIcon.tsx
|
|
555
|
+
import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
556
|
+
function FilteredEmptyIcon({ size = 96 }) {
|
|
557
|
+
return /* @__PURE__ */ jsxs3(
|
|
558
|
+
"svg",
|
|
559
|
+
{
|
|
560
|
+
width: size,
|
|
561
|
+
height: size,
|
|
562
|
+
viewBox: "0 0 96 96",
|
|
563
|
+
fill: "none",
|
|
564
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
565
|
+
"aria-hidden": true,
|
|
566
|
+
children: [
|
|
567
|
+
/* @__PURE__ */ jsx3("rect", { width: "96", height: "96", rx: "22.08", fill: "#E8F0FF" }),
|
|
568
|
+
/* @__PURE__ */ jsx3(
|
|
569
|
+
"rect",
|
|
570
|
+
{
|
|
571
|
+
x: "15.36",
|
|
572
|
+
y: "19.68",
|
|
573
|
+
width: "57.6",
|
|
574
|
+
height: "50.88",
|
|
575
|
+
rx: "4.32",
|
|
576
|
+
fill: "white",
|
|
577
|
+
style: { filter: "drop-shadow(0px 1px 3px rgba(0,0,0,0.10))" }
|
|
578
|
+
}
|
|
579
|
+
),
|
|
580
|
+
/* @__PURE__ */ jsx3(
|
|
581
|
+
"rect",
|
|
582
|
+
{
|
|
583
|
+
x: "24",
|
|
584
|
+
y: "12.48",
|
|
585
|
+
width: "57.6",
|
|
586
|
+
height: "50.88",
|
|
587
|
+
rx: "4.32",
|
|
588
|
+
fill: "white",
|
|
589
|
+
style: { filter: "drop-shadow(0px 1px 3px rgba(0,0,0,0.10))" }
|
|
590
|
+
}
|
|
591
|
+
),
|
|
592
|
+
/* @__PURE__ */ jsx3("rect", { x: "33.6", y: "30.72", width: "19.2", height: "2.4", rx: "1.2", fill: "#93B8DA" }),
|
|
593
|
+
/* @__PURE__ */ jsx3("rect", { x: "33.6", y: "36.48", width: "28.8", height: "2.4", rx: "1.2", fill: "#BDD1E8" }),
|
|
594
|
+
/* @__PURE__ */ jsx3("rect", { x: "33.6", y: "42.24", width: "24", height: "2.4", rx: "1.2", fill: "#BDD1E8" }),
|
|
595
|
+
/* @__PURE__ */ jsx3("rect", { x: "33.6", y: "48", width: "16.8", height: "2.4", rx: "1.2", fill: "#DDE9F5" }),
|
|
596
|
+
/* @__PURE__ */ jsx3("circle", { cx: "67.2", cy: "66.24", r: "12.96", fill: "#2563EB" }),
|
|
597
|
+
/* @__PURE__ */ jsx3("line", { x1: "61", y1: "62.5", x2: "73", y2: "62.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
598
|
+
/* @__PURE__ */ jsx3("line", { x1: "63", y1: "66.5", x2: "71", y2: "66.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" }),
|
|
599
|
+
/* @__PURE__ */ jsx3("line", { x1: "65", y1: "70.5", x2: "69", y2: "70.5", stroke: "white", strokeWidth: "1.5", strokeLinecap: "round" })
|
|
600
|
+
]
|
|
601
|
+
}
|
|
602
|
+
);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
// src/components/Skeleton/Skeleton.tsx
|
|
606
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
607
|
+
function Skeleton({ variant, width, height, className }) {
|
|
608
|
+
const classes = ["mr-skeleton", `mr-skeleton--${variant}`, className].filter(Boolean).join(" ");
|
|
609
|
+
return /* @__PURE__ */ jsx4("div", { className: classes, style: { width, height } });
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/components/DeleteConfirmModal/DeleteConfirmModal.tsx
|
|
613
|
+
import { useEffect as useEffect2 } from "react";
|
|
614
|
+
import { createPortal } from "react-dom";
|
|
615
|
+
import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
616
|
+
function DeleteConfirmModal({
|
|
617
|
+
recordLabel,
|
|
618
|
+
patientName,
|
|
619
|
+
deleting,
|
|
620
|
+
onConfirm,
|
|
621
|
+
onCancel
|
|
622
|
+
}) {
|
|
623
|
+
useEffect2(() => {
|
|
624
|
+
const onKey = (e) => {
|
|
625
|
+
if (e.key === "Escape") onCancel();
|
|
626
|
+
};
|
|
627
|
+
document.addEventListener("keydown", onKey);
|
|
628
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
629
|
+
}, [onCancel]);
|
|
630
|
+
if (typeof document === "undefined") return null;
|
|
631
|
+
return createPortal(
|
|
632
|
+
/* @__PURE__ */ jsx5("div", { className: "mr-delete-modal", role: "presentation", onClick: onCancel, children: /* @__PURE__ */ jsxs4(
|
|
633
|
+
"div",
|
|
634
|
+
{
|
|
635
|
+
className: "mr-delete-modal__dialog",
|
|
636
|
+
role: "alertdialog",
|
|
637
|
+
"aria-modal": "true",
|
|
638
|
+
"aria-label": "Delete this record?",
|
|
639
|
+
onClick: (e) => e.stopPropagation(),
|
|
640
|
+
children: [
|
|
641
|
+
/* @__PURE__ */ jsxs4("div", { className: "mr-delete-modal__content", children: [
|
|
642
|
+
/* @__PURE__ */ jsx5("p", { className: "mr-delete-modal__title", children: "Delete this record?" }),
|
|
643
|
+
/* @__PURE__ */ jsxs4("p", { className: "mr-delete-modal__desc", children: [
|
|
644
|
+
/* @__PURE__ */ jsx5("strong", { children: recordLabel }),
|
|
645
|
+
" will be permanently removed from ",
|
|
646
|
+
patientName ? /* @__PURE__ */ jsxs4("strong", { children: [
|
|
647
|
+
patientName,
|
|
648
|
+
"\u2019s"
|
|
649
|
+
] }) : "these",
|
|
650
|
+
" records. This action cannot be undone."
|
|
651
|
+
] })
|
|
652
|
+
] }),
|
|
653
|
+
/* @__PURE__ */ jsxs4("div", { className: "mr-delete-modal__footer", children: [
|
|
654
|
+
/* @__PURE__ */ jsx5(
|
|
655
|
+
"button",
|
|
656
|
+
{
|
|
657
|
+
type: "button",
|
|
658
|
+
className: "mr-delete-modal__cancel",
|
|
659
|
+
disabled: deleting,
|
|
660
|
+
onClick: onCancel,
|
|
661
|
+
children: "Cancel"
|
|
662
|
+
}
|
|
663
|
+
),
|
|
664
|
+
/* @__PURE__ */ jsx5(
|
|
665
|
+
"button",
|
|
666
|
+
{
|
|
667
|
+
type: "button",
|
|
668
|
+
className: "mr-delete-modal__delete",
|
|
669
|
+
disabled: deleting,
|
|
670
|
+
onClick: onConfirm,
|
|
671
|
+
children: deleting ? "Deleting\u2026" : "Delete"
|
|
672
|
+
}
|
|
673
|
+
)
|
|
674
|
+
] })
|
|
675
|
+
]
|
|
676
|
+
}
|
|
677
|
+
) }),
|
|
678
|
+
document.body
|
|
679
|
+
);
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// src/helpers/formatters.ts
|
|
683
|
+
var KB = 1024;
|
|
684
|
+
var MB = KB * 1024;
|
|
685
|
+
var GB = MB * 1024;
|
|
686
|
+
function formatFileSize(bytes) {
|
|
687
|
+
if (bytes < KB) return `${bytes} B`;
|
|
688
|
+
if (bytes < MB) return `${(bytes / KB).toFixed(1)} KB`;
|
|
689
|
+
if (bytes < GB) return `${(bytes / MB).toFixed(1)} MB`;
|
|
690
|
+
return `${(bytes / GB).toFixed(1)} GB`;
|
|
691
|
+
}
|
|
692
|
+
function epochToDisplay(epochMs) {
|
|
693
|
+
return new Date(epochMs).toLocaleDateString(void 0, {
|
|
694
|
+
day: "numeric",
|
|
695
|
+
month: "short",
|
|
696
|
+
year: "numeric"
|
|
697
|
+
});
|
|
698
|
+
}
|
|
699
|
+
function relativeTime(epochMs, now = Date.now()) {
|
|
700
|
+
const diff = now - epochMs;
|
|
701
|
+
const sec = Math.round(diff / 1e3);
|
|
702
|
+
const min = Math.round(sec / 60);
|
|
703
|
+
const hr = Math.round(min / 60);
|
|
704
|
+
const day = Math.round(hr / 24);
|
|
705
|
+
if (sec < 60) return "just now";
|
|
706
|
+
if (min < 60) return `${min}m ago`;
|
|
707
|
+
if (hr < 24) return `${hr}h ago`;
|
|
708
|
+
if (day < 30) return `${day}d ago`;
|
|
709
|
+
return epochToDisplay(epochMs);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
// src/views/RecordsView/RecordsToolbar.tsx
|
|
713
|
+
import { useCallback as useCallback5, useEffect as useEffect10, useMemo as useMemo6, useRef as useRef8, useState as useState8 } from "react";
|
|
714
|
+
import { useStore as useStore7 } from "zustand";
|
|
715
|
+
import {
|
|
716
|
+
ChevronLeft,
|
|
717
|
+
ChevronRight,
|
|
718
|
+
Filter,
|
|
719
|
+
LayoutGrid,
|
|
720
|
+
List,
|
|
721
|
+
RefreshCcw,
|
|
722
|
+
SquareCheck,
|
|
723
|
+
Upload
|
|
724
|
+
} from "lucide-react";
|
|
725
|
+
|
|
726
|
+
// src/components/FilterChip/FilterChip.tsx
|
|
727
|
+
import { memo } from "react";
|
|
728
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
729
|
+
var FilterChip = memo(function FilterChip2({
|
|
730
|
+
id,
|
|
731
|
+
label,
|
|
732
|
+
count,
|
|
733
|
+
active,
|
|
734
|
+
onSelect
|
|
735
|
+
}) {
|
|
736
|
+
return /* @__PURE__ */ jsx6(
|
|
737
|
+
"button",
|
|
738
|
+
{
|
|
739
|
+
type: "button",
|
|
740
|
+
className: `mr-filter-chip${active ? " mr-filter-chip--active" : ""}`,
|
|
741
|
+
"aria-pressed": active,
|
|
742
|
+
onClick: () => onSelect(id),
|
|
743
|
+
children: count == null ? label : `${label} (${count})`
|
|
744
|
+
}
|
|
745
|
+
);
|
|
746
|
+
});
|
|
747
|
+
|
|
748
|
+
// src/components/Tooltip/Tooltip.tsx
|
|
749
|
+
import { useRef, useState } from "react";
|
|
750
|
+
import { createPortal as createPortal2 } from "react-dom";
|
|
751
|
+
import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
752
|
+
function Tooltip({ content, children }) {
|
|
753
|
+
const triggerRef = useRef(null);
|
|
754
|
+
const [coords, setCoords] = useState(null);
|
|
755
|
+
const show = () => {
|
|
756
|
+
const el = triggerRef.current;
|
|
757
|
+
if (!el) return;
|
|
758
|
+
const r = el.getBoundingClientRect();
|
|
759
|
+
setCoords({ top: r.bottom, left: r.left + r.width / 2 });
|
|
760
|
+
};
|
|
761
|
+
const hide = () => setCoords(null);
|
|
762
|
+
return /* @__PURE__ */ jsxs5(
|
|
763
|
+
"span",
|
|
764
|
+
{
|
|
765
|
+
ref: triggerRef,
|
|
766
|
+
className: "mr-tooltip",
|
|
767
|
+
tabIndex: 0,
|
|
768
|
+
onMouseEnter: show,
|
|
769
|
+
onMouseLeave: hide,
|
|
770
|
+
onFocus: show,
|
|
771
|
+
onBlur: hide,
|
|
772
|
+
children: [
|
|
773
|
+
children,
|
|
774
|
+
coords !== null && typeof document !== "undefined" && createPortal2(
|
|
775
|
+
/* @__PURE__ */ jsx7(
|
|
776
|
+
"span",
|
|
777
|
+
{
|
|
778
|
+
className: "mr-tooltip__bubble",
|
|
779
|
+
role: "tooltip",
|
|
780
|
+
style: { top: coords.top, left: coords.left },
|
|
781
|
+
children: content
|
|
782
|
+
}
|
|
783
|
+
),
|
|
784
|
+
document.body
|
|
785
|
+
)
|
|
786
|
+
]
|
|
787
|
+
}
|
|
788
|
+
);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
// src/views/RecordsView/FilterPopover.tsx
|
|
792
|
+
import { useMemo as useMemo5, useState as useState7 } from "react";
|
|
793
|
+
import { useStore as useStore6 } from "zustand";
|
|
794
|
+
|
|
795
|
+
// src/components/PresetSelect/PresetSelect.tsx
|
|
796
|
+
import { useEffect as useEffect3, useRef as useRef2, useState as useState2 } from "react";
|
|
797
|
+
import { createPortal as createPortal3 } from "react-dom";
|
|
798
|
+
import { ChevronsUpDown, Check } from "lucide-react";
|
|
799
|
+
import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
800
|
+
var MENU_MAX_H = 240;
|
|
801
|
+
function PresetSelect({
|
|
802
|
+
value,
|
|
803
|
+
options,
|
|
804
|
+
onChange,
|
|
805
|
+
active,
|
|
806
|
+
placeholder
|
|
807
|
+
}) {
|
|
808
|
+
const [menu, setMenu] = useState2(null);
|
|
809
|
+
const fieldRef = useRef2(null);
|
|
810
|
+
const menuRef = useRef2(null);
|
|
811
|
+
const open = menu !== null;
|
|
812
|
+
const selected = options.find((o) => o.value === value);
|
|
813
|
+
const place = () => {
|
|
814
|
+
const el = fieldRef.current;
|
|
815
|
+
if (!el) return;
|
|
816
|
+
const r = el.getBoundingClientRect();
|
|
817
|
+
const margin = 8;
|
|
818
|
+
const spaceBelow = window.innerHeight - (r.bottom + 4) - margin;
|
|
819
|
+
setMenu({
|
|
820
|
+
left: r.left,
|
|
821
|
+
width: r.width,
|
|
822
|
+
top: r.bottom + 4,
|
|
823
|
+
maxH: Math.min(MENU_MAX_H, spaceBelow)
|
|
824
|
+
});
|
|
825
|
+
};
|
|
826
|
+
useEffect3(() => {
|
|
827
|
+
if (!open) return;
|
|
828
|
+
const onDown = (e) => {
|
|
829
|
+
const n = e.target;
|
|
830
|
+
if (fieldRef.current?.contains(n) || menuRef.current?.contains(n)) return;
|
|
831
|
+
setMenu(null);
|
|
832
|
+
};
|
|
833
|
+
const onScroll = (e) => {
|
|
834
|
+
if (menuRef.current && menuRef.current.contains(e.target)) return;
|
|
835
|
+
place();
|
|
836
|
+
};
|
|
837
|
+
const onResize = () => setMenu(null);
|
|
838
|
+
document.addEventListener("mousedown", onDown);
|
|
839
|
+
window.addEventListener("scroll", onScroll, true);
|
|
840
|
+
window.addEventListener("resize", onResize);
|
|
841
|
+
return () => {
|
|
842
|
+
document.removeEventListener("mousedown", onDown);
|
|
843
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
844
|
+
window.removeEventListener("resize", onResize);
|
|
845
|
+
};
|
|
846
|
+
}, [open]);
|
|
847
|
+
return /* @__PURE__ */ jsxs6("div", { className: "mr-preset-select", children: [
|
|
848
|
+
/* @__PURE__ */ jsxs6(
|
|
849
|
+
"button",
|
|
850
|
+
{
|
|
851
|
+
ref: fieldRef,
|
|
852
|
+
type: "button",
|
|
853
|
+
className: `mr-preset-select__field${active ? " mr-preset-select__field--active" : ""}`,
|
|
854
|
+
"aria-haspopup": "listbox",
|
|
855
|
+
"aria-expanded": open,
|
|
856
|
+
onClick: () => open ? setMenu(null) : place(),
|
|
857
|
+
children: [
|
|
858
|
+
/* @__PURE__ */ jsx8(
|
|
859
|
+
"span",
|
|
860
|
+
{
|
|
861
|
+
className: `mr-preset-select__value${selected ? "" : " mr-preset-select__value--placeholder"}`,
|
|
862
|
+
children: selected?.label ?? placeholder ?? ""
|
|
863
|
+
}
|
|
864
|
+
),
|
|
865
|
+
/* @__PURE__ */ jsx8(ChevronsUpDown, { size: 16, "aria-hidden": true, className: "mr-preset-select__chevron" })
|
|
866
|
+
]
|
|
867
|
+
}
|
|
868
|
+
),
|
|
869
|
+
open && typeof document !== "undefined" && createPortal3(
|
|
870
|
+
/* @__PURE__ */ jsx8(
|
|
871
|
+
"ul",
|
|
872
|
+
{
|
|
873
|
+
ref: menuRef,
|
|
874
|
+
className: "mr-preset-select__menu",
|
|
875
|
+
role: "listbox",
|
|
876
|
+
"data-mr-portal": true,
|
|
877
|
+
style: {
|
|
878
|
+
left: menu.left,
|
|
879
|
+
width: menu.width,
|
|
880
|
+
top: menu.top,
|
|
881
|
+
bottom: menu.bottom,
|
|
882
|
+
maxHeight: menu.maxH
|
|
883
|
+
},
|
|
884
|
+
children: options.map((o) => /* @__PURE__ */ jsx8("li", { children: /* @__PURE__ */ jsxs6(
|
|
885
|
+
"button",
|
|
886
|
+
{
|
|
887
|
+
type: "button",
|
|
888
|
+
role: "option",
|
|
889
|
+
"aria-selected": o.value === value,
|
|
890
|
+
className: `mr-preset-select__option${o.value === value ? " mr-preset-select__option--active" : ""}`,
|
|
891
|
+
onClick: () => {
|
|
892
|
+
onChange(o.value);
|
|
893
|
+
setMenu(null);
|
|
894
|
+
},
|
|
895
|
+
children: [
|
|
896
|
+
/* @__PURE__ */ jsx8("span", { children: o.label }),
|
|
897
|
+
o.value === value && /* @__PURE__ */ jsx8(Check, { size: 14, "aria-hidden": true })
|
|
898
|
+
]
|
|
899
|
+
}
|
|
900
|
+
) }, o.value))
|
|
901
|
+
}
|
|
902
|
+
),
|
|
903
|
+
document.body
|
|
904
|
+
)
|
|
905
|
+
] });
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// src/components/MultiSelect/MultiSelect.tsx
|
|
909
|
+
import { useEffect as useEffect4, useMemo as useMemo2, useRef as useRef3, useState as useState3 } from "react";
|
|
910
|
+
import { createPortal as createPortal4 } from "react-dom";
|
|
911
|
+
import { ChevronsUpDown as ChevronsUpDown2, Check as Check2, Plus, X, Search } from "lucide-react";
|
|
912
|
+
import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
913
|
+
function MultiSelect({
|
|
914
|
+
value,
|
|
915
|
+
options,
|
|
916
|
+
onChange,
|
|
917
|
+
placeholder = "Select",
|
|
918
|
+
searchPlaceholder = "Search\u2026",
|
|
919
|
+
allowCreate = false,
|
|
920
|
+
validate,
|
|
921
|
+
max
|
|
922
|
+
}) {
|
|
923
|
+
const [query, setQuery] = useState3("");
|
|
924
|
+
const [menu, setMenu] = useState3(null);
|
|
925
|
+
const fieldRef = useRef3(null);
|
|
926
|
+
const menuRef = useRef3(null);
|
|
927
|
+
const open = menu !== null;
|
|
928
|
+
const MENU_MAX_H2 = 260;
|
|
929
|
+
const place = () => {
|
|
930
|
+
const el = fieldRef.current;
|
|
931
|
+
if (!el) return;
|
|
932
|
+
const r = el.getBoundingClientRect();
|
|
933
|
+
const margin = 8;
|
|
934
|
+
const spaceBelow = window.innerHeight - (r.bottom + 4) - margin;
|
|
935
|
+
setMenu({
|
|
936
|
+
left: r.left,
|
|
937
|
+
width: r.width,
|
|
938
|
+
top: r.bottom + 4,
|
|
939
|
+
maxH: Math.min(MENU_MAX_H2, spaceBelow)
|
|
940
|
+
});
|
|
941
|
+
};
|
|
942
|
+
useEffect4(() => {
|
|
943
|
+
if (!open) return;
|
|
944
|
+
const onDown = (e) => {
|
|
945
|
+
const n = e.target;
|
|
946
|
+
if (fieldRef.current?.contains(n) || menuRef.current?.contains(n)) return;
|
|
947
|
+
setMenu(null);
|
|
948
|
+
};
|
|
949
|
+
const onScroll = (e) => {
|
|
950
|
+
if (menuRef.current && menuRef.current.contains(e.target)) return;
|
|
951
|
+
place();
|
|
952
|
+
};
|
|
953
|
+
const onResize = () => setMenu(null);
|
|
954
|
+
document.addEventListener("mousedown", onDown);
|
|
955
|
+
window.addEventListener("scroll", onScroll, true);
|
|
956
|
+
window.addEventListener("resize", onResize);
|
|
957
|
+
return () => {
|
|
958
|
+
document.removeEventListener("mousedown", onDown);
|
|
959
|
+
window.removeEventListener("scroll", onScroll, true);
|
|
960
|
+
window.removeEventListener("resize", onResize);
|
|
961
|
+
};
|
|
962
|
+
}, [open]);
|
|
963
|
+
useEffect4(() => {
|
|
964
|
+
if (!open) setQuery("");
|
|
965
|
+
}, [open]);
|
|
966
|
+
const atMax = max != null && value.length >= max;
|
|
967
|
+
const toggle = (v) => {
|
|
968
|
+
if (value.includes(v)) onChange(value.filter((x) => x !== v));
|
|
969
|
+
else if (!atMax) onChange([...value, v]);
|
|
970
|
+
};
|
|
971
|
+
const q = query.trim();
|
|
972
|
+
const filtered = useMemo2(() => {
|
|
973
|
+
const ql = q.toLowerCase();
|
|
974
|
+
return ql ? options.filter((o) => o.toLowerCase().includes(ql)) : options;
|
|
975
|
+
}, [options, q]);
|
|
976
|
+
const canCreate = allowCreate && q.length > 0 && !options.some((o) => o.toLowerCase() === q.toLowerCase()) && !value.some((v) => v.toLowerCase() === q.toLowerCase()) && (!validate || validate(q)) && !atMax;
|
|
977
|
+
const create = () => {
|
|
978
|
+
onChange([...value, q]);
|
|
979
|
+
setQuery("");
|
|
980
|
+
};
|
|
981
|
+
return /* @__PURE__ */ jsxs7("div", { className: "mr-multi-select", children: [
|
|
982
|
+
/* @__PURE__ */ jsxs7(
|
|
983
|
+
"button",
|
|
984
|
+
{
|
|
985
|
+
ref: fieldRef,
|
|
986
|
+
type: "button",
|
|
987
|
+
className: `mr-multi-select__field${value.length ? " mr-multi-select__field--active" : ""}`,
|
|
988
|
+
"aria-haspopup": "listbox",
|
|
989
|
+
"aria-expanded": open,
|
|
990
|
+
onClick: () => open ? setMenu(null) : place(),
|
|
991
|
+
children: [
|
|
992
|
+
/* @__PURE__ */ jsx9(Search, { size: 14, "aria-hidden": true, className: "mr-multi-select__field-search-icon" }),
|
|
993
|
+
/* @__PURE__ */ jsx9(
|
|
994
|
+
"span",
|
|
995
|
+
{
|
|
996
|
+
className: `mr-multi-select__value${value.length ? "" : " mr-multi-select__value--placeholder"}`,
|
|
997
|
+
children: value.length === 0 ? placeholder : `${value.length} ${value.length === 1 ? "tag" : "tags"} selected`
|
|
998
|
+
}
|
|
999
|
+
),
|
|
1000
|
+
/* @__PURE__ */ jsx9(ChevronsUpDown2, { size: 16, "aria-hidden": true, className: "mr-multi-select__chevron" })
|
|
1001
|
+
]
|
|
1002
|
+
}
|
|
1003
|
+
),
|
|
1004
|
+
value.length > 0 && /* @__PURE__ */ jsx9("div", { className: "mr-multi-select__selected", children: value.map((v) => /* @__PURE__ */ jsxs7("span", { className: "mr-multi-select__chip", children: [
|
|
1005
|
+
/* @__PURE__ */ jsx9("span", { className: "mr-multi-select__chip-label", children: v }),
|
|
1006
|
+
/* @__PURE__ */ jsx9(
|
|
1007
|
+
"button",
|
|
1008
|
+
{
|
|
1009
|
+
type: "button",
|
|
1010
|
+
"aria-label": `Remove ${v}`,
|
|
1011
|
+
className: "mr-multi-select__chip-x",
|
|
1012
|
+
onClick: () => onChange(value.filter((x) => x !== v)),
|
|
1013
|
+
children: /* @__PURE__ */ jsx9(X, { size: 11, "aria-hidden": true })
|
|
1014
|
+
}
|
|
1015
|
+
)
|
|
1016
|
+
] }, v)) }),
|
|
1017
|
+
open && typeof document !== "undefined" && createPortal4(
|
|
1018
|
+
/* @__PURE__ */ jsxs7(
|
|
1019
|
+
"div",
|
|
1020
|
+
{
|
|
1021
|
+
ref: menuRef,
|
|
1022
|
+
className: "mr-multi-select__menu",
|
|
1023
|
+
role: "listbox",
|
|
1024
|
+
"aria-multiselectable": true,
|
|
1025
|
+
"data-mr-portal": true,
|
|
1026
|
+
style: {
|
|
1027
|
+
left: menu.left,
|
|
1028
|
+
width: menu.width,
|
|
1029
|
+
top: menu.top,
|
|
1030
|
+
bottom: menu.bottom,
|
|
1031
|
+
maxHeight: menu.maxH
|
|
1032
|
+
},
|
|
1033
|
+
children: [
|
|
1034
|
+
/* @__PURE__ */ jsx9("div", { className: "mr-multi-select__search", children: /* @__PURE__ */ jsx9(
|
|
1035
|
+
"input",
|
|
1036
|
+
{
|
|
1037
|
+
type: "text",
|
|
1038
|
+
className: "mr-multi-select__search-input",
|
|
1039
|
+
placeholder: searchPlaceholder,
|
|
1040
|
+
value: query,
|
|
1041
|
+
autoFocus: true,
|
|
1042
|
+
onChange: (e) => setQuery(e.target.value),
|
|
1043
|
+
onKeyDown: (e) => {
|
|
1044
|
+
if (e.key === "Enter" && canCreate) {
|
|
1045
|
+
e.preventDefault();
|
|
1046
|
+
create();
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
) }),
|
|
1051
|
+
/* @__PURE__ */ jsxs7("ul", { className: "mr-multi-select__options", children: [
|
|
1052
|
+
filtered.map((o) => {
|
|
1053
|
+
const selected = value.includes(o);
|
|
1054
|
+
return /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs7(
|
|
1055
|
+
"button",
|
|
1056
|
+
{
|
|
1057
|
+
type: "button",
|
|
1058
|
+
role: "option",
|
|
1059
|
+
"aria-selected": selected,
|
|
1060
|
+
className: `mr-multi-select__option${selected ? " mr-multi-select__option--active" : ""}`,
|
|
1061
|
+
disabled: !selected && atMax,
|
|
1062
|
+
onClick: () => toggle(o),
|
|
1063
|
+
children: [
|
|
1064
|
+
/* @__PURE__ */ jsx9("span", { className: "mr-multi-select__option-label", children: o }),
|
|
1065
|
+
selected && /* @__PURE__ */ jsx9(Check2, { size: 14, "aria-hidden": true })
|
|
1066
|
+
]
|
|
1067
|
+
}
|
|
1068
|
+
) }, o);
|
|
1069
|
+
}),
|
|
1070
|
+
canCreate && /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs7(
|
|
1071
|
+
"button",
|
|
1072
|
+
{
|
|
1073
|
+
type: "button",
|
|
1074
|
+
className: "mr-multi-select__option mr-multi-select__create",
|
|
1075
|
+
onClick: create,
|
|
1076
|
+
children: [
|
|
1077
|
+
/* @__PURE__ */ jsx9(Plus, { size: 14, "aria-hidden": true }),
|
|
1078
|
+
"Add \u201C",
|
|
1079
|
+
q,
|
|
1080
|
+
"\u201D"
|
|
1081
|
+
]
|
|
1082
|
+
}
|
|
1083
|
+
) }),
|
|
1084
|
+
filtered.length === 0 && !canCreate && /* @__PURE__ */ jsx9("li", { className: "mr-multi-select__empty text-center", children: "No data" })
|
|
1085
|
+
] })
|
|
1086
|
+
]
|
|
1087
|
+
}
|
|
1088
|
+
),
|
|
1089
|
+
document.body
|
|
1090
|
+
)
|
|
1091
|
+
] });
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// src/connection/useRecordsConnection.ts
|
|
1095
|
+
import { useCallback, useEffect as useEffect5, useRef as useRef4, useState as useState4 } from "react";
|
|
1096
|
+
|
|
1097
|
+
// src/helpers/mappings.ts
|
|
1098
|
+
var defaultLabelOf = createDocumentTypeLabelResolver();
|
|
1099
|
+
var toMs = (epochSeconds) => epochSeconds ? epochSeconds * 1e3 : 0;
|
|
1100
|
+
function documentItemToUi(doc, labelOf = defaultLabelOf) {
|
|
1101
|
+
const meta = doc.metadata ?? {};
|
|
1102
|
+
const typeCode = doc.document_type ?? doc.file_type ?? "";
|
|
1103
|
+
const created = toMs(meta.document_date ?? doc.upload_date);
|
|
1104
|
+
const typeLabel = labelOf(typeCode) || "Untitled";
|
|
1105
|
+
return {
|
|
1106
|
+
id: doc.document_id,
|
|
1107
|
+
patientId: doc.patient_id,
|
|
1108
|
+
title: typeLabel,
|
|
1109
|
+
typeCode,
|
|
1110
|
+
type: typeLabel,
|
|
1111
|
+
thumbnailUrl: meta.thumbnail ?? null,
|
|
1112
|
+
createdAtEpoch: created,
|
|
1113
|
+
updatedAtEpoch: toMs(doc.upload_date) || created,
|
|
1114
|
+
tags: meta.tags ?? [],
|
|
1115
|
+
cases: doc.cases ?? [],
|
|
1116
|
+
syncState: doc.sync_state ?? null,
|
|
1117
|
+
fileType: doc.file_type ?? null,
|
|
1118
|
+
isSmart: doc.is_smart ?? false,
|
|
1119
|
+
isAnalysing: doc.is_analyzing ?? false
|
|
1120
|
+
};
|
|
1121
|
+
}
|
|
1122
|
+
function caseItemToUi(raw) {
|
|
1123
|
+
const item = raw.item ?? {};
|
|
1124
|
+
const created = toMs(item.created_at);
|
|
1125
|
+
return {
|
|
1126
|
+
id: raw.id,
|
|
1127
|
+
name: item.display_name ?? "Untitled case",
|
|
1128
|
+
typeCode: item.type ?? "",
|
|
1129
|
+
createdAtEpoch: created,
|
|
1130
|
+
updatedAtEpoch: toMs(raw.updated_at) || created,
|
|
1131
|
+
occurredAtEpoch: item.occurred_at ? toMs(item.occurred_at) : null
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
function fileToQueueItem(localId, file) {
|
|
1135
|
+
return {
|
|
1136
|
+
id: localId,
|
|
1137
|
+
fileName: file.name,
|
|
1138
|
+
mimeType: file.type,
|
|
1139
|
+
sizeBytes: file.size,
|
|
1140
|
+
progress: 0,
|
|
1141
|
+
status: "pending"
|
|
1142
|
+
};
|
|
1143
|
+
}
|
|
1144
|
+
|
|
1145
|
+
// src/connection/useRecordsConnection.ts
|
|
1146
|
+
var LIMIT = 100;
|
|
1147
|
+
function useRecordsConnection() {
|
|
1148
|
+
const { bid, patientId, store, labelOf } = useSdk();
|
|
1149
|
+
const [sourceRefreshedAt, setSourceRefreshedAt] = useState4(
|
|
1150
|
+
() => getCore().sourceRefreshedAt
|
|
1151
|
+
);
|
|
1152
|
+
const loadedKeyRef = useRef4(null);
|
|
1153
|
+
const applyItems = useCallback(
|
|
1154
|
+
(items) => {
|
|
1155
|
+
store.getState().records.setAll(items.map((d) => documentItemToUi(d, labelOf)));
|
|
1156
|
+
},
|
|
1157
|
+
[store, labelOf]
|
|
1158
|
+
);
|
|
1159
|
+
const load = useCallback(async () => {
|
|
1160
|
+
const records = store.getState().records;
|
|
1161
|
+
records.setStatus("loading");
|
|
1162
|
+
try {
|
|
1163
|
+
const fresh = await getCore().listDocuments({
|
|
1164
|
+
bid,
|
|
1165
|
+
patientId,
|
|
1166
|
+
limit: LIMIT,
|
|
1167
|
+
preferenceType: "HTML",
|
|
1168
|
+
onStale: (cached) => {
|
|
1169
|
+
applyItems(cached);
|
|
1170
|
+
store.getState().records.setStatus("stale");
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
applyItems(fresh);
|
|
1174
|
+
records.setStatus("fresh");
|
|
1175
|
+
} catch (e) {
|
|
1176
|
+
records.setError(e instanceof Error ? e.message : "Failed to load records");
|
|
1177
|
+
}
|
|
1178
|
+
}, [bid, patientId, store, applyItems]);
|
|
1179
|
+
useEffect5(() => {
|
|
1180
|
+
const key = `${bid}::${patientId}`;
|
|
1181
|
+
if (loadedKeyRef.current === key) return;
|
|
1182
|
+
loadedKeyRef.current = key;
|
|
1183
|
+
void load();
|
|
1184
|
+
}, [bid, patientId, load]);
|
|
1185
|
+
useEffect5(() => {
|
|
1186
|
+
if (loadedKeyRef.current !== `${bid}::${patientId}`) return;
|
|
1187
|
+
void getCore().listLocalDocuments({ bid, patientId, limit: LIMIT }).then(applyItems);
|
|
1188
|
+
}, [bid, patientId, labelOf, applyItems]);
|
|
1189
|
+
useEffect5(() => {
|
|
1190
|
+
const unsubscribe = getCore().subscribe("records:changed", () => {
|
|
1191
|
+
void getCore().listLocalDocuments({ bid, patientId, limit: LIMIT }).then(applyItems);
|
|
1192
|
+
});
|
|
1193
|
+
return unsubscribe;
|
|
1194
|
+
}, [bid, patientId, applyItems]);
|
|
1195
|
+
const editRecord = useCallback(
|
|
1196
|
+
async (documentId, data) => {
|
|
1197
|
+
await getCore().editRecord({ documentId, data, bid, patientId });
|
|
1198
|
+
},
|
|
1199
|
+
[bid, patientId]
|
|
1200
|
+
);
|
|
1201
|
+
const deleteRecord = useCallback(
|
|
1202
|
+
async (documentId) => {
|
|
1203
|
+
const records = store.getState().records;
|
|
1204
|
+
records.markPending(documentId);
|
|
1205
|
+
try {
|
|
1206
|
+
await getCore().deleteRecord({ documentId, bid, patientId });
|
|
1207
|
+
records.remove(documentId);
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
records.unmarkPending(documentId);
|
|
1210
|
+
throw e;
|
|
1211
|
+
}
|
|
1212
|
+
},
|
|
1213
|
+
[bid, patientId, store]
|
|
1214
|
+
);
|
|
1215
|
+
const refresh = useCallback(async () => {
|
|
1216
|
+
store.getState().records.setStatus("loading");
|
|
1217
|
+
try {
|
|
1218
|
+
const fresh = await getCore().refreshDocumentSource({ bid, patientId, preferenceType: "HTML" });
|
|
1219
|
+
if (fresh.length > 0) applyItems(fresh);
|
|
1220
|
+
setSourceRefreshedAt(getCore().sourceRefreshedAt);
|
|
1221
|
+
store.getState().records.setStatus("fresh");
|
|
1222
|
+
} catch (e) {
|
|
1223
|
+
store.getState().records.setError(e instanceof Error ? e.message : "Failed to refresh");
|
|
1224
|
+
}
|
|
1225
|
+
}, [bid, patientId, store, applyItems]);
|
|
1226
|
+
return { refresh, sourceRefreshedAt, editRecord, deleteRecord };
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
// src/connection/useRecordDetail.ts
|
|
1230
|
+
import { useEffect as useEffect6 } from "react";
|
|
1231
|
+
import { useStore } from "zustand";
|
|
1232
|
+
|
|
1233
|
+
// src/connection/useAllRecordTags.ts
|
|
1234
|
+
import { useEffect as useEffect7, useState as useState5 } from "react";
|
|
1235
|
+
import { useStore as useStore2 } from "zustand";
|
|
1236
|
+
|
|
1237
|
+
// src/connection/useRecordPreview.ts
|
|
1238
|
+
import { useEffect as useEffect8, useRef as useRef5, useState as useState6 } from "react";
|
|
1239
|
+
|
|
1240
|
+
// src/helpers/smartReport.ts
|
|
1241
|
+
var str = (o, keys) => {
|
|
1242
|
+
for (const k of keys) {
|
|
1243
|
+
const v = o[k];
|
|
1244
|
+
if (typeof v === "string" && v.trim()) return v.trim();
|
|
1245
|
+
if (typeof v === "number") return String(v);
|
|
1246
|
+
}
|
|
1247
|
+
return "";
|
|
1248
|
+
};
|
|
1249
|
+
var normalizeStatus = (raw) => {
|
|
1250
|
+
const s = raw.toLowerCase();
|
|
1251
|
+
if (s.includes("high") || s === "h" || s.includes("above") || s === "abnormal_high") return "high";
|
|
1252
|
+
if (s.includes("low") || s === "l" || s.includes("below") || s === "abnormal_low") return "low";
|
|
1253
|
+
if (s.includes("normal") || s.includes("in range") || s === "n" || s === "ok") return "normal";
|
|
1254
|
+
return "unknown";
|
|
1255
|
+
};
|
|
1256
|
+
var deriveStatusFromRange = (value, refRange) => {
|
|
1257
|
+
const num = parseFloat(value.replace(/,/g, ""));
|
|
1258
|
+
if (Number.isNaN(num) || !refRange) return "unknown";
|
|
1259
|
+
const r = refRange.toLowerCase().replace(/,/g, "");
|
|
1260
|
+
const between = r.match(/(-?\d+\.?\d*)\s*(?:-|–|to)\s*(-?\d+\.?\d*)/);
|
|
1261
|
+
if (between) {
|
|
1262
|
+
const lo = parseFloat(between[1]);
|
|
1263
|
+
const hi = parseFloat(between[2]);
|
|
1264
|
+
if (num < lo) return "low";
|
|
1265
|
+
if (num > hi) return "high";
|
|
1266
|
+
return "normal";
|
|
1267
|
+
}
|
|
1268
|
+
const upper = r.match(/(?:<=?|up to|below)\s*(-?\d+\.?\d*)/);
|
|
1269
|
+
if (upper) return num > parseFloat(upper[1]) ? "high" : "normal";
|
|
1270
|
+
const lower = r.match(/(?:>=?|above)\s*(-?\d+\.?\d*)/);
|
|
1271
|
+
if (lower) return num < parseFloat(lower[1]) ? "low" : "normal";
|
|
1272
|
+
return "unknown";
|
|
1273
|
+
};
|
|
1274
|
+
function parseHistory(field) {
|
|
1275
|
+
const raw = field.history ?? field.previous ?? field.trend ?? field.historical;
|
|
1276
|
+
if (!Array.isArray(raw)) return [];
|
|
1277
|
+
return raw.map((p) => {
|
|
1278
|
+
if (p == null || typeof p !== "object") return null;
|
|
1279
|
+
const o = p;
|
|
1280
|
+
const value = str(o, ["value", "result", "val", "reading"]);
|
|
1281
|
+
const label = str(o, ["date", "label", "when", "at"]);
|
|
1282
|
+
if (!value) return null;
|
|
1283
|
+
return { value, label: label || "" };
|
|
1284
|
+
}).filter((p) => p !== null);
|
|
1285
|
+
}
|
|
1286
|
+
function parseVitals(report) {
|
|
1287
|
+
const fields = [...report.verified ?? [], ...report.unverified ?? []];
|
|
1288
|
+
return fields.map((field, i) => {
|
|
1289
|
+
const name = str(field, ["name", "label", "parameter", "key", "title", "test"]);
|
|
1290
|
+
const value = str(field, ["value", "result", "val", "reading"]);
|
|
1291
|
+
if (!name && !value) return null;
|
|
1292
|
+
const refRange = str(field, ["range", "ref_range", "reference", "refRange", "normal_range"]);
|
|
1293
|
+
let status = normalizeStatus(str(field, ["status", "flag", "interpretation", "severity"]));
|
|
1294
|
+
if (status === "unknown") status = deriveStatusFromRange(value, refRange);
|
|
1295
|
+
return {
|
|
1296
|
+
id: str(field, ["id", "code"]) || `${name || "vital"}-${i}`,
|
|
1297
|
+
name: name || "Unknown",
|
|
1298
|
+
value,
|
|
1299
|
+
unit: str(field, ["unit", "units"]),
|
|
1300
|
+
refRange,
|
|
1301
|
+
status,
|
|
1302
|
+
history: parseHistory(field)
|
|
1303
|
+
};
|
|
1304
|
+
}).filter((v) => v !== null);
|
|
1305
|
+
}
|
|
1306
|
+
var isOutOfRange = (v) => v.status === "high" || v.status === "low";
|
|
1307
|
+
function vitalsNoteHeading(opts) {
|
|
1308
|
+
return `**Vitals / Lab parameters \u2014 ${opts?.reportName ?? "Report"}${opts?.date ? ` (${opts.date})` : ""}:**`;
|
|
1309
|
+
}
|
|
1310
|
+
function vitalsToNoteText(vitals, opts) {
|
|
1311
|
+
const lines = vitals.map((v) => {
|
|
1312
|
+
const val = [v.value, v.unit].filter(Boolean).join(" ");
|
|
1313
|
+
return val ? `${v.name}: ${val}` : v.name;
|
|
1314
|
+
});
|
|
1315
|
+
return [vitalsNoteHeading(opts), ...lines].join("\n");
|
|
1316
|
+
}
|
|
1317
|
+
|
|
1318
|
+
// src/connection/useRecordPreview.ts
|
|
1319
|
+
function classifyFile(rawType) {
|
|
1320
|
+
const t = (rawType ?? "").toLowerCase();
|
|
1321
|
+
if (t.includes("pdf")) return "pdf";
|
|
1322
|
+
if (t.includes("image") || t === "img" || /(png|jpe?g|gif|webp|heic)/.test(t)) return "image";
|
|
1323
|
+
return "text";
|
|
1324
|
+
}
|
|
1325
|
+
var EMPTY = {
|
|
1326
|
+
status: "loading",
|
|
1327
|
+
files: [],
|
|
1328
|
+
vitals: [],
|
|
1329
|
+
hasSmartReport: false
|
|
1330
|
+
};
|
|
1331
|
+
function useRecordPreview(documentId) {
|
|
1332
|
+
const { bid, patientId } = useSdk();
|
|
1333
|
+
const [data, setData] = useState6(EMPTY);
|
|
1334
|
+
const inflightRef = useRef5(null);
|
|
1335
|
+
useEffect8(() => {
|
|
1336
|
+
if (!documentId) {
|
|
1337
|
+
setData(EMPTY);
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
if (inflightRef.current === documentId) return;
|
|
1341
|
+
inflightRef.current = documentId;
|
|
1342
|
+
let cancelled = false;
|
|
1343
|
+
setData(EMPTY);
|
|
1344
|
+
(async () => {
|
|
1345
|
+
try {
|
|
1346
|
+
const res = await getCore().describeDocument({ documentId, bid, patientId, preferenceType: "HTML" });
|
|
1347
|
+
if (cancelled) return;
|
|
1348
|
+
const files = (res.files ?? []).filter((f) => f.asset_url).map((f) => ({ url: f.asset_url, kind: classifyFile(f.file_type) }));
|
|
1349
|
+
const vitals = res.smart_report ? parseVitals(res.smart_report) : [];
|
|
1350
|
+
setData({
|
|
1351
|
+
status: "loaded",
|
|
1352
|
+
files,
|
|
1353
|
+
vitals,
|
|
1354
|
+
hasSmartReport: res.smart_report != null
|
|
1355
|
+
});
|
|
1356
|
+
} catch {
|
|
1357
|
+
if (!cancelled) setData({ status: "error", files: [], vitals: [], hasSmartReport: false });
|
|
1358
|
+
}
|
|
1359
|
+
})();
|
|
1360
|
+
return () => {
|
|
1361
|
+
cancelled = true;
|
|
1362
|
+
inflightRef.current = null;
|
|
1363
|
+
};
|
|
1364
|
+
}, [documentId, bid, patientId]);
|
|
1365
|
+
return data;
|
|
1366
|
+
}
|
|
1367
|
+
|
|
1368
|
+
// src/connection/useCasesConnection.ts
|
|
1369
|
+
import { useCallback as useCallback2, useEffect as useEffect9, useRef as useRef6 } from "react";
|
|
1370
|
+
function useCasesConnection(enabled = true) {
|
|
1371
|
+
const { bid, patientId, store } = useSdk();
|
|
1372
|
+
const loadedKeyRef = useRef6(null);
|
|
1373
|
+
const applyItems = useCallback2(
|
|
1374
|
+
(items) => {
|
|
1375
|
+
store.getState().cases.setAll(items.map(caseItemToUi));
|
|
1376
|
+
},
|
|
1377
|
+
[store]
|
|
1378
|
+
);
|
|
1379
|
+
const load = useCallback2(async () => {
|
|
1380
|
+
const cases = store.getState().cases;
|
|
1381
|
+
cases.setStatus("loading");
|
|
1382
|
+
try {
|
|
1383
|
+
const fresh = await getCore().listCases({
|
|
1384
|
+
bid,
|
|
1385
|
+
patientId,
|
|
1386
|
+
onStale: (cached) => {
|
|
1387
|
+
applyItems(cached);
|
|
1388
|
+
store.getState().cases.setStatus("stale");
|
|
1389
|
+
}
|
|
1390
|
+
});
|
|
1391
|
+
applyItems(fresh);
|
|
1392
|
+
cases.setStatus("fresh");
|
|
1393
|
+
} catch (e) {
|
|
1394
|
+
cases.setError(e instanceof Error ? e.message : "Failed to load cases");
|
|
1395
|
+
}
|
|
1396
|
+
}, [bid, patientId, store, applyItems]);
|
|
1397
|
+
useEffect9(() => {
|
|
1398
|
+
if (!enabled) return;
|
|
1399
|
+
const key = `${bid}::${patientId}`;
|
|
1400
|
+
if (loadedKeyRef.current === key) return;
|
|
1401
|
+
loadedKeyRef.current = key;
|
|
1402
|
+
void load();
|
|
1403
|
+
}, [enabled, bid, patientId, load]);
|
|
1404
|
+
useEffect9(() => {
|
|
1405
|
+
if (!enabled) return;
|
|
1406
|
+
const unsubscribe = getCore().subscribe("cases:changed", () => {
|
|
1407
|
+
void getCore().listLocalCases({ bid, patientId }).then(applyItems);
|
|
1408
|
+
});
|
|
1409
|
+
return unsubscribe;
|
|
1410
|
+
}, [enabled, bid, patientId, applyItems]);
|
|
1411
|
+
const createCase = useCallback2(
|
|
1412
|
+
async (data) => {
|
|
1413
|
+
const id = data.id ?? crypto.randomUUID();
|
|
1414
|
+
const res = await getCore().createCase({ data: { ...data, id }, bid, patientId });
|
|
1415
|
+
return res.id;
|
|
1416
|
+
},
|
|
1417
|
+
[bid, patientId]
|
|
1418
|
+
);
|
|
1419
|
+
const updateCase = useCallback2(
|
|
1420
|
+
async (caseId, data) => {
|
|
1421
|
+
await getCore().updateCase({ caseId, data, bid, patientId });
|
|
1422
|
+
},
|
|
1423
|
+
[bid, patientId]
|
|
1424
|
+
);
|
|
1425
|
+
const deleteCase = useCallback2(
|
|
1426
|
+
async (caseId) => {
|
|
1427
|
+
await getCore().deleteCase({ caseId, bid, patientId });
|
|
1428
|
+
store.getState().cases.remove(caseId);
|
|
1429
|
+
},
|
|
1430
|
+
[bid, patientId, store]
|
|
1431
|
+
);
|
|
1432
|
+
return { refresh: load, createCase, updateCase, deleteCase };
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
// src/connection/useUploadConnection.ts
|
|
1436
|
+
import { useCallback as useCallback3, useRef as useRef7 } from "react";
|
|
1437
|
+
function resolveContentType(file) {
|
|
1438
|
+
const t = file.type.toLowerCase();
|
|
1439
|
+
if (t === "image/jpeg" || t === "image/jpg" || t === "image/png" || t === "application/pdf") {
|
|
1440
|
+
return t;
|
|
1441
|
+
}
|
|
1442
|
+
const ext = file.name.split(".").pop()?.toLowerCase();
|
|
1443
|
+
if (ext === "pdf") return "application/pdf";
|
|
1444
|
+
if (ext === "png") return "image/png";
|
|
1445
|
+
if (ext === "jpg" || ext === "jpeg") return "image/jpeg";
|
|
1446
|
+
return "application/pdf";
|
|
1447
|
+
}
|
|
1448
|
+
function useUploadConnection() {
|
|
1449
|
+
const { bid, patientId, store } = useSdk();
|
|
1450
|
+
const seq = useRef7(0);
|
|
1451
|
+
const upload = useCallback3(
|
|
1452
|
+
async (items) => {
|
|
1453
|
+
if (items.length === 0) return;
|
|
1454
|
+
const localIds = items.map(({ file }) => {
|
|
1455
|
+
const id = `upload-${seq.current += 1}-${file.name}`;
|
|
1456
|
+
store.getState().uploadQueue.add(fileToQueueItem(id, file));
|
|
1457
|
+
return id;
|
|
1458
|
+
});
|
|
1459
|
+
const batchRequests = items.map((it) => ({
|
|
1460
|
+
dt: it.documentType,
|
|
1461
|
+
dd_e: Math.floor(it.documentDateMs / 1e3),
|
|
1462
|
+
// epoch seconds
|
|
1463
|
+
...it.tags && it.tags.length ? { tg: it.tags } : {},
|
|
1464
|
+
...it.caseIds && it.caseIds.length ? { cases: it.caseIds } : {},
|
|
1465
|
+
files: [
|
|
1466
|
+
{
|
|
1467
|
+
contentType: resolveContentType(it.file),
|
|
1468
|
+
file_size: it.file.size
|
|
1469
|
+
}
|
|
1470
|
+
]
|
|
1471
|
+
}));
|
|
1472
|
+
localIds.forEach((id) => store.getState().uploadQueue.updateProgress(id, 0));
|
|
1473
|
+
try {
|
|
1474
|
+
const res = await getCore().addRecord({
|
|
1475
|
+
batchRequests,
|
|
1476
|
+
files: items.map((it) => [it.file]),
|
|
1477
|
+
filenames: items.map((it) => [it.file.name]),
|
|
1478
|
+
bid,
|
|
1479
|
+
patientId
|
|
1480
|
+
});
|
|
1481
|
+
const queue = store.getState().uploadQueue;
|
|
1482
|
+
if (res.message === "queued_offline" || !res.batch_response?.length) {
|
|
1483
|
+
throw new Error("No internet connection. Your upload will retry automatically when you're back online.");
|
|
1484
|
+
}
|
|
1485
|
+
localIds.forEach((id, i) => {
|
|
1486
|
+
const documentId = res.batch_response?.[i]?.document_id ?? "";
|
|
1487
|
+
const errorDetails = res.batch_response?.[i]?.error_details;
|
|
1488
|
+
if (errorDetails) {
|
|
1489
|
+
queue.markFailed(id);
|
|
1490
|
+
} else {
|
|
1491
|
+
console.log("[MR:upload] status \u2192 completed", { localId: id, documentId });
|
|
1492
|
+
queue.markCompleted(id, documentId);
|
|
1493
|
+
}
|
|
1494
|
+
});
|
|
1495
|
+
} catch (e) {
|
|
1496
|
+
const queue = store.getState().uploadQueue;
|
|
1497
|
+
localIds.forEach((id) => {
|
|
1498
|
+
queue.markFailed(id);
|
|
1499
|
+
});
|
|
1500
|
+
throw e;
|
|
1501
|
+
}
|
|
1502
|
+
},
|
|
1503
|
+
[bid, patientId, store]
|
|
1504
|
+
);
|
|
1505
|
+
return { upload };
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
// src/connection/useLogout.ts
|
|
1509
|
+
import { useCallback as useCallback4 } from "react";
|
|
1510
|
+
function useLogout() {
|
|
1511
|
+
return useCallback4(() => {
|
|
1512
|
+
teardownWorkerClient();
|
|
1513
|
+
}, []);
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// src/stores/selectors/recordsSelectors.ts
|
|
1517
|
+
import { useMemo as useMemo3 } from "react";
|
|
1518
|
+
import { useStore as useStore3 } from "zustand";
|
|
1519
|
+
import { useShallow } from "zustand/react/shallow";
|
|
1520
|
+
function useRecordById(store, id) {
|
|
1521
|
+
return useStore3(store, (s) => s.records.byId[id]);
|
|
1522
|
+
}
|
|
1523
|
+
function useRecordIdRange(store, start, end) {
|
|
1524
|
+
return useStore3(store, useShallow((s) => s.records.ids.slice(start, end)));
|
|
1525
|
+
}
|
|
1526
|
+
function useRecordsCount(store) {
|
|
1527
|
+
return useStore3(store, (s) => s.records.ids.length);
|
|
1528
|
+
}
|
|
1529
|
+
function useRecordsStatus(store) {
|
|
1530
|
+
return useStore3(store, (s) => s.records.status);
|
|
1531
|
+
}
|
|
1532
|
+
function useThumbnailUrl(store, id) {
|
|
1533
|
+
return useStore3(store, (s) => s.records.byId[id]?.thumbnailUrl ?? null);
|
|
1534
|
+
}
|
|
1535
|
+
function useIsSelected(store, id) {
|
|
1536
|
+
return useStore3(store, (s) => s.selection.recordIds.has(id));
|
|
1537
|
+
}
|
|
1538
|
+
function useAllTags(store) {
|
|
1539
|
+
const byId = useStore3(store, (s) => s.records.byId);
|
|
1540
|
+
return useMemo3(() => {
|
|
1541
|
+
const set = /* @__PURE__ */ new Set();
|
|
1542
|
+
for (const id in byId) {
|
|
1543
|
+
for (const t of byId[id].tags) set.add(t);
|
|
1544
|
+
}
|
|
1545
|
+
return [...set].sort((a, b) => a.localeCompare(b));
|
|
1546
|
+
}, [byId]);
|
|
1547
|
+
}
|
|
1548
|
+
|
|
1549
|
+
// src/stores/selectors/casesSelectors.ts
|
|
1550
|
+
import { useStore as useStore4 } from "zustand";
|
|
1551
|
+
import { useShallow as useShallow2 } from "zustand/react/shallow";
|
|
1552
|
+
function useCaseById(store, id) {
|
|
1553
|
+
return useStore4(store, (s) => s.cases.byId[id]);
|
|
1554
|
+
}
|
|
1555
|
+
function useCaseIds(store) {
|
|
1556
|
+
return useStore4(store, useShallow2((s) => s.cases.ids));
|
|
1557
|
+
}
|
|
1558
|
+
function useCasesStatus(store) {
|
|
1559
|
+
return useStore4(store, (s) => s.cases.status);
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
// src/stores/selectors/filteredSelectors.ts
|
|
1563
|
+
import { useMemo as useMemo4 } from "react";
|
|
1564
|
+
import { useStore as useStore5 } from "zustand";
|
|
1565
|
+
|
|
1566
|
+
// src/helpers/recordFilter.ts
|
|
1567
|
+
function recordMatchesFilters(r, filters, { skipType = false } = {}) {
|
|
1568
|
+
if (!skipType && filters.type && r.typeCode !== filters.type) return false;
|
|
1569
|
+
const search = filters.search.trim().toLowerCase();
|
|
1570
|
+
if (search && !r.title.toLowerCase().includes(search)) return false;
|
|
1571
|
+
if (filters.documentDateFrom != null && r.createdAtEpoch < filters.documentDateFrom) return false;
|
|
1572
|
+
if (filters.documentDateTo != null && r.createdAtEpoch > filters.documentDateTo) return false;
|
|
1573
|
+
if (filters.uploadDateFrom != null && r.updatedAtEpoch < filters.uploadDateFrom) return false;
|
|
1574
|
+
if (filters.uploadDateTo != null && r.updatedAtEpoch > filters.uploadDateTo) return false;
|
|
1575
|
+
if (filters.tags.length) {
|
|
1576
|
+
const tagSet = new Set(filters.tags);
|
|
1577
|
+
if (!r.tags.some((t) => tagSet.has(t))) return false;
|
|
1578
|
+
}
|
|
1579
|
+
return true;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
// src/stores/selectors/filteredSelectors.ts
|
|
1583
|
+
function useFilteredRecordIds(store) {
|
|
1584
|
+
const ids = useStore5(store, (s) => s.records.ids);
|
|
1585
|
+
const byId = useStore5(store, (s) => s.records.byId);
|
|
1586
|
+
const filters = useStore5(store, (s) => s.filters);
|
|
1587
|
+
return useMemo4(() => {
|
|
1588
|
+
const filtered = ids.filter((id) => {
|
|
1589
|
+
const r = byId[id];
|
|
1590
|
+
return r ? recordMatchesFilters(r, filters) : false;
|
|
1591
|
+
});
|
|
1592
|
+
const dir = filters.sortDir === "asc" ? 1 : -1;
|
|
1593
|
+
const sorted = [...filtered].sort((a, b) => {
|
|
1594
|
+
const ra = byId[a];
|
|
1595
|
+
const rb = byId[b];
|
|
1596
|
+
if (filters.sortBy === "name") return dir * ra.title.localeCompare(rb.title);
|
|
1597
|
+
return dir * (ra.createdAtEpoch - rb.createdAtEpoch);
|
|
1598
|
+
});
|
|
1599
|
+
return sorted;
|
|
1600
|
+
}, [ids, byId, filters]);
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
// src/connection/useRecordSelectors.ts
|
|
1604
|
+
function useRecordById2(id) {
|
|
1605
|
+
return useRecordById(useSdk().store, id);
|
|
1606
|
+
}
|
|
1607
|
+
function useRecordIdRange2(start, end) {
|
|
1608
|
+
return useRecordIdRange(useSdk().store, start, end);
|
|
1609
|
+
}
|
|
1610
|
+
function useRecordsCount2() {
|
|
1611
|
+
return useRecordsCount(useSdk().store);
|
|
1612
|
+
}
|
|
1613
|
+
function useRecordsStatus2() {
|
|
1614
|
+
return useRecordsStatus(useSdk().store);
|
|
1615
|
+
}
|
|
1616
|
+
function useThumbnailUrl2(id) {
|
|
1617
|
+
return useThumbnailUrl(useSdk().store, id);
|
|
1618
|
+
}
|
|
1619
|
+
function useIsSelected2(id) {
|
|
1620
|
+
return useIsSelected(useSdk().store, id);
|
|
1621
|
+
}
|
|
1622
|
+
function useAllTags2() {
|
|
1623
|
+
return useAllTags(useSdk().store);
|
|
1624
|
+
}
|
|
1625
|
+
function useCaseById2(id) {
|
|
1626
|
+
return useCaseById(useSdk().store, id);
|
|
1627
|
+
}
|
|
1628
|
+
function useCaseIds2() {
|
|
1629
|
+
return useCaseIds(useSdk().store);
|
|
1630
|
+
}
|
|
1631
|
+
function useCasesStatus2() {
|
|
1632
|
+
return useCasesStatus(useSdk().store);
|
|
1633
|
+
}
|
|
1634
|
+
function useFilteredRecordIds2() {
|
|
1635
|
+
return useFilteredRecordIds(useSdk().store);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
// src/views/RecordsView/FilterPopover.tsx
|
|
1639
|
+
import { jsx as jsx10, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1640
|
+
var PRESET_OPTIONS = [
|
|
1641
|
+
{ value: "anytime", label: "Any time" },
|
|
1642
|
+
{ value: "last7", label: "Last 7 days" },
|
|
1643
|
+
{ value: "last30", label: "Last 30 days" },
|
|
1644
|
+
{ value: "last3m", label: "Last 3 months" },
|
|
1645
|
+
{ value: "custom", label: "Custom range" }
|
|
1646
|
+
];
|
|
1647
|
+
var DAY = 24 * 60 * 60 * 1e3;
|
|
1648
|
+
var toInput = (ms) => ms == null ? "" : new Date(ms).toISOString().slice(0, 10);
|
|
1649
|
+
var fromInput = (v, endOfDay = false) => {
|
|
1650
|
+
if (!v) return null;
|
|
1651
|
+
const d = /* @__PURE__ */ new Date(v + (endOfDay ? "T23:59:59.999" : "T00:00:00"));
|
|
1652
|
+
return Number.isNaN(d.getTime()) ? null : d.getTime();
|
|
1653
|
+
};
|
|
1654
|
+
function resolveRange(preset, customFrom, customTo) {
|
|
1655
|
+
const now = Date.now();
|
|
1656
|
+
switch (preset) {
|
|
1657
|
+
case "last7":
|
|
1658
|
+
return { from: now - 7 * DAY, to: now };
|
|
1659
|
+
case "last30":
|
|
1660
|
+
return { from: now - 30 * DAY, to: now };
|
|
1661
|
+
case "last3m":
|
|
1662
|
+
return { from: now - 90 * DAY, to: now };
|
|
1663
|
+
case "custom":
|
|
1664
|
+
return { from: fromInput(customFrom), to: fromInput(customTo, true) };
|
|
1665
|
+
default:
|
|
1666
|
+
return { from: null, to: null };
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
function FilterPopover({ onClose }) {
|
|
1670
|
+
const { store, labelOf } = useSdk();
|
|
1671
|
+
const allTags = useAllTags2();
|
|
1672
|
+
const filters = useStore6(store, (s) => s.filters);
|
|
1673
|
+
const byId = useStore6(store, (s) => s.records.byId);
|
|
1674
|
+
const ids = useStore6(store, (s) => s.records.ids);
|
|
1675
|
+
const typeOptions = useMemo5(() => {
|
|
1676
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1677
|
+
return ids.map((id) => byId[id]?.typeCode).filter((code) => !!code && !seen.has(code) && !!seen.add(code)).map((code) => ({ value: code, label: labelOf(code) }));
|
|
1678
|
+
}, [ids, byId, labelOf]);
|
|
1679
|
+
const [docType, setDocType] = useState7(filters.type ?? "");
|
|
1680
|
+
const [docPreset, setDocPreset] = useState7(filters.documentDatePreset);
|
|
1681
|
+
const [docFrom, setDocFrom] = useState7(toInput(filters.documentDateFrom));
|
|
1682
|
+
const [docTo, setDocTo] = useState7(toInput(filters.documentDateTo));
|
|
1683
|
+
const [upPreset, setUpPreset] = useState7(filters.uploadDatePreset);
|
|
1684
|
+
const [upFrom, setUpFrom] = useState7(toInput(filters.uploadDateFrom));
|
|
1685
|
+
const [upTo, setUpTo] = useState7(toInput(filters.uploadDateTo));
|
|
1686
|
+
const [tags, setTags] = useState7(filters.tags);
|
|
1687
|
+
const handleClear = () => {
|
|
1688
|
+
setDocType("");
|
|
1689
|
+
setDocPreset("anytime");
|
|
1690
|
+
setDocFrom("");
|
|
1691
|
+
setDocTo("");
|
|
1692
|
+
setUpPreset("anytime");
|
|
1693
|
+
setUpFrom("");
|
|
1694
|
+
setUpTo("");
|
|
1695
|
+
setTags([]);
|
|
1696
|
+
store.getState().filters.setType(null);
|
|
1697
|
+
store.getState().filters.clearPopoverFilters();
|
|
1698
|
+
onClose();
|
|
1699
|
+
};
|
|
1700
|
+
const handleApply = () => {
|
|
1701
|
+
store.getState().filters.setType(docType || null);
|
|
1702
|
+
const doc = resolveRange(docPreset, docFrom, docTo);
|
|
1703
|
+
const up = resolveRange(upPreset, upFrom, upTo);
|
|
1704
|
+
store.getState().filters.applyPopoverFilters({
|
|
1705
|
+
documentDateFrom: doc.from,
|
|
1706
|
+
documentDateTo: doc.to,
|
|
1707
|
+
uploadDateFrom: up.from,
|
|
1708
|
+
uploadDateTo: up.to,
|
|
1709
|
+
documentDatePreset: docPreset,
|
|
1710
|
+
uploadDatePreset: upPreset,
|
|
1711
|
+
tags
|
|
1712
|
+
});
|
|
1713
|
+
onClose();
|
|
1714
|
+
};
|
|
1715
|
+
return /* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover", role: "dialog", "aria-label": "Filters", children: [
|
|
1716
|
+
/* @__PURE__ */ jsx10("p", { className: "mr-filter-popover__title", children: "Filters" }),
|
|
1717
|
+
/* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__body", children: [
|
|
1718
|
+
typeOptions.length > 0 && /* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__group", children: [
|
|
1719
|
+
/* @__PURE__ */ jsx10("p", { className: "mr-filter-popover__label", children: "Document type" }),
|
|
1720
|
+
/* @__PURE__ */ jsx10(
|
|
1721
|
+
PresetSelect,
|
|
1722
|
+
{
|
|
1723
|
+
value: docType,
|
|
1724
|
+
options: [{ value: "", label: "All types" }, ...typeOptions],
|
|
1725
|
+
onChange: (v) => setDocType(v),
|
|
1726
|
+
active: !!docType,
|
|
1727
|
+
placeholder: "All types"
|
|
1728
|
+
}
|
|
1729
|
+
)
|
|
1730
|
+
] }),
|
|
1731
|
+
/* @__PURE__ */ jsx10(
|
|
1732
|
+
PresetDateRange,
|
|
1733
|
+
{
|
|
1734
|
+
label: "Document date",
|
|
1735
|
+
preset: docPreset,
|
|
1736
|
+
from: docFrom,
|
|
1737
|
+
to: docTo,
|
|
1738
|
+
onPreset: setDocPreset,
|
|
1739
|
+
onFrom: setDocFrom,
|
|
1740
|
+
onTo: setDocTo
|
|
1741
|
+
}
|
|
1742
|
+
),
|
|
1743
|
+
/* @__PURE__ */ jsx10(
|
|
1744
|
+
PresetDateRange,
|
|
1745
|
+
{
|
|
1746
|
+
label: "Upload date",
|
|
1747
|
+
preset: upPreset,
|
|
1748
|
+
from: upFrom,
|
|
1749
|
+
to: upTo,
|
|
1750
|
+
onPreset: setUpPreset,
|
|
1751
|
+
onFrom: setUpFrom,
|
|
1752
|
+
onTo: setUpTo
|
|
1753
|
+
}
|
|
1754
|
+
),
|
|
1755
|
+
/* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__group", children: [
|
|
1756
|
+
/* @__PURE__ */ jsx10("p", { className: "mr-filter-popover__label", children: "Tags" }),
|
|
1757
|
+
/* @__PURE__ */ jsx10(
|
|
1758
|
+
MultiSelect,
|
|
1759
|
+
{
|
|
1760
|
+
value: tags,
|
|
1761
|
+
options: allTags ?? [],
|
|
1762
|
+
onChange: setTags,
|
|
1763
|
+
placeholder: "Search or select tags"
|
|
1764
|
+
}
|
|
1765
|
+
)
|
|
1766
|
+
] })
|
|
1767
|
+
] }),
|
|
1768
|
+
/* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__cta", children: [
|
|
1769
|
+
/* @__PURE__ */ jsx10("button", { type: "button", className: "mr-filter-popover__clear", onClick: handleClear, children: "Clear filters" }),
|
|
1770
|
+
/* @__PURE__ */ jsx10("button", { type: "button", className: "mr-filter-popover__apply", onClick: handleApply, children: "Apply filters" })
|
|
1771
|
+
] })
|
|
1772
|
+
] });
|
|
1773
|
+
}
|
|
1774
|
+
function PresetDateRange({
|
|
1775
|
+
label,
|
|
1776
|
+
preset,
|
|
1777
|
+
from,
|
|
1778
|
+
to,
|
|
1779
|
+
onPreset,
|
|
1780
|
+
onFrom,
|
|
1781
|
+
onTo
|
|
1782
|
+
}) {
|
|
1783
|
+
return /* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__group", children: [
|
|
1784
|
+
/* @__PURE__ */ jsx10("p", { className: "mr-filter-popover__label", children: label }),
|
|
1785
|
+
/* @__PURE__ */ jsx10(
|
|
1786
|
+
PresetSelect,
|
|
1787
|
+
{
|
|
1788
|
+
value: preset,
|
|
1789
|
+
options: PRESET_OPTIONS,
|
|
1790
|
+
onChange: onPreset,
|
|
1791
|
+
active: preset !== "anytime"
|
|
1792
|
+
}
|
|
1793
|
+
),
|
|
1794
|
+
preset === "custom" && /* @__PURE__ */ jsxs8("div", { className: "mr-filter-popover__range", children: [
|
|
1795
|
+
/* @__PURE__ */ jsx10(
|
|
1796
|
+
"input",
|
|
1797
|
+
{
|
|
1798
|
+
type: "date",
|
|
1799
|
+
className: "mr-filter-popover__date",
|
|
1800
|
+
value: from,
|
|
1801
|
+
max: to || void 0,
|
|
1802
|
+
onChange: (e) => onFrom(e.target.value)
|
|
1803
|
+
}
|
|
1804
|
+
),
|
|
1805
|
+
/* @__PURE__ */ jsx10("span", { className: "mr-filter-popover__to", children: "to" }),
|
|
1806
|
+
/* @__PURE__ */ jsx10(
|
|
1807
|
+
"input",
|
|
1808
|
+
{
|
|
1809
|
+
type: "date",
|
|
1810
|
+
className: "mr-filter-popover__date",
|
|
1811
|
+
value: to,
|
|
1812
|
+
min: from || void 0,
|
|
1813
|
+
onChange: (e) => onTo(e.target.value)
|
|
1814
|
+
}
|
|
1815
|
+
)
|
|
1816
|
+
] })
|
|
1817
|
+
] });
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
// src/views/RecordsView/RecordsToolbar.tsx
|
|
1821
|
+
import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1822
|
+
var ALL = "__all__";
|
|
1823
|
+
function RecordsToolbar({
|
|
1824
|
+
viewMode,
|
|
1825
|
+
onViewModeChange,
|
|
1826
|
+
onUpload,
|
|
1827
|
+
onRefresh,
|
|
1828
|
+
sourceRefreshedAt,
|
|
1829
|
+
onFilter,
|
|
1830
|
+
onToggleSelect,
|
|
1831
|
+
selectionMode
|
|
1832
|
+
}) {
|
|
1833
|
+
const { store, labelOf } = useSdk();
|
|
1834
|
+
const byId = useStore7(store, (s) => s.records.byId);
|
|
1835
|
+
const ids = useStore7(store, (s) => s.records.ids);
|
|
1836
|
+
const filteredIds = useFilteredRecordIds2();
|
|
1837
|
+
const filters = useStore7(store, (s) => s.filters);
|
|
1838
|
+
const activeType = filters.type;
|
|
1839
|
+
const activeFilterCount = useStore7(store, (s) => {
|
|
1840
|
+
const f = s.filters;
|
|
1841
|
+
const docDate = f.documentDateFrom != null || f.documentDateTo != null ? 1 : 0;
|
|
1842
|
+
const upDate = f.uploadDateFrom != null || f.uploadDateTo != null ? 1 : 0;
|
|
1843
|
+
return docDate + upDate + f.tags.length;
|
|
1844
|
+
});
|
|
1845
|
+
const scrollRef = useRef8(null);
|
|
1846
|
+
const [filterOpen, setFilterOpen] = useState8(false);
|
|
1847
|
+
const filterRef = useRef8(null);
|
|
1848
|
+
useEffect10(() => {
|
|
1849
|
+
if (!filterOpen) return;
|
|
1850
|
+
const onDown = (e) => {
|
|
1851
|
+
const t = e.target;
|
|
1852
|
+
if (t.closest?.("[data-mr-portal]")) return;
|
|
1853
|
+
if (filterRef.current && !filterRef.current.contains(t)) setFilterOpen(false);
|
|
1854
|
+
};
|
|
1855
|
+
document.addEventListener("mousedown", onDown);
|
|
1856
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
1857
|
+
}, [filterOpen]);
|
|
1858
|
+
const [isRefreshing, setIsRefreshing] = useState8(false);
|
|
1859
|
+
const [, setNow] = useState8(0);
|
|
1860
|
+
useEffect10(() => {
|
|
1861
|
+
const t = setInterval(() => setNow((n) => n + 1), 3e4);
|
|
1862
|
+
return () => clearInterval(t);
|
|
1863
|
+
}, []);
|
|
1864
|
+
const handleRefresh = useCallback5(async () => {
|
|
1865
|
+
if (isRefreshing) return;
|
|
1866
|
+
setIsRefreshing(true);
|
|
1867
|
+
try {
|
|
1868
|
+
await onRefresh?.();
|
|
1869
|
+
} finally {
|
|
1870
|
+
setIsRefreshing(false);
|
|
1871
|
+
}
|
|
1872
|
+
}, [isRefreshing, onRefresh]);
|
|
1873
|
+
const lastSyncedLabel = sourceRefreshedAt != null ? relativeTime(sourceRefreshedAt) : null;
|
|
1874
|
+
const typeChips = useMemo6(() => {
|
|
1875
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1876
|
+
for (const id of ids) {
|
|
1877
|
+
const r = byId[id];
|
|
1878
|
+
if (!r) continue;
|
|
1879
|
+
if (!counts.has(r.typeCode)) counts.set(r.typeCode, 0);
|
|
1880
|
+
if (recordMatchesFilters(r, filters, { skipType: true })) {
|
|
1881
|
+
counts.set(r.typeCode, (counts.get(r.typeCode) ?? 0) + 1);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
return [...counts.entries()].map(([code, count]) => ({
|
|
1885
|
+
code,
|
|
1886
|
+
label: labelOf(code),
|
|
1887
|
+
count
|
|
1888
|
+
}));
|
|
1889
|
+
}, [ids, byId, labelOf, filters]);
|
|
1890
|
+
const selectType = (id) => {
|
|
1891
|
+
store.getState().filters.setType(id === ALL ? null : id);
|
|
1892
|
+
};
|
|
1893
|
+
const scrollBy = (delta) => {
|
|
1894
|
+
scrollRef.current?.scrollBy({ left: delta, behavior: "smooth" });
|
|
1895
|
+
};
|
|
1896
|
+
return /* @__PURE__ */ jsxs9("div", { className: "mr-records-toolbar", children: [
|
|
1897
|
+
/* @__PURE__ */ jsxs9("div", { className: "mr-toolbar-filter", ref: filterRef, children: [
|
|
1898
|
+
/* @__PURE__ */ jsx11(Tooltip, { content: "Filter", children: /* @__PURE__ */ jsxs9(
|
|
1899
|
+
"button",
|
|
1900
|
+
{
|
|
1901
|
+
type: "button",
|
|
1902
|
+
className: `mr-toolbar-icon-btn${filterOpen ? " mr-toolbar-icon-btn--active" : ""}`,
|
|
1903
|
+
"aria-label": "Filter",
|
|
1904
|
+
"aria-expanded": filterOpen,
|
|
1905
|
+
onClick: () => {
|
|
1906
|
+
setFilterOpen((o) => !o);
|
|
1907
|
+
onFilter?.();
|
|
1908
|
+
},
|
|
1909
|
+
children: [
|
|
1910
|
+
/* @__PURE__ */ jsx11(Filter, { size: 16, "aria-hidden": true, color: "var(--mr-primary)" }),
|
|
1911
|
+
activeFilterCount > 0 && /* @__PURE__ */ jsx11("span", { className: "mr-toolbar-filter__badge", children: activeFilterCount })
|
|
1912
|
+
]
|
|
1913
|
+
}
|
|
1914
|
+
) }),
|
|
1915
|
+
filterOpen && /* @__PURE__ */ jsx11(FilterPopover, { onClose: () => setFilterOpen(false) })
|
|
1916
|
+
] }),
|
|
1917
|
+
/* @__PURE__ */ jsxs9("div", { className: "mr-toolbar-chiprail", children: [
|
|
1918
|
+
/* @__PURE__ */ jsx11(
|
|
1919
|
+
"button",
|
|
1920
|
+
{
|
|
1921
|
+
type: "button",
|
|
1922
|
+
className: "mr-toolbar-chiprail__chevron",
|
|
1923
|
+
"aria-label": "Scroll filters left",
|
|
1924
|
+
onClick: () => scrollBy(-200),
|
|
1925
|
+
children: /* @__PURE__ */ jsx11(ChevronLeft, { size: 16, "aria-hidden": true })
|
|
1926
|
+
}
|
|
1927
|
+
),
|
|
1928
|
+
/* @__PURE__ */ jsxs9("div", { className: "mr-toolbar-chiprail__scroll", ref: scrollRef, children: [
|
|
1929
|
+
/* @__PURE__ */ jsx11(
|
|
1930
|
+
FilterChip,
|
|
1931
|
+
{
|
|
1932
|
+
id: ALL,
|
|
1933
|
+
label: "All Records",
|
|
1934
|
+
count: filteredIds?.length,
|
|
1935
|
+
active: activeType == null,
|
|
1936
|
+
onSelect: selectType
|
|
1937
|
+
}
|
|
1938
|
+
),
|
|
1939
|
+
typeChips.map(({ code, label, count }) => /* @__PURE__ */ jsx11(
|
|
1940
|
+
FilterChip,
|
|
1941
|
+
{
|
|
1942
|
+
id: code,
|
|
1943
|
+
label,
|
|
1944
|
+
count,
|
|
1945
|
+
active: activeType === code,
|
|
1946
|
+
onSelect: selectType
|
|
1947
|
+
},
|
|
1948
|
+
code
|
|
1949
|
+
))
|
|
1950
|
+
] }),
|
|
1951
|
+
/* @__PURE__ */ jsx11("span", { className: "mr-toolbar-chiprail__fade", "aria-hidden": true }),
|
|
1952
|
+
/* @__PURE__ */ jsx11(
|
|
1953
|
+
"button",
|
|
1954
|
+
{
|
|
1955
|
+
type: "button",
|
|
1956
|
+
className: "mr-toolbar-chiprail__chevron",
|
|
1957
|
+
"aria-label": "Scroll filters right",
|
|
1958
|
+
onClick: () => scrollBy(200),
|
|
1959
|
+
children: /* @__PURE__ */ jsx11(ChevronRight, { size: 16, "aria-hidden": true })
|
|
1960
|
+
}
|
|
1961
|
+
)
|
|
1962
|
+
] }),
|
|
1963
|
+
/* @__PURE__ */ jsxs9("div", { className: "mr-toolbar-toggle", role: "group", "aria-label": "View mode", children: [
|
|
1964
|
+
/* @__PURE__ */ jsx11(Tooltip, { content: "Grid view", children: /* @__PURE__ */ jsx11(
|
|
1965
|
+
"button",
|
|
1966
|
+
{
|
|
1967
|
+
type: "button",
|
|
1968
|
+
className: `mr-toolbar-toggle__btn${viewMode === "grid" ? " mr-toolbar-toggle__btn--active" : ""}`,
|
|
1969
|
+
"aria-label": "Grid view",
|
|
1970
|
+
"aria-pressed": viewMode === "grid",
|
|
1971
|
+
onClick: () => onViewModeChange("grid"),
|
|
1972
|
+
children: /* @__PURE__ */ jsx11(LayoutGrid, { size: 16, "aria-hidden": true })
|
|
1973
|
+
}
|
|
1974
|
+
) }),
|
|
1975
|
+
/* @__PURE__ */ jsx11(Tooltip, { content: "List view", children: /* @__PURE__ */ jsx11(
|
|
1976
|
+
"button",
|
|
1977
|
+
{
|
|
1978
|
+
type: "button",
|
|
1979
|
+
className: `mr-toolbar-toggle__btn${viewMode === "list" ? " mr-toolbar-toggle__btn--active" : ""}`,
|
|
1980
|
+
"aria-label": "List view",
|
|
1981
|
+
"aria-pressed": viewMode === "list",
|
|
1982
|
+
onClick: () => onViewModeChange("list"),
|
|
1983
|
+
children: /* @__PURE__ */ jsx11(List, { size: 16, "aria-hidden": true })
|
|
1984
|
+
}
|
|
1985
|
+
) })
|
|
1986
|
+
] }),
|
|
1987
|
+
/* @__PURE__ */ jsx11("span", { className: "mr-toolbar-divider", "aria-hidden": true }),
|
|
1988
|
+
/* @__PURE__ */ jsx11(Tooltip, { content: "Select multiple records to add to context", children: /* @__PURE__ */ jsx11(
|
|
1989
|
+
"button",
|
|
1990
|
+
{
|
|
1991
|
+
type: "button",
|
|
1992
|
+
className: `mr-toolbar-icon-btn${selectionMode ? " mr-toolbar-icon-btn--active" : ""}`,
|
|
1993
|
+
"aria-label": "Select multiple records to add to context",
|
|
1994
|
+
"aria-pressed": selectionMode,
|
|
1995
|
+
onClick: onToggleSelect,
|
|
1996
|
+
children: /* @__PURE__ */ jsx11(SquareCheck, { size: 16, "aria-hidden": true, color: "var(--mr-primary)" })
|
|
1997
|
+
}
|
|
1998
|
+
) }),
|
|
1999
|
+
/* @__PURE__ */ jsx11(Tooltip, { content: "Refresh", children: /* @__PURE__ */ jsxs9(
|
|
2000
|
+
"button",
|
|
2001
|
+
{
|
|
2002
|
+
type: "button",
|
|
2003
|
+
className: "mr-toolbar-sync",
|
|
2004
|
+
"aria-label": "Refresh",
|
|
2005
|
+
disabled: isRefreshing,
|
|
2006
|
+
onClick: handleRefresh,
|
|
2007
|
+
children: [
|
|
2008
|
+
/* @__PURE__ */ jsx11(
|
|
2009
|
+
RefreshCcw,
|
|
2010
|
+
{
|
|
2011
|
+
size: 16,
|
|
2012
|
+
"aria-hidden": true,
|
|
2013
|
+
className: isRefreshing ? "mr-toolbar-sync__icon--spinning" : void 0
|
|
2014
|
+
}
|
|
2015
|
+
),
|
|
2016
|
+
lastSyncedLabel && /* @__PURE__ */ jsx11("span", { className: "mr-toolbar-sync__label", children: lastSyncedLabel })
|
|
2017
|
+
]
|
|
2018
|
+
}
|
|
2019
|
+
) }),
|
|
2020
|
+
onUpload && /* @__PURE__ */ jsxs9("button", { type: "button", className: "mr-toolbar-upload", onClick: onUpload, children: [
|
|
2021
|
+
/* @__PURE__ */ jsx11(Upload, { size: 16, "aria-hidden": true }),
|
|
2022
|
+
"Upload"
|
|
2023
|
+
] })
|
|
2024
|
+
] });
|
|
2025
|
+
}
|
|
2026
|
+
|
|
2027
|
+
// src/components/SidebarItem/SidebarItem.tsx
|
|
2028
|
+
import { memo as memo2 } from "react";
|
|
2029
|
+
import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
2030
|
+
var SidebarItem = memo2(function SidebarItem2({
|
|
2031
|
+
id,
|
|
2032
|
+
dayNumber,
|
|
2033
|
+
weekday,
|
|
2034
|
+
countLabel,
|
|
2035
|
+
summary,
|
|
2036
|
+
selected,
|
|
2037
|
+
onSelect
|
|
2038
|
+
}) {
|
|
2039
|
+
return /* @__PURE__ */ jsxs10(
|
|
2040
|
+
"button",
|
|
2041
|
+
{
|
|
2042
|
+
type: "button",
|
|
2043
|
+
className: `mr-sidebar-item${selected ? " mr-sidebar-item--selected" : ""}`,
|
|
2044
|
+
"aria-pressed": selected,
|
|
2045
|
+
onClick: () => onSelect(id),
|
|
2046
|
+
children: [
|
|
2047
|
+
/* @__PURE__ */ jsxs10("span", { className: "mr-sidebar-item__date", children: [
|
|
2048
|
+
/* @__PURE__ */ jsx12("span", { className: "mr-sidebar-item__day-num", children: dayNumber }),
|
|
2049
|
+
/* @__PURE__ */ jsx12("span", { className: "mr-sidebar-item__weekday", children: weekday })
|
|
2050
|
+
] }),
|
|
2051
|
+
/* @__PURE__ */ jsxs10("span", { className: "mr-sidebar-item__text", children: [
|
|
2052
|
+
/* @__PURE__ */ jsx12("span", { className: "mr-sidebar-item__count", children: countLabel }),
|
|
2053
|
+
/* @__PURE__ */ jsx12("span", { className: "mr-sidebar-item__summary", children: summary })
|
|
2054
|
+
] }),
|
|
2055
|
+
selected && /* @__PURE__ */ jsx12("span", { className: "mr-sidebar-item__indicator", "aria-hidden": true })
|
|
2056
|
+
]
|
|
2057
|
+
}
|
|
2058
|
+
);
|
|
2059
|
+
});
|
|
2060
|
+
|
|
2061
|
+
// src/views/RecordsView/SidebarPagination.tsx
|
|
2062
|
+
import { ChevronLeft as ChevronLeft2, ChevronRight as ChevronRight2 } from "lucide-react";
|
|
2063
|
+
import { jsx as jsx13, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
2064
|
+
function SidebarPagination({ page, pageCount, onChange }) {
|
|
2065
|
+
if (pageCount <= 1) return null;
|
|
2066
|
+
const goToPage = (val) => {
|
|
2067
|
+
const n = parseInt(val, 10);
|
|
2068
|
+
if (!isNaN(n) && n >= 1 && n <= pageCount) onChange(n - 1);
|
|
2069
|
+
};
|
|
2070
|
+
return /* @__PURE__ */ jsxs11("div", { className: "mr-sidebar-pagination", children: [
|
|
2071
|
+
/* @__PURE__ */ jsx13(
|
|
2072
|
+
"button",
|
|
2073
|
+
{
|
|
2074
|
+
type: "button",
|
|
2075
|
+
className: "mr-sidebar-pagination__btn",
|
|
2076
|
+
"aria-label": "Previous page",
|
|
2077
|
+
disabled: page <= 0,
|
|
2078
|
+
onClick: () => onChange(page - 1),
|
|
2079
|
+
children: /* @__PURE__ */ jsx13(ChevronLeft2, { size: 16, "aria-hidden": true })
|
|
2080
|
+
}
|
|
2081
|
+
),
|
|
2082
|
+
/* @__PURE__ */ jsxs11("div", { className: "mr-sidebar-pagination__jumper", children: [
|
|
2083
|
+
/* @__PURE__ */ jsx13("span", { className: "mr-sidebar-pagination__text", children: "Page" }),
|
|
2084
|
+
/* @__PURE__ */ jsx13(
|
|
2085
|
+
"input",
|
|
2086
|
+
{
|
|
2087
|
+
type: "number",
|
|
2088
|
+
className: "mr-sidebar-pagination__page-box",
|
|
2089
|
+
min: 1,
|
|
2090
|
+
max: pageCount,
|
|
2091
|
+
defaultValue: page + 1,
|
|
2092
|
+
onBlur: (e) => goToPage(e.target.value),
|
|
2093
|
+
onKeyDown: (e) => {
|
|
2094
|
+
if (e.key === "Enter") goToPage(e.target.value);
|
|
2095
|
+
}
|
|
2096
|
+
},
|
|
2097
|
+
page
|
|
2098
|
+
),
|
|
2099
|
+
/* @__PURE__ */ jsxs11("span", { className: "mr-sidebar-pagination__text", children: [
|
|
2100
|
+
"of ",
|
|
2101
|
+
pageCount
|
|
2102
|
+
] })
|
|
2103
|
+
] }),
|
|
2104
|
+
/* @__PURE__ */ jsx13(
|
|
2105
|
+
"button",
|
|
2106
|
+
{
|
|
2107
|
+
type: "button",
|
|
2108
|
+
className: "mr-sidebar-pagination__btn",
|
|
2109
|
+
"aria-label": "Next page",
|
|
2110
|
+
disabled: page >= pageCount - 1,
|
|
2111
|
+
onClick: () => onChange(page + 1),
|
|
2112
|
+
children: /* @__PURE__ */ jsx13(ChevronRight2, { size: 16, "aria-hidden": true })
|
|
2113
|
+
}
|
|
2114
|
+
)
|
|
2115
|
+
] });
|
|
2116
|
+
}
|
|
2117
|
+
|
|
2118
|
+
// src/components/CasePicker/CasePicker.tsx
|
|
2119
|
+
import { useEffect as useEffect11, useMemo as useMemo7, useRef as useRef9, useState as useState9 } from "react";
|
|
2120
|
+
import { createPortal as createPortal5 } from "react-dom";
|
|
2121
|
+
import { Search as Search2, Check as Check3, Plus as Plus2, ChevronDown, X as X2 } from "lucide-react";
|
|
2122
|
+
import { useStore as useStore8 } from "zustand";
|
|
2123
|
+
import { Fragment, jsx as jsx14, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2124
|
+
var CASE_TYPE_OPTIONS = [
|
|
2125
|
+
{ value: "OP", label: "Out-patient" },
|
|
2126
|
+
{ value: "IP", label: "In-patient" },
|
|
2127
|
+
{ value: "EM", label: "Emergency" },
|
|
2128
|
+
{ value: "HH", label: "Home Health" },
|
|
2129
|
+
{ value: "DC", label: "Day Care" }
|
|
2130
|
+
];
|
|
2131
|
+
var todayISO = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2132
|
+
function CasePicker({ selected, onChange, mode = "dropdown" }) {
|
|
2133
|
+
const { store } = useSdk();
|
|
2134
|
+
const { createCase } = useCasesConnection();
|
|
2135
|
+
const caseIds = useStore8(store, (s) => s.cases.ids);
|
|
2136
|
+
const casesById = useStore8(store, (s) => s.cases.byId);
|
|
2137
|
+
const cases = useMemo7(
|
|
2138
|
+
() => caseIds.map((id) => casesById[id]).filter(Boolean),
|
|
2139
|
+
[caseIds, casesById]
|
|
2140
|
+
);
|
|
2141
|
+
const selectedCase = cases.find((c) => c.id === selected) ?? null;
|
|
2142
|
+
const [creating, setCreating] = useState9(false);
|
|
2143
|
+
const [newName, setNewName] = useState9("");
|
|
2144
|
+
const [newType, setNewType] = useState9("OP");
|
|
2145
|
+
const [newDate, setNewDate] = useState9(todayISO());
|
|
2146
|
+
const [saving, setSaving] = useState9(false);
|
|
2147
|
+
const [query, setQuery] = useState9("");
|
|
2148
|
+
const [menuPos, setMenuPos] = useState9(null);
|
|
2149
|
+
const fieldRef = useRef9(null);
|
|
2150
|
+
const menuRef = useRef9(null);
|
|
2151
|
+
const open = menuPos !== null;
|
|
2152
|
+
const filtered = useMemo7(() => {
|
|
2153
|
+
const q = query.trim().toLowerCase();
|
|
2154
|
+
return q ? cases.filter((c) => c.name.toLowerCase().includes(q)) : cases;
|
|
2155
|
+
}, [cases, query]);
|
|
2156
|
+
const place = () => {
|
|
2157
|
+
const el = fieldRef.current;
|
|
2158
|
+
if (!el) return;
|
|
2159
|
+
const r = el.getBoundingClientRect();
|
|
2160
|
+
const spaceBelow = window.innerHeight - r.bottom - 8;
|
|
2161
|
+
const spaceAbove = r.top - 8;
|
|
2162
|
+
if (spaceBelow >= 200 || spaceBelow >= spaceAbove) {
|
|
2163
|
+
setMenuPos({ top: r.bottom + 4, left: r.left, width: r.width, maxH: Math.min(320, spaceBelow) });
|
|
2164
|
+
} else {
|
|
2165
|
+
setMenuPos({ bottom: window.innerHeight - r.top + 4, left: r.left, width: r.width, maxH: Math.min(320, spaceAbove) });
|
|
2166
|
+
}
|
|
2167
|
+
};
|
|
2168
|
+
useEffect11(() => {
|
|
2169
|
+
if (!open) {
|
|
2170
|
+
setQuery("");
|
|
2171
|
+
setCreating(false);
|
|
2172
|
+
setNewName("");
|
|
2173
|
+
return;
|
|
2174
|
+
}
|
|
2175
|
+
const onDown = (e) => {
|
|
2176
|
+
const t = e.target;
|
|
2177
|
+
if (fieldRef.current?.contains(t) || menuRef.current?.contains(t)) return;
|
|
2178
|
+
if (t.closest?.("[data-mr-portal]")) return;
|
|
2179
|
+
setMenuPos(null);
|
|
2180
|
+
};
|
|
2181
|
+
const onResize = () => setMenuPos(null);
|
|
2182
|
+
document.addEventListener("mousedown", onDown);
|
|
2183
|
+
window.addEventListener("resize", onResize);
|
|
2184
|
+
return () => {
|
|
2185
|
+
document.removeEventListener("mousedown", onDown);
|
|
2186
|
+
window.removeEventListener("resize", onResize);
|
|
2187
|
+
};
|
|
2188
|
+
}, [open]);
|
|
2189
|
+
const handleCreate = async () => {
|
|
2190
|
+
const name = newName.trim();
|
|
2191
|
+
if (!name) return;
|
|
2192
|
+
setSaving(true);
|
|
2193
|
+
try {
|
|
2194
|
+
const occurred_at = newDate ? Math.floor((/* @__PURE__ */ new Date(newDate + "T00:00:00")).getTime() / 1e3) : void 0;
|
|
2195
|
+
const id = await createCase({ display_name: name, type: newType, occurred_at });
|
|
2196
|
+
onChange(id);
|
|
2197
|
+
setCreating(false);
|
|
2198
|
+
setNewName("");
|
|
2199
|
+
setNewType("OP");
|
|
2200
|
+
setNewDate(todayISO());
|
|
2201
|
+
if (mode === "dropdown") setMenuPos(null);
|
|
2202
|
+
} finally {
|
|
2203
|
+
setSaving(false);
|
|
2204
|
+
}
|
|
2205
|
+
};
|
|
2206
|
+
const resetCreate = () => {
|
|
2207
|
+
setCreating(false);
|
|
2208
|
+
setNewName("");
|
|
2209
|
+
setNewType("OP");
|
|
2210
|
+
setNewDate(todayISO());
|
|
2211
|
+
};
|
|
2212
|
+
const listContent = creating ? (
|
|
2213
|
+
// Create mode — replace list entirely with the create form
|
|
2214
|
+
/* @__PURE__ */ jsxs12("div", { className: "mr-case-picker__create-form", children: [
|
|
2215
|
+
/* @__PURE__ */ jsx14(
|
|
2216
|
+
"input",
|
|
2217
|
+
{
|
|
2218
|
+
type: "text",
|
|
2219
|
+
className: "mr-case-picker__create-input",
|
|
2220
|
+
placeholder: "Case name",
|
|
2221
|
+
autoFocus: true,
|
|
2222
|
+
value: newName,
|
|
2223
|
+
onChange: (e) => setNewName(e.target.value),
|
|
2224
|
+
onKeyDown: (e) => {
|
|
2225
|
+
if (e.key === "Escape") resetCreate();
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
),
|
|
2229
|
+
/* @__PURE__ */ jsx14(
|
|
2230
|
+
PresetSelect,
|
|
2231
|
+
{
|
|
2232
|
+
value: newType,
|
|
2233
|
+
options: CASE_TYPE_OPTIONS,
|
|
2234
|
+
onChange: setNewType,
|
|
2235
|
+
active: newType !== "OP"
|
|
2236
|
+
}
|
|
2237
|
+
),
|
|
2238
|
+
/* @__PURE__ */ jsx14(
|
|
2239
|
+
"input",
|
|
2240
|
+
{
|
|
2241
|
+
type: "date",
|
|
2242
|
+
className: "mr-case-picker__create-input",
|
|
2243
|
+
value: newDate,
|
|
2244
|
+
max: todayISO(),
|
|
2245
|
+
onChange: (e) => setNewDate(e.target.value)
|
|
2246
|
+
}
|
|
2247
|
+
),
|
|
2248
|
+
/* @__PURE__ */ jsxs12("div", { className: "mr-case-picker__create-actions", children: [
|
|
2249
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "mr-case-picker__create-cancel", onClick: resetCreate, children: "Cancel" }),
|
|
2250
|
+
/* @__PURE__ */ jsx14(
|
|
2251
|
+
"button",
|
|
2252
|
+
{
|
|
2253
|
+
type: "button",
|
|
2254
|
+
className: "mr-case-picker__create-save",
|
|
2255
|
+
disabled: !newName.trim() || saving,
|
|
2256
|
+
onClick: () => void handleCreate(),
|
|
2257
|
+
children: saving ? "\u2026" : "Create and Add"
|
|
2258
|
+
}
|
|
2259
|
+
)
|
|
2260
|
+
] })
|
|
2261
|
+
] })
|
|
2262
|
+
) : (
|
|
2263
|
+
// List mode — show cases + footer button
|
|
2264
|
+
/* @__PURE__ */ jsxs12(Fragment, { children: [
|
|
2265
|
+
/* @__PURE__ */ jsx14("ul", { className: "mr-case-picker__list", children: filtered.length === 0 ? /* @__PURE__ */ jsx14("li", { className: "mr-case-picker__empty", children: "No cases found" }) : filtered.map((c) => /* @__PURE__ */ jsx14("li", { children: /* @__PURE__ */ jsxs12(
|
|
2266
|
+
"button",
|
|
2267
|
+
{
|
|
2268
|
+
type: "button",
|
|
2269
|
+
className: `mr-case-picker__option${selected === c.id ? " mr-case-picker__option--active" : ""}`,
|
|
2270
|
+
onClick: () => {
|
|
2271
|
+
onChange(c.id);
|
|
2272
|
+
if (mode === "dropdown") setMenuPos(null);
|
|
2273
|
+
},
|
|
2274
|
+
children: [
|
|
2275
|
+
/* @__PURE__ */ jsx14("span", { children: c.name }),
|
|
2276
|
+
selected === c.id && /* @__PURE__ */ jsx14(Check3, { size: 14, "aria-hidden": true })
|
|
2277
|
+
]
|
|
2278
|
+
}
|
|
2279
|
+
) }, c.id)) }),
|
|
2280
|
+
/* @__PURE__ */ jsx14("div", { className: "mr-case-picker__footer", children: /* @__PURE__ */ jsxs12("button", { type: "button", className: "mr-case-picker__create-btn", onClick: () => setCreating(true), children: [
|
|
2281
|
+
/* @__PURE__ */ jsx14(Plus2, { size: 14, "aria-hidden": true }),
|
|
2282
|
+
"New care context"
|
|
2283
|
+
] }) })
|
|
2284
|
+
] })
|
|
2285
|
+
);
|
|
2286
|
+
if (mode === "inline") {
|
|
2287
|
+
return /* @__PURE__ */ jsx14("div", { className: "mr-case-picker mr-case-picker--inline", children: creating ? /* @__PURE__ */ jsxs12("div", { className: "mr-case-picker__create-form", children: [
|
|
2288
|
+
/* @__PURE__ */ jsx14(
|
|
2289
|
+
"input",
|
|
2290
|
+
{
|
|
2291
|
+
type: "text",
|
|
2292
|
+
className: "mr-case-picker__create-input",
|
|
2293
|
+
placeholder: "Case name",
|
|
2294
|
+
autoFocus: true,
|
|
2295
|
+
value: newName,
|
|
2296
|
+
onChange: (e) => setNewName(e.target.value),
|
|
2297
|
+
onKeyDown: (e) => {
|
|
2298
|
+
if (e.key === "Escape") resetCreate();
|
|
2299
|
+
}
|
|
2300
|
+
}
|
|
2301
|
+
),
|
|
2302
|
+
/* @__PURE__ */ jsx14(
|
|
2303
|
+
PresetSelect,
|
|
2304
|
+
{
|
|
2305
|
+
value: newType,
|
|
2306
|
+
options: CASE_TYPE_OPTIONS,
|
|
2307
|
+
onChange: setNewType,
|
|
2308
|
+
active: newType !== "OP"
|
|
2309
|
+
}
|
|
2310
|
+
),
|
|
2311
|
+
/* @__PURE__ */ jsx14(
|
|
2312
|
+
"input",
|
|
2313
|
+
{
|
|
2314
|
+
type: "date",
|
|
2315
|
+
className: "mr-case-picker__create-input",
|
|
2316
|
+
value: newDate,
|
|
2317
|
+
max: todayISO(),
|
|
2318
|
+
onChange: (e) => setNewDate(e.target.value)
|
|
2319
|
+
}
|
|
2320
|
+
),
|
|
2321
|
+
/* @__PURE__ */ jsxs12("div", { className: "mr-case-picker__create-actions", children: [
|
|
2322
|
+
/* @__PURE__ */ jsx14("button", { type: "button", className: "mr-case-picker__create-cancel", onClick: resetCreate, children: "Cancel" }),
|
|
2323
|
+
/* @__PURE__ */ jsx14(
|
|
2324
|
+
"button",
|
|
2325
|
+
{
|
|
2326
|
+
type: "button",
|
|
2327
|
+
className: "mr-case-picker__create-save",
|
|
2328
|
+
disabled: !newName.trim() || saving,
|
|
2329
|
+
onClick: () => void handleCreate(),
|
|
2330
|
+
children: saving ? "\u2026" : "Create and Add"
|
|
2331
|
+
}
|
|
2332
|
+
)
|
|
2333
|
+
] })
|
|
2334
|
+
] }) : /* @__PURE__ */ jsxs12("button", { type: "button", className: "mr-case-picker__create-btn", onClick: () => setCreating(true), children: [
|
|
2335
|
+
/* @__PURE__ */ jsx14(Plus2, { size: 14, "aria-hidden": true }),
|
|
2336
|
+
"New care context"
|
|
2337
|
+
] }) });
|
|
2338
|
+
}
|
|
2339
|
+
return /* @__PURE__ */ jsxs12(Fragment, { children: [
|
|
2340
|
+
/* @__PURE__ */ jsxs12(
|
|
2341
|
+
"button",
|
|
2342
|
+
{
|
|
2343
|
+
ref: fieldRef,
|
|
2344
|
+
type: "button",
|
|
2345
|
+
className: `mr-case-picker__field${open ? " mr-case-picker__field--open" : ""}${selected ? " mr-case-picker__field--active" : ""}`,
|
|
2346
|
+
onClick: () => open ? setMenuPos(null) : place(),
|
|
2347
|
+
children: [
|
|
2348
|
+
/* @__PURE__ */ jsx14(Search2, { size: 14, "aria-hidden": true, className: "mr-case-picker__field-icon" }),
|
|
2349
|
+
/* @__PURE__ */ jsx14("span", { className: selectedCase ? "mr-case-picker__field-value" : "mr-case-picker__field-placeholder", children: selectedCase?.name ?? "Search or select case\u2026" }),
|
|
2350
|
+
selected ? /* @__PURE__ */ jsx14(X2, { size: 14, "aria-hidden": true, className: "mr-case-picker__field-icon", onClick: (e) => {
|
|
2351
|
+
e.stopPropagation();
|
|
2352
|
+
onChange(null);
|
|
2353
|
+
} }) : /* @__PURE__ */ jsx14(ChevronDown, { size: 14, "aria-hidden": true, className: "mr-case-picker__field-icon" })
|
|
2354
|
+
]
|
|
2355
|
+
}
|
|
2356
|
+
),
|
|
2357
|
+
open && typeof document !== "undefined" && createPortal5(
|
|
2358
|
+
/* @__PURE__ */ jsxs12(
|
|
2359
|
+
"div",
|
|
2360
|
+
{
|
|
2361
|
+
ref: menuRef,
|
|
2362
|
+
className: "mr-case-picker__menu",
|
|
2363
|
+
"data-mr-portal": true,
|
|
2364
|
+
style: {
|
|
2365
|
+
...menuPos.top !== void 0 ? { top: menuPos.top } : { bottom: menuPos.bottom },
|
|
2366
|
+
left: menuPos.left,
|
|
2367
|
+
width: menuPos.width,
|
|
2368
|
+
maxHeight: menuPos.maxH
|
|
2369
|
+
},
|
|
2370
|
+
children: [
|
|
2371
|
+
!creating && /* @__PURE__ */ jsxs12("div", { className: "mr-case-picker__search-row", children: [
|
|
2372
|
+
/* @__PURE__ */ jsx14(Search2, { size: 14, className: "mr-case-picker__search-icon", "aria-hidden": true }),
|
|
2373
|
+
/* @__PURE__ */ jsx14(
|
|
2374
|
+
"input",
|
|
2375
|
+
{
|
|
2376
|
+
type: "text",
|
|
2377
|
+
className: "mr-case-picker__search-input",
|
|
2378
|
+
placeholder: "Search cases\u2026",
|
|
2379
|
+
autoFocus: !creating,
|
|
2380
|
+
value: query,
|
|
2381
|
+
onChange: (e) => setQuery(e.target.value)
|
|
2382
|
+
}
|
|
2383
|
+
)
|
|
2384
|
+
] }),
|
|
2385
|
+
listContent
|
|
2386
|
+
]
|
|
2387
|
+
}
|
|
2388
|
+
),
|
|
2389
|
+
document.body
|
|
2390
|
+
)
|
|
2391
|
+
] });
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
// src/views/RecordsView/RecordsSidebar.tsx
|
|
2395
|
+
import { jsx as jsx15, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2396
|
+
function RecordsSidebar({
|
|
2397
|
+
tab,
|
|
2398
|
+
onTabChange,
|
|
2399
|
+
sections,
|
|
2400
|
+
activeKey,
|
|
2401
|
+
onSelectSection,
|
|
2402
|
+
page,
|
|
2403
|
+
pageCount,
|
|
2404
|
+
onPageChange
|
|
2405
|
+
}) {
|
|
2406
|
+
const showCareContextEmpty = tab === "careContext" && sections.length === 0;
|
|
2407
|
+
return /* @__PURE__ */ jsxs13("nav", { className: "mr-records-sidebar", children: [
|
|
2408
|
+
/* @__PURE__ */ jsx15("div", { className: "mr-records-sidebar__tabs", children: /* @__PURE__ */ jsxs13("div", { className: "mr-records-sidebar__tabsrow", role: "tablist", children: [
|
|
2409
|
+
/* @__PURE__ */ jsx15(
|
|
2410
|
+
"button",
|
|
2411
|
+
{
|
|
2412
|
+
type: "button",
|
|
2413
|
+
role: "tab",
|
|
2414
|
+
"aria-selected": tab === "date",
|
|
2415
|
+
className: `mr-records-sidebar__tab${tab === "date" ? " mr-records-sidebar__tab--active" : ""}`,
|
|
2416
|
+
onClick: () => onTabChange("date"),
|
|
2417
|
+
children: "Date"
|
|
2418
|
+
}
|
|
2419
|
+
),
|
|
2420
|
+
/* @__PURE__ */ jsx15(
|
|
2421
|
+
"button",
|
|
2422
|
+
{
|
|
2423
|
+
type: "button",
|
|
2424
|
+
role: "tab",
|
|
2425
|
+
"aria-selected": tab === "careContext",
|
|
2426
|
+
className: `mr-records-sidebar__tab${tab === "careContext" ? " mr-records-sidebar__tab--active" : ""}`,
|
|
2427
|
+
onClick: () => onTabChange("careContext"),
|
|
2428
|
+
children: "Care Context"
|
|
2429
|
+
}
|
|
2430
|
+
)
|
|
2431
|
+
] }) }),
|
|
2432
|
+
/* @__PURE__ */ jsx15("div", { className: "mr-records-sidebar__body", children: showCareContextEmpty ? /* @__PURE__ */ jsxs13("div", { className: "mr-records-sidebar__empty-context", children: [
|
|
2433
|
+
/* @__PURE__ */ jsx15("p", { className: "mr-records-sidebar__empty-text", children: "No cases yet. Create one." }),
|
|
2434
|
+
/* @__PURE__ */ jsx15(CasePicker, { selected: null, onChange: () => {
|
|
2435
|
+
}, mode: "inline" })
|
|
2436
|
+
] }) : sections.map((s, i) => {
|
|
2437
|
+
const showMonth = tab === "date" && (i === 0 || sections[i - 1].monthKey !== s.monthKey);
|
|
2438
|
+
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
2439
|
+
showMonth && /* @__PURE__ */ jsx15("div", { className: "mr-records-sidebar__month", children: s.monthLabel }),
|
|
2440
|
+
/* @__PURE__ */ jsx15(
|
|
2441
|
+
SidebarItem,
|
|
2442
|
+
{
|
|
2443
|
+
id: s.key,
|
|
2444
|
+
dayNumber: s.dayNumber,
|
|
2445
|
+
weekday: s.weekday,
|
|
2446
|
+
countLabel: s.countLabel,
|
|
2447
|
+
summary: s.summary,
|
|
2448
|
+
selected: activeKey === s.key,
|
|
2449
|
+
onSelect: onSelectSection
|
|
2450
|
+
}
|
|
2451
|
+
)
|
|
2452
|
+
] }, s.key);
|
|
2453
|
+
}) }, tab),
|
|
2454
|
+
/* @__PURE__ */ jsx15(SidebarPagination, { page, pageCount, onChange: onPageChange })
|
|
2455
|
+
] });
|
|
2456
|
+
}
|
|
2457
|
+
|
|
2458
|
+
// src/views/RecordsView/RecordsGrid.tsx
|
|
2459
|
+
import { useEffect as useEffect16, useRef as useRef14 } from "react";
|
|
2460
|
+
|
|
2461
|
+
// src/views/RecordsView/RecordCardContainer.tsx
|
|
2462
|
+
import { memo as memo8 } from "react";
|
|
2463
|
+
|
|
2464
|
+
// src/components/RecordCard/RecordCard.tsx
|
|
2465
|
+
import { memo as memo7, useMemo as useMemo9 } from "react";
|
|
2466
|
+
import { Check as Check5, Copy, Eye, FolderPlus, Trash2 } from "lucide-react";
|
|
2467
|
+
|
|
2468
|
+
// src/components/Badge/Badge.tsx
|
|
2469
|
+
import { memo as memo3 } from "react";
|
|
2470
|
+
import { Star } from "lucide-react";
|
|
2471
|
+
|
|
2472
|
+
// src/components/icons/AnalysingIcon.tsx
|
|
2473
|
+
import { jsx as jsx16, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2474
|
+
function AnalysingIcon({ size = 89 }) {
|
|
2475
|
+
const scale = size / 89;
|
|
2476
|
+
return /* @__PURE__ */ jsxs14(
|
|
2477
|
+
"svg",
|
|
2478
|
+
{
|
|
2479
|
+
width: 89 * scale,
|
|
2480
|
+
height: 24 * scale,
|
|
2481
|
+
viewBox: "0 0 89 24",
|
|
2482
|
+
fill: "none",
|
|
2483
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2484
|
+
"aria-hidden": true,
|
|
2485
|
+
children: [
|
|
2486
|
+
/* @__PURE__ */ jsx16("path", { d: "M0 6C0 2.68629 2.68629 0 6 0H83C86.3137 0 89 2.68629 89 6V18C89 21.3137 86.3137 24 83 24H6C2.68629 24 0 21.3137 0 18V6Z", fill: "#FFFAEB" }),
|
|
2487
|
+
/* @__PURE__ */ jsx16("g", { clipPath: "url(#mr-analysing-clip)", children: /* @__PURE__ */ jsx16("path", { d: "M14 7V9M16.1 9.89995L17.55 8.44995M17 12H19M16.1 14.1L17.55 15.55M14 15V17M10.45 15.55L11.9 14.1M9 12H11M10.45 8.44995L11.9 9.89995", stroke: "#B45309", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
2488
|
+
/* @__PURE__ */ jsx16("path", { d: "M25.696 16H24.2983L27.4389 7.27273H28.9602L32.1009 16H30.7031L28.2358 8.85795H28.1676L25.696 16ZM25.9304 12.5824H30.4645V13.6903H25.9304V12.5824ZM34.533 12.1136V16H33.2589V9.45455H34.4819V10.5199H34.5629C34.7134 10.1733 34.9492 9.89489 35.2702 9.68466C35.5941 9.47443 36.0018 9.36932 36.4933 9.36932C36.9393 9.36932 37.3299 9.46307 37.6651 9.65057C38.0004 9.83523 38.2603 10.1108 38.445 10.4773C38.6296 10.8437 38.7219 11.2969 38.7219 11.8366V16H37.4478V11.9901C37.4478 11.5156 37.3242 11.1449 37.0771 10.8778C36.8299 10.608 36.4904 10.473 36.0586 10.473C35.7631 10.473 35.5004 10.5369 35.2702 10.6648C35.043 10.7926 34.8626 10.9801 34.729 11.2273C34.5984 11.4716 34.533 11.767 34.533 12.1136ZM42.3356 16.1449C41.9208 16.1449 41.5458 16.0682 41.2106 15.9148C40.8754 15.7585 40.6097 15.5327 40.4137 15.2372C40.2205 14.9418 40.1239 14.5795 40.1239 14.1506C40.1239 13.7812 40.195 13.4773 40.337 13.2386C40.479 13 40.6708 12.8111 40.9123 12.6719C41.1538 12.5327 41.4237 12.4276 41.7219 12.3565C42.0202 12.2855 42.3242 12.2315 42.6339 12.1946C43.0259 12.1491 43.3441 12.1122 43.5884 12.0838C43.8327 12.0526 44.0103 12.0028 44.1211 11.9347C44.2319 11.8665 44.2873 11.7557 44.2873 11.6023V11.5724C44.2873 11.2003 44.1822 10.9119 43.9719 10.7074C43.7646 10.5028 43.4549 10.4006 43.043 10.4006C42.614 10.4006 42.2759 10.4957 42.0288 10.6861C41.7844 10.8736 41.6154 11.0824 41.5217 11.3125L40.3242 11.0398C40.4663 10.642 40.6737 10.321 40.9464 10.0767C41.2219 9.82955 41.5387 9.65057 41.8967 9.53977C42.2546 9.42614 42.631 9.36932 43.0259 9.36932C43.2873 9.36932 43.5643 9.40057 43.8569 9.46307C44.1523 9.52273 44.4279 9.63352 44.6836 9.79545C44.9421 9.95739 45.1538 10.1889 45.3185 10.4901C45.4833 10.7884 45.5657 11.1761 45.5657 11.6534V16H44.3214V15.1051H44.2702C44.1879 15.2699 44.0643 15.4318 43.8995 15.5909C43.7347 15.75 43.5231 15.8821 43.2646 15.9872C43.006 16.0923 42.6964 16.1449 42.3356 16.1449ZM42.6126 15.1222C42.9648 15.1222 43.266 15.0526 43.516 14.9134C43.7688 14.7741 43.9606 14.5923 44.0913 14.3679C44.2248 14.1406 44.2915 13.8977 44.2915 13.6392V12.7955C44.2461 12.8409 44.158 12.8835 44.0273 12.9233C43.8995 12.9602 43.7532 12.9929 43.5884 13.0213C43.4237 13.0469 43.2631 13.071 43.1069 13.0938C42.9506 13.1136 42.82 13.1307 42.7148 13.1449C42.4677 13.1761 42.2418 13.2287 42.0373 13.3026C41.8356 13.3764 41.6737 13.483 41.5515 13.6222C41.4322 13.7585 41.3725 13.9403 41.3725 14.1676C41.3725 14.483 41.489 14.7216 41.7219 14.8835C41.9549 15.0426 42.2518 15.1222 42.6126 15.1222ZM48.5369 7.27273V16H47.2628V7.27273H48.5369ZM51.0565 18.4545C50.8661 18.4545 50.6928 18.4389 50.5366 18.4077C50.3803 18.3793 50.2638 18.348 50.1871 18.3139L50.494 17.2699C50.7269 17.3324 50.9343 17.3594 51.1161 17.3509C51.2979 17.3423 51.4585 17.2741 51.5977 17.1463C51.7397 17.0185 51.8647 16.8097 51.9727 16.5199L52.1303 16.0852L49.7354 9.45455H51.0991L52.7567 14.5341H52.8249L54.4826 9.45455H55.8505L53.1531 16.8736C53.0281 17.2145 52.869 17.5028 52.6758 17.7386C52.4826 17.9773 52.2525 18.1563 51.9854 18.2756C51.7184 18.3949 51.4087 18.4545 51.0565 18.4545ZM61.9528 11.0526L60.7979 11.2571C60.7496 11.1094 60.6729 10.9687 60.5678 10.8352C60.4656 10.7017 60.3263 10.5923 60.1502 10.5071C59.9741 10.4219 59.7539 10.3793 59.4897 10.3793C59.1289 10.3793 58.8278 10.4602 58.5863 10.6222C58.3448 10.7812 58.2241 10.9872 58.2241 11.2401C58.2241 11.4588 58.305 11.6349 58.467 11.7685C58.6289 11.902 58.8903 12.0114 59.2511 12.0966L60.2908 12.3352C60.8931 12.4744 61.342 12.6889 61.6374 12.9787C61.9329 13.2685 62.0806 13.6449 62.0806 14.108C62.0806 14.5 61.967 14.8494 61.7397 15.1562C61.5153 15.4602 61.2013 15.6989 60.7979 15.8722C60.3974 16.0455 59.9329 16.1321 59.4045 16.1321C58.6715 16.1321 58.0735 15.9759 57.6104 15.6634C57.1474 15.348 56.8633 14.9006 56.7582 14.321L57.9897 14.1335C58.0664 14.4545 58.2241 14.6974 58.4627 14.8622C58.7013 15.0241 59.0124 15.1051 59.396 15.1051C59.8136 15.1051 60.1474 15.0185 60.3974 14.8452C60.6474 14.669 60.7724 14.4545 60.7724 14.2017C60.7724 13.9972 60.6957 13.8253 60.5423 13.6861C60.3917 13.5469 60.1602 13.4418 59.8477 13.3707L58.7397 13.1278C58.1289 12.9886 57.6772 12.767 57.3846 12.4631C57.0948 12.1591 56.9499 11.7741 56.9499 11.3082C56.9499 10.9219 57.0579 10.5838 57.2738 10.294C57.4897 10.0043 57.788 9.77841 58.1687 9.61648C58.5494 9.4517 58.9854 9.36932 59.4769 9.36932C60.1843 9.36932 60.7411 9.52273 61.1474 9.82955C61.5536 10.1335 61.8221 10.5412 61.9528 11.0526ZM63.4815 16V9.45455H64.7557V16H63.4815ZM64.125 8.4446C63.9034 8.4446 63.7131 8.37074 63.554 8.22301C63.3977 8.07244 63.3196 7.89347 63.3196 7.68608C63.3196 7.47585 63.3977 7.29687 63.554 7.14915C63.7131 6.99858 63.9034 6.9233 64.125 6.9233C64.3466 6.9233 64.5355 6.99858 64.6918 7.14915C64.8509 7.29687 64.9304 7.47585 64.9304 7.68608C64.9304 7.89347 64.8509 8.07244 64.6918 8.22301C64.5355 8.37074 64.3466 8.4446 64.125 8.4446ZM67.744 12.1136V16H66.4698V9.45455H67.6928V10.5199H67.7738C67.9244 10.1733 68.1602 9.89489 68.4812 9.68466C68.805 9.47443 69.2127 9.36932 69.7042 9.36932C70.1502 9.36932 70.5408 9.46307 70.8761 9.65057C71.2113 9.83523 71.4712 10.1108 71.6559 10.4773C71.8406 10.8437 71.9329 11.2969 71.9329 11.8366V16H70.6587V11.9901C70.6587 11.5156 70.5352 11.1449 70.288 10.8778C70.0408 10.608 69.7013 10.473 69.2695 10.473C68.9741 10.473 68.7113 10.5369 68.4812 10.6648C68.2539 10.7926 68.0735 10.9801 67.94 11.2273C67.8093 11.4716 67.744 11.767 67.744 12.1136ZM76.386 18.5909C75.8661 18.5909 75.4187 18.5227 75.0437 18.3864C74.6715 18.25 74.3675 18.0696 74.1317 17.8452C73.896 17.6207 73.7198 17.375 73.6033 17.108L74.6985 16.6562C74.7752 16.7812 74.8775 16.9134 75.0053 17.0526C75.136 17.1946 75.3121 17.3153 75.5337 17.4148C75.7582 17.5142 76.0465 17.5639 76.3988 17.5639C76.8817 17.5639 77.2809 17.446 77.5962 17.2102C77.9116 16.9773 78.0692 16.6051 78.0692 16.0938V14.8068H77.9883C77.9116 14.946 77.8008 15.1009 77.6559 15.2713C77.5138 15.4418 77.3178 15.5895 77.0678 15.7145C76.8178 15.8395 76.4925 15.902 76.092 15.902C75.5749 15.902 75.109 15.7812 74.6942 15.5398C74.2823 15.2955 73.9556 14.9361 73.7141 14.4616C73.4755 13.9844 73.3562 13.3977 73.3562 12.7017C73.3562 12.0057 73.4741 11.4091 73.7099 10.9119C73.9485 10.4148 74.2752 10.0341 74.69 9.76989C75.1048 9.50284 75.5749 9.36932 76.1005 9.36932C76.5067 9.36932 76.8349 9.4375 77.0849 9.57386C77.3349 9.70739 77.5295 9.86364 77.6687 10.0426C77.8107 10.2216 77.9201 10.3793 77.9968 10.5156H78.0906V9.45455H79.3391V16.1449C79.3391 16.7074 79.2085 17.169 78.9471 17.5298C78.6857 17.8906 78.332 18.1577 77.886 18.331C77.4428 18.5043 76.9428 18.5909 76.386 18.5909ZM76.3732 14.8452C76.7397 14.8452 77.0494 14.7599 77.3022 14.5895C77.5579 14.4162 77.7511 14.169 77.8817 13.848C78.0153 13.5241 78.082 13.1364 78.082 12.6847C78.082 12.2443 78.0167 11.8565 77.886 11.5213C77.7553 11.1861 77.5636 10.9247 77.3107 10.7372C77.0579 10.5469 76.7454 10.4517 76.3732 10.4517C75.9897 10.4517 75.6701 10.5511 75.4144 10.75C75.1587 10.946 74.9656 11.2131 74.8349 11.5511C74.707 11.8892 74.6431 12.267 74.6431 12.6847C74.6431 13.1136 74.7085 13.4901 74.8391 13.8139C74.9698 14.1378 75.163 14.3906 75.4187 14.5724C75.6772 14.7543 75.9954 14.8452 76.3732 14.8452Z", fill: "#B45309" }),
|
|
2489
|
+
/* @__PURE__ */ jsx16("defs", { children: /* @__PURE__ */ jsx16("clipPath", { id: "mr-analysing-clip", children: /* @__PURE__ */ jsx16("rect", { width: "12", height: "12", fill: "white", transform: "translate(8 6)" }) }) })
|
|
2490
|
+
]
|
|
2491
|
+
}
|
|
2492
|
+
);
|
|
2493
|
+
}
|
|
2494
|
+
|
|
2495
|
+
// src/components/icons/UploadingIcon.tsx
|
|
2496
|
+
import { jsx as jsx17, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
2497
|
+
function UploadingIcon() {
|
|
2498
|
+
return /* @__PURE__ */ jsxs15("svg", { width: "75", height: "24", viewBox: "0 0 75 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [
|
|
2499
|
+
/* @__PURE__ */ jsx17("g", { style: { transformOrigin: "6px 12px", animation: "mr-spin 1s linear infinite" }, children: /* @__PURE__ */ jsx17("path", { d: "M10.5 12.0002C10.5 12.9505 10.1991 13.8764 9.64047 14.6452C9.08187 15.414 8.29423 15.9862 7.39044 16.2798C6.48665 16.5734 5.5131 16.5734 4.60932 16.2797C3.70555 15.986 2.91794 15.4138 2.35938 14.645C1.80083 13.8762 1.49999 12.9503 1.5 12C1.50001 11.0497 1.80085 10.1238 2.35942 9.35497C2.91799 8.58617 3.7056 8.01392 4.60938 7.72026C5.51316 7.42659 6.48671 7.42658 7.3905 7.72022", stroke: "#215FFF", strokeLinecap: "round", strokeLinejoin: "round" }) }),
|
|
2500
|
+
/* @__PURE__ */ jsx17("path", { d: "M22.571 7.27273H23.892V13.0128C23.892 13.6236 23.7486 14.1648 23.4616 14.6364C23.1747 15.1051 22.7713 15.4744 22.2514 15.7443C21.7315 16.0114 21.1222 16.1449 20.4233 16.1449C19.7273 16.1449 19.1193 16.0114 18.5994 15.7443C18.0795 15.4744 17.6761 15.1051 17.3892 14.6364C17.1023 14.1648 16.9588 13.6236 16.9588 13.0128V7.27273H18.2756V12.9062C18.2756 13.3011 18.3622 13.652 18.5355 13.9588C18.7116 14.2656 18.9602 14.5071 19.2812 14.6832C19.6023 14.8565 19.983 14.9432 20.4233 14.9432C20.8665 14.9432 21.2486 14.8565 21.5696 14.6832C21.8935 14.5071 22.1406 14.2656 22.3111 13.9588C22.4844 13.652 22.571 13.3011 22.571 12.9062V7.27273ZM25.7042 18.4545V9.45455H26.9485V10.5156H27.055C27.1289 10.3793 27.2354 10.2216 27.3746 10.0426C27.5138 9.86364 27.707 9.70739 27.9542 9.57386C28.2013 9.4375 28.5281 9.36932 28.9343 9.36932C29.4627 9.36932 29.9343 9.50284 30.3491 9.76989C30.7638 10.0369 31.0891 10.4219 31.3249 10.9247C31.5636 11.4276 31.6829 12.0327 31.6829 12.7401C31.6829 13.4474 31.565 14.054 31.3292 14.5597C31.0934 15.0625 30.7695 15.4503 30.3576 15.723C29.9457 15.9929 29.4755 16.1278 28.9471 16.1278C28.5494 16.1278 28.2241 16.0611 27.9712 15.9276C27.7212 15.794 27.5252 15.6378 27.3832 15.4588C27.2411 15.2798 27.1317 15.1207 27.055 14.9815H26.9783V18.4545H25.7042ZM26.9528 12.7273C26.9528 13.1875 27.0195 13.5909 27.1531 13.9375C27.2866 14.2841 27.4798 14.5554 27.7326 14.7514C27.9854 14.9446 28.2951 15.0412 28.6616 15.0412C29.0423 15.0412 29.3604 14.9403 29.6161 14.7386C29.8718 14.5341 30.065 14.2571 30.1957 13.9077C30.3292 13.5582 30.396 13.1648 30.396 12.7273C30.396 12.2955 30.3306 11.9077 30.1999 11.5639C30.0721 11.2202 29.8789 10.9489 29.6204 10.75C29.3647 10.5511 29.0451 10.4517 28.6616 10.4517C28.2923 10.4517 27.9798 10.5469 27.7241 10.7372C27.4712 10.9276 27.2795 11.1932 27.1488 11.5341C27.0181 11.875 26.9528 12.2727 26.9528 12.7273ZM34.3846 7.27273V16H33.1104V7.27273H34.3846ZM38.8558 16.1321C38.2422 16.1321 37.7067 15.9915 37.2493 15.7102C36.7919 15.429 36.4368 15.0355 36.1839 14.5298C35.9311 14.0241 35.8047 13.4332 35.8047 12.7571C35.8047 12.0781 35.9311 11.4844 36.1839 10.9759C36.4368 10.4673 36.7919 10.0724 37.2493 9.79119C37.7067 9.50994 38.2422 9.36932 38.8558 9.36932C39.4695 9.36932 40.005 9.50994 40.4624 9.79119C40.9197 10.0724 41.2749 10.4673 41.5277 10.9759C41.7805 11.4844 41.907 12.0781 41.907 12.7571C41.907 13.4332 41.7805 14.0241 41.5277 14.5298C41.2749 15.0355 40.9197 15.429 40.4624 15.7102C40.005 15.9915 39.4695 16.1321 38.8558 16.1321ZM38.8601 15.0625C39.2578 15.0625 39.5874 14.9574 39.8487 14.7472C40.1101 14.5369 40.3033 14.2571 40.4283 13.9077C40.5561 13.5582 40.62 13.1733 40.62 12.7528C40.62 12.3352 40.5561 11.9517 40.4283 11.6023C40.3033 11.25 40.1101 10.9673 39.8487 10.7543C39.5874 10.5412 39.2578 10.4347 38.8601 10.4347C38.4595 10.4347 38.1271 10.5412 37.8629 10.7543C37.6016 10.9673 37.407 11.25 37.2791 11.6023C37.1541 11.9517 37.0916 12.3352 37.0916 12.7528C37.0916 13.1733 37.1541 13.5582 37.2791 13.9077C37.407 14.2571 37.6016 14.5369 37.8629 14.7472C38.1271 14.9574 38.4595 15.0625 38.8601 15.0625ZM45.234 16.1449C44.8192 16.1449 44.4442 16.0682 44.109 15.9148C43.7738 15.7585 43.5082 15.5327 43.3121 15.2372C43.119 14.9418 43.0224 14.5795 43.0224 14.1506C43.0224 13.7812 43.0934 13.4773 43.2354 13.2386C43.3775 13 43.5692 12.8111 43.8107 12.6719C44.0522 12.5327 44.3221 12.4276 44.6204 12.3565C44.9187 12.2855 45.2227 12.2315 45.5323 12.1946C45.9244 12.1491 46.2425 12.1122 46.4869 12.0838C46.7312 12.0526 46.9087 12.0028 47.0195 11.9347C47.1303 11.8665 47.1857 11.7557 47.1857 11.6023V11.5724C47.1857 11.2003 47.0806 10.9119 46.8704 10.7074C46.663 10.5028 46.3533 10.4006 45.9414 10.4006C45.5124 10.4006 45.1744 10.4957 44.9272 10.6861C44.6829 10.8736 44.5138 11.0824 44.4201 11.3125L43.2227 11.0398C43.3647 10.642 43.5721 10.321 43.8448 10.0767C44.1204 9.82955 44.4371 9.65057 44.7951 9.53977C45.1531 9.42614 45.5295 9.36932 45.9244 9.36932C46.1857 9.36932 46.4627 9.40057 46.7553 9.46307C47.0508 9.52273 47.3263 9.63352 47.582 9.79545C47.8406 9.95739 48.0522 10.1889 48.217 10.4901C48.3817 10.7884 48.4641 11.1761 48.4641 11.6534V16H47.2198V15.1051H47.1687C47.0863 15.2699 46.9627 15.4318 46.7979 15.5909C46.6332 15.75 46.4215 15.8821 46.163 15.9872C45.9045 16.0923 45.5948 16.1449 45.234 16.1449ZM45.511 15.1222C45.8633 15.1222 46.1644 15.0526 46.4144 14.9134C46.6673 14.7741 46.859 14.5923 46.9897 14.3679C47.1232 14.1406 47.19 13.8977 47.19 13.6392V12.7955C47.1445 12.8409 47.0565 12.8835 46.9258 12.9233C46.7979 12.9602 46.6516 12.9929 46.4869 13.0213C46.3221 13.0469 46.1616 13.071 46.0053 13.0938C45.8491 13.1136 45.7184 13.1307 45.6133 13.1449C45.3661 13.1761 45.1403 13.2287 44.9357 13.3026C44.734 13.3764 44.5721 13.483 44.4499 13.6222C44.3306 13.7585 44.271 13.9403 44.271 14.1676C44.271 14.483 44.3874 14.7216 44.6204 14.8835C44.8533 15.0426 45.1502 15.1222 45.511 15.1222ZM52.6115 16.1278C52.0831 16.1278 51.6115 15.9929 51.1967 15.723C50.7848 15.4503 50.4609 15.0625 50.2251 14.5597C49.9922 14.054 49.8757 13.4474 49.8757 12.7401C49.8757 12.0327 49.9936 11.4276 50.2294 10.9247C50.468 10.4219 50.7947 10.0369 51.2095 9.76989C51.6243 9.50284 52.0945 9.36932 52.62 9.36932C53.0263 9.36932 53.353 9.4375 53.6001 9.57386C53.8501 9.70739 54.0433 9.86364 54.1797 10.0426C54.3189 10.2216 54.4268 10.3793 54.5036 10.5156H54.5803V7.27273H55.8544V16H54.6101V14.9815H54.5036C54.4268 15.1207 54.3161 15.2798 54.1712 15.4588C54.0291 15.6378 53.8331 15.794 53.5831 15.9276C53.3331 16.0611 53.0092 16.1278 52.6115 16.1278ZM52.8928 15.0412C53.2592 15.0412 53.5689 14.9446 53.8217 14.7514C54.0774 14.5554 54.2706 14.2841 54.4013 13.9375C54.5348 13.5909 54.6016 13.1875 54.6016 12.7273C54.6016 12.2727 54.5362 11.875 54.4055 11.5341C54.2749 11.1932 54.0831 10.9276 53.8303 10.7372C53.5774 10.5469 53.2649 10.4517 52.8928 10.4517C52.5092 10.4517 52.1896 10.5511 51.9339 10.75C51.6783 10.9489 51.4851 11.2202 51.3544 11.5639C51.2266 11.9077 51.1626 12.2955 51.1626 12.7273C51.1626 13.1648 51.228 13.5582 51.3587 13.9077C51.4893 14.2571 51.6825 14.5341 51.9382 14.7386C52.1967 14.9403 52.5149 15.0412 52.8928 15.0412ZM57.6729 16V9.45455H58.9471V16H57.6729ZM58.3164 8.4446C58.0948 8.4446 57.9045 8.37074 57.7454 8.22301C57.5891 8.07244 57.511 7.89347 57.511 7.68608C57.511 7.47585 57.5891 7.29687 57.7454 7.14915C57.9045 6.99858 58.0948 6.9233 58.3164 6.9233C58.538 6.9233 58.7269 6.99858 58.8832 7.14915C59.0423 7.29687 59.1218 7.47585 59.1218 7.68608C59.1218 7.89347 59.0423 8.07244 58.8832 8.22301C58.7269 8.37074 58.538 8.4446 58.3164 8.4446ZM61.9354 12.1136V16H60.6612V9.45455H61.8842V10.5199H61.9652C62.1158 10.1733 62.3516 9.89489 62.6726 9.68466C62.9964 9.47443 63.4041 9.36932 63.8956 9.36932C64.3416 9.36932 64.7322 9.46307 65.0675 9.65057C65.4027 9.83523 65.6626 10.1108 65.8473 10.4773C66.032 10.8437 66.1243 11.2969 66.1243 11.8366V16H64.8501V11.9901C64.8501 11.5156 64.7266 11.1449 64.4794 10.8778C64.2322 10.608 63.8928 10.473 63.4609 10.473C63.1655 10.473 62.9027 10.5369 62.6726 10.6648C62.4453 10.7926 62.2649 10.9801 62.1314 11.2273C62.0007 11.4716 61.9354 11.767 61.9354 12.1136ZM70.5774 18.5909C70.0575 18.5909 69.6101 18.5227 69.2351 18.3864C68.8629 18.25 68.5589 18.0696 68.3232 17.8452C68.0874 17.6207 67.9112 17.375 67.7947 17.108L68.8899 16.6562C68.9666 16.7812 69.0689 16.9134 69.1967 17.0526C69.3274 17.1946 69.5036 17.3153 69.7251 17.4148C69.9496 17.5142 70.2379 17.5639 70.5902 17.5639C71.0732 17.5639 71.4723 17.446 71.7876 17.2102C72.103 16.9773 72.2607 16.6051 72.2607 16.0938V14.8068H72.1797C72.103 14.946 71.9922 15.1009 71.8473 15.2713C71.7053 15.4418 71.5092 15.5895 71.2592 15.7145C71.0092 15.8395 70.6839 15.902 70.2834 15.902C69.7663 15.902 69.3004 15.7812 68.8857 15.5398C68.4737 15.2955 68.147 14.9361 67.9055 14.4616C67.6669 13.9844 67.5476 13.3977 67.5476 12.7017C67.5476 12.0057 67.6655 11.4091 67.9013 10.9119C68.1399 10.4148 68.4666 10.0341 68.8814 9.76989C69.2962 9.50284 69.7663 9.36932 70.2919 9.36932C70.6982 9.36932 71.0263 9.4375 71.2763 9.57386C71.5263 9.70739 71.7209 9.86364 71.8601 10.0426C72.0021 10.2216 72.1115 10.3793 72.1882 10.5156H72.282V9.45455H73.5305V16.1449C73.5305 16.7074 73.3999 17.169 73.1385 17.5298C72.8771 17.8906 72.5234 18.1577 72.0774 18.331C71.6342 18.5043 71.1342 18.5909 70.5774 18.5909ZM70.5646 14.8452C70.9311 14.8452 71.2408 14.7599 71.4936 14.5895C71.7493 14.4162 71.9425 14.169 72.0732 13.848C72.2067 13.5241 72.2734 13.1364 72.2734 12.6847C72.2734 12.2443 72.2081 11.8565 72.0774 11.5213C71.9467 11.1861 71.755 10.9247 71.5021 10.7372C71.2493 10.5469 70.9368 10.4517 70.5646 10.4517C70.1811 10.4517 69.8615 10.5511 69.6058 10.75C69.3501 10.946 69.157 11.2131 69.0263 11.5511C68.8984 11.8892 68.8345 12.267 68.8345 12.6847C68.8345 13.1136 68.8999 13.4901 69.0305 13.8139C69.1612 14.1378 69.3544 14.3906 69.6101 14.5724C69.8686 14.7543 70.1868 14.8452 70.5646 14.8452Z", fill: "#215FFF" })
|
|
2501
|
+
] });
|
|
2502
|
+
}
|
|
2503
|
+
|
|
2504
|
+
// src/components/icons/FailedUploadIcon.tsx
|
|
2505
|
+
import { jsx as jsx18, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2506
|
+
function FailedUploadIcon() {
|
|
2507
|
+
return /* @__PURE__ */ jsxs16("svg", { width: "108", height: "24", viewBox: "0 0 108 24", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": true, children: [
|
|
2508
|
+
/* @__PURE__ */ jsx18("path", { d: "M6 10.5001V12.5001M6 14.5001H6.005M10.865 15.0001L6.86496 8.00011C6.77775 7.84621 6.65127 7.71821 6.49843 7.62915C6.34559 7.54009 6.17186 7.49316 5.99496 7.49316C5.81807 7.49316 5.64434 7.54009 5.4915 7.62915C5.33866 7.71821 5.21218 7.84621 5.12496 8.00011L1.12496 15.0001C1.03681 15.1528 0.990579 15.3261 0.990969 15.5024C0.99136 15.6787 1.03835 15.8517 1.12719 16.004C1.21602 16.1563 1.34354 16.2824 1.49681 16.3695C1.65009 16.4566 1.82367 16.5017 1.99996 16.5001H9.99996C10.1754 16.4999 10.3477 16.4536 10.4996 16.3658C10.6515 16.2779 10.7776 16.1517 10.8652 15.9997C10.9529 15.8477 10.999 15.6753 10.9989 15.4999C10.9989 15.3244 10.9527 15.1521 10.865 15.0001Z", stroke: "#D92D20", strokeLinecap: "round", strokeLinejoin: "round" }),
|
|
2509
|
+
/* @__PURE__ */ jsx18("path", { d: "M16.9588 16V7.27273H22.3707V8.40625H18.2756V11.0653H21.983V12.1946H18.2756V16H16.9588ZM25.7692 16.1449C25.3544 16.1449 24.9794 16.0682 24.6442 15.9148C24.3089 15.7585 24.0433 15.5327 23.8473 15.2372C23.6541 14.9418 23.5575 14.5795 23.5575 14.1506C23.5575 13.7812 23.6286 13.4773 23.7706 13.2386C23.9126 13 24.1044 12.8111 24.3459 12.6719C24.5874 12.5327 24.8572 12.4276 25.1555 12.3565C25.4538 12.2855 25.7578 12.2315 26.0675 12.1946C26.4595 12.1491 26.7777 12.1122 27.022 12.0838C27.2663 12.0526 27.4439 12.0028 27.5547 11.9347C27.6655 11.8665 27.7209 11.7557 27.7209 11.6023V11.5724C27.7209 11.2003 27.6158 10.9119 27.4055 10.7074C27.1982 10.5028 26.8885 10.4006 26.4766 10.4006C26.0476 10.4006 25.7095 10.4957 25.4624 10.6861C25.218 10.8736 25.049 11.0824 24.9553 11.3125L23.7578 11.0398C23.8999 10.642 24.1072 10.321 24.38 10.0767C24.6555 9.82955 24.9723 9.65057 25.3303 9.53977C25.6882 9.42614 26.0646 9.36932 26.4595 9.36932C26.7209 9.36932 26.9979 9.40057 27.2905 9.46307C27.5859 9.52273 27.8615 9.63352 28.1172 9.79545C28.3757 9.95739 28.5874 10.1889 28.7521 10.4901C28.9169 10.7884 28.9993 11.1761 28.9993 11.6534V16H27.755V15.1051H27.7038C27.6214 15.2699 27.4979 15.4318 27.3331 15.5909C27.1683 15.75 26.9567 15.8821 26.6982 15.9872C26.4396 16.0923 26.13 16.1449 25.7692 16.1449ZM26.0462 15.1222C26.3984 15.1222 26.6996 15.0526 26.9496 14.9134C27.2024 14.7741 27.3942 14.5923 27.5249 14.3679C27.6584 14.1406 27.7251 13.8977 27.7251 13.6392V12.7955C27.6797 12.8409 27.5916 12.8835 27.4609 12.9233C27.3331 12.9602 27.1868 12.9929 27.022 13.0213C26.8572 13.0469 26.6967 13.071 26.5405 13.0938C26.3842 13.1136 26.2536 13.1307 26.1484 13.1449C25.9013 13.1761 25.6754 13.2287 25.4709 13.3026C25.2692 13.3764 25.1072 13.483 24.9851 13.6222C24.8658 13.7585 24.8061 13.9403 24.8061 14.1676C24.8061 14.483 24.9226 14.7216 25.1555 14.8835C25.3885 15.0426 25.6854 15.1222 26.0462 15.1222ZM30.6964 16V9.45455H31.9705V16H30.6964ZM31.3398 8.4446C31.1183 8.4446 30.9279 8.37074 30.7688 8.22301C30.6126 8.07244 30.5344 7.89347 30.5344 7.68608C30.5344 7.47585 30.6126 7.29687 30.7688 7.14915C30.9279 6.99858 31.1183 6.9233 31.3398 6.9233C31.5614 6.9233 31.7504 6.99858 31.9066 7.14915C32.0657 7.29687 32.1452 7.47585 32.1452 7.68608C32.1452 7.89347 32.0657 8.07244 31.9066 8.22301C31.7504 8.37074 31.5614 8.4446 31.3398 8.4446ZM34.9588 7.27273V16H33.6847V7.27273H34.9588ZM39.494 16.1321C38.8491 16.1321 38.2937 15.9943 37.8278 15.7188C37.3647 15.4403 37.0067 15.0497 36.7539 14.5469C36.5039 14.0412 36.3789 13.4489 36.3789 12.7699C36.3789 12.0994 36.5039 11.5085 36.7539 10.9972C37.0067 10.4858 37.359 10.0866 37.8107 9.79972C38.2653 9.51278 38.7965 9.36932 39.4045 9.36932C39.7738 9.36932 40.1317 9.4304 40.4783 9.55256C40.8249 9.67472 41.136 9.86648 41.4116 10.1278C41.6871 10.3892 41.9045 10.7287 42.0636 11.1463C42.2227 11.5611 42.3022 12.0653 42.3022 12.6591V13.1108H37.0991V12.1562H41.0536C41.0536 11.821 40.9854 11.5241 40.8491 11.2656C40.7127 11.0043 40.521 10.7983 40.2738 10.6477C40.0295 10.4972 39.7425 10.4219 39.413 10.4219C39.055 10.4219 38.7425 10.5099 38.4755 10.6861C38.2113 10.8594 38.0067 11.0866 37.8619 11.3679C37.7198 11.6463 37.6488 11.9489 37.6488 12.2756V13.0213C37.6488 13.4588 37.7255 13.831 37.8789 14.1378C38.0352 14.4446 38.2525 14.679 38.5309 14.8409C38.8093 15 39.1346 15.0795 39.5067 15.0795C39.7482 15.0795 39.9684 15.0455 40.1673 14.9773C40.3661 14.9062 40.538 14.8011 40.6829 14.6619C40.8278 14.5227 40.9386 14.3509 41.0153 14.1463L42.2212 14.3636C42.1246 14.7187 41.9513 15.0298 41.7013 15.2969C41.4542 15.5611 41.1431 15.767 40.7681 15.9148C40.396 16.0597 39.9712 16.1321 39.494 16.1321ZM46.1662 16.1278C45.6378 16.1278 45.1662 15.9929 44.7514 15.723C44.3395 15.4503 44.0156 15.0625 43.7798 14.5597C43.5469 14.054 43.4304 13.4474 43.4304 12.7401C43.4304 12.0327 43.5483 11.4276 43.7841 10.9247C44.0227 10.4219 44.3494 10.0369 44.7642 9.76989C45.179 9.50284 45.6491 9.36932 46.1747 9.36932C46.581 9.36932 46.9077 9.4375 47.1548 9.57386C47.4048 9.70739 47.598 9.86364 47.7344 10.0426C47.8736 10.2216 47.9815 10.3793 48.0582 10.5156H48.1349V7.27273H49.4091V16H48.1648V14.9815H48.0582C47.9815 15.1207 47.8707 15.2798 47.7259 15.4588C47.5838 15.6378 47.3878 15.794 47.1378 15.9276C46.8878 16.0611 46.5639 16.1278 46.1662 16.1278ZM46.4474 15.0412C46.8139 15.0412 47.1236 14.9446 47.3764 14.7514C47.6321 14.5554 47.8253 14.2841 47.956 13.9375C48.0895 13.5909 48.1562 13.1875 48.1562 12.7273C48.1562 12.2727 48.0909 11.875 47.9602 11.5341C47.8295 11.1932 47.6378 10.9276 47.3849 10.7372C47.1321 10.5469 46.8196 10.4517 46.4474 10.4517C46.0639 10.4517 45.7443 10.5511 45.4886 10.75C45.233 10.9489 45.0398 11.2202 44.9091 11.5639C44.7813 11.9077 44.7173 12.2955 44.7173 12.7273C44.7173 13.1648 44.7827 13.5582 44.9134 13.9077C45.044 14.2571 45.2372 14.5341 45.4929 14.7386C45.7514 14.9403 46.0696 15.0412 46.4474 15.0412ZM57.4588 9.45455V10.4773H53.8835V9.45455H57.4588ZM54.8423 7.88636H56.1165V14.0781C56.1165 14.3253 56.1534 14.5114 56.2273 14.6364C56.3011 14.7585 56.3963 14.8423 56.5128 14.8878C56.6321 14.9304 56.7614 14.9517 56.9006 14.9517C57.0028 14.9517 57.0923 14.9446 57.169 14.9304C57.2457 14.9162 57.3054 14.9048 57.348 14.8963L57.5781 15.9489C57.5043 15.9773 57.3991 16.0057 57.2628 16.0341C57.1264 16.0653 56.956 16.0824 56.7514 16.0852C56.4162 16.0909 56.1037 16.0312 55.8139 15.9062C55.5241 15.7812 55.2898 15.5881 55.1108 15.3267C54.9318 15.0653 54.8423 14.7372 54.8423 14.3423V7.88636ZM61.555 16.1321C60.9414 16.1321 60.4059 15.9915 59.9485 15.7102C59.4911 15.429 59.136 15.0355 58.8832 14.5298C58.6303 14.0241 58.5039 13.4332 58.5039 12.7571C58.5039 12.0781 58.6303 11.4844 58.8832 10.9759C59.136 10.4673 59.4911 10.0724 59.9485 9.79119C60.4059 9.50994 60.9414 9.36932 61.555 9.36932C62.1687 9.36932 62.7042 9.50994 63.1616 9.79119C63.619 10.0724 63.9741 10.4673 64.2269 10.9759C64.4798 11.4844 64.6062 12.0781 64.6062 12.7571C64.6062 13.4332 64.4798 14.0241 64.2269 14.5298C63.9741 15.0355 63.619 15.429 63.1616 15.7102C62.7042 15.9915 62.1687 16.1321 61.555 16.1321ZM61.5593 15.0625C61.957 15.0625 62.2866 14.9574 62.5479 14.7472C62.8093 14.5369 63.0025 14.2571 63.1275 13.9077C63.2553 13.5582 63.3192 13.1733 63.3192 12.7528C63.3192 12.3352 63.2553 11.9517 63.1275 11.6023C63.0025 11.25 62.8093 10.9673 62.5479 10.7543C62.2866 10.5412 61.957 10.4347 61.5593 10.4347C61.1587 10.4347 60.8263 10.5412 60.5621 10.7543C60.3008 10.9673 60.1062 11.25 59.9783 11.6023C59.8533 11.9517 59.7908 12.3352 59.7908 12.7528C59.7908 13.1733 59.8533 13.5582 59.9783 13.9077C60.1062 14.2571 60.3008 14.5369 60.5621 14.7472C60.8263 14.9574 61.1587 15.0625 61.5593 15.0625ZM73.3505 13.2855V9.45455H74.6289V16H73.3761V14.8665H73.3079C73.1573 15.2159 72.9158 15.5071 72.5835 15.7401C72.2539 15.9702 71.8434 16.0852 71.3519 16.0852C70.9315 16.0852 70.5593 15.9929 70.2354 15.8082C69.9144 15.6207 69.6616 15.3438 69.4769 14.9773C69.2951 14.6108 69.2042 14.1577 69.2042 13.6179V9.45455H70.4783V13.4645C70.4783 13.9105 70.6019 14.2656 70.8491 14.5298C71.0962 14.794 71.4173 14.9261 71.8121 14.9261C72.0508 14.9261 72.288 14.8665 72.5238 14.7472C72.7624 14.6278 72.9599 14.4474 73.1161 14.206C73.2752 13.9645 73.3533 13.6577 73.3505 13.2855ZM76.3409 18.4545V9.45455H77.5852V10.5156H77.6918C77.7656 10.3793 77.8722 10.2216 78.0114 10.0426C78.1506 9.86364 78.3438 9.70739 78.5909 9.57386C78.8381 9.4375 79.1648 9.36932 79.571 9.36932C80.0994 9.36932 80.571 9.50284 80.9858 9.76989C81.4006 10.0369 81.7259 10.4219 81.9616 10.9247C82.2003 11.4276 82.3196 12.0327 82.3196 12.7401C82.3196 13.4474 82.2017 14.054 81.9659 14.5597C81.7301 15.0625 81.4063 15.4503 80.9943 15.723C80.5824 15.9929 80.1122 16.1278 79.5838 16.1278C79.1861 16.1278 78.8608 16.0611 78.608 15.9276C78.358 15.794 78.1619 15.6378 78.0199 15.4588C77.8778 15.2798 77.7685 15.1207 77.6918 14.9815H77.6151V18.4545H76.3409ZM77.5895 12.7273C77.5895 13.1875 77.6563 13.5909 77.7898 13.9375C77.9233 14.2841 78.1165 14.5554 78.3693 14.7514C78.6222 14.9446 78.9318 15.0412 79.2983 15.0412C79.679 15.0412 79.9972 14.9403 80.2528 14.7386C80.5085 14.5341 80.7017 14.2571 80.8324 13.9077C80.9659 13.5582 81.0327 13.1648 81.0327 12.7273C81.0327 12.2955 80.9673 11.9077 80.8366 11.5639C80.7088 11.2202 80.5156 10.9489 80.2571 10.75C80.0014 10.5511 79.6818 10.4517 79.2983 10.4517C78.929 10.4517 78.6165 10.5469 78.3608 10.7372C78.108 10.9276 77.9162 11.1932 77.7855 11.5341C77.6548 11.875 77.5895 12.2727 77.5895 12.7273ZM85.0213 7.27273V16H83.7472V7.27273H85.0213ZM89.4925 16.1321C88.8789 16.1321 88.3434 15.9915 87.886 15.7102C87.4286 15.429 87.0735 15.0355 86.8207 14.5298C86.5678 14.0241 86.4414 13.4332 86.4414 12.7571C86.4414 12.0781 86.5678 11.4844 86.8207 10.9759C87.0735 10.4673 87.4286 10.0724 87.886 9.79119C88.3434 9.50994 88.8789 9.36932 89.4925 9.36932C90.1062 9.36932 90.6417 9.50994 91.0991 9.79119C91.5565 10.0724 91.9116 10.4673 92.1644 10.9759C92.4173 11.4844 92.5437 12.0781 92.5437 12.7571C92.5437 13.4332 92.4173 14.0241 92.1644 14.5298C91.9116 15.0355 91.5565 15.429 91.0991 15.7102C90.6417 15.9915 90.1062 16.1321 89.4925 16.1321ZM89.4968 15.0625C89.8945 15.0625 90.2241 14.9574 90.4854 14.7472C90.7468 14.5369 90.94 14.2571 91.065 13.9077C91.1928 13.5582 91.2567 13.1733 91.2567 12.7528C91.2567 12.3352 91.1928 11.9517 91.065 11.6023C90.94 11.25 90.7468 10.9673 90.4854 10.7543C90.2241 10.5412 89.8945 10.4347 89.4968 10.4347C89.0962 10.4347 88.7638 10.5412 88.4996 10.7543C88.2383 10.9673 88.0437 11.25 87.9158 11.6023C87.7908 11.9517 87.7283 12.3352 87.7283 12.7528C87.7283 13.1733 87.7908 13.5582 87.9158 13.9077C88.0437 14.2571 88.2383 14.5369 88.4996 14.7472C88.7638 14.9574 89.0962 15.0625 89.4968 15.0625ZM95.8707 16.1449C95.456 16.1449 95.081 16.0682 94.7457 15.9148C94.4105 15.7585 94.1449 15.5327 93.9489 15.2372C93.7557 14.9418 93.6591 14.5795 93.6591 14.1506C93.6591 13.7812 93.7301 13.4773 93.8722 13.2386C94.0142 13 94.206 12.8111 94.4474 12.6719C94.6889 12.5327 94.9588 12.4276 95.2571 12.3565C95.5554 12.2855 95.8594 12.2315 96.169 12.1946C96.5611 12.1491 96.8793 12.1122 97.1236 12.0838C97.3679 12.0526 97.5455 12.0028 97.6562 11.9347C97.767 11.8665 97.8224 11.7557 97.8224 11.6023V11.5724C97.8224 11.2003 97.7173 10.9119 97.5071 10.7074C97.2997 10.5028 96.9901 10.4006 96.5781 10.4006C96.1491 10.4006 95.8111 10.4957 95.5639 10.6861C95.3196 10.8736 95.1506 11.0824 95.0568 11.3125L93.8594 11.0398C94.0014 10.642 94.2088 10.321 94.4815 10.0767C94.7571 9.82955 95.0739 9.65057 95.4318 9.53977C95.7898 9.42614 96.1662 9.36932 96.5611 9.36932C96.8224 9.36932 97.0994 9.40057 97.392 9.46307C97.6875 9.52273 97.9631 9.63352 98.2188 9.79545C98.4773 9.95739 98.6889 10.1889 98.8537 10.4901C99.0185 10.7884 99.1009 11.1761 99.1009 11.6534V16H97.8565V15.1051H97.8054C97.723 15.2699 97.5994 15.4318 97.4347 15.5909C97.2699 15.75 97.0582 15.8821 96.7997 15.9872C96.5412 16.0923 96.2315 16.1449 95.8707 16.1449ZM96.1477 15.1222C96.5 15.1222 96.8011 15.0526 97.0511 14.9134C97.304 14.7741 97.4957 14.5923 97.6264 14.3679C97.7599 14.1406 97.8267 13.8977 97.8267 13.6392V12.7955C97.7813 12.8409 97.6932 12.8835 97.5625 12.9233C97.4347 12.9602 97.2884 12.9929 97.1236 13.0213C96.9588 13.0469 96.7983 13.071 96.642 13.0938C96.4858 13.1136 96.3551 13.1307 96.25 13.1449C96.0028 13.1761 95.777 13.2287 95.5724 13.3026C95.3707 13.3764 95.2088 13.483 95.0866 13.6222C94.9673 13.7585 94.9077 13.9403 94.9077 14.1676C94.9077 14.483 95.0241 14.7216 95.2571 14.8835C95.4901 15.0426 95.7869 15.1222 96.1477 15.1222ZM103.248 16.1278C102.72 16.1278 102.248 15.9929 101.833 15.723C101.422 15.4503 101.098 15.0625 100.862 14.5597C100.629 14.054 100.512 13.4474 100.512 12.7401C100.512 12.0327 100.63 11.4276 100.866 10.9247C101.105 10.4219 101.431 10.0369 101.846 9.76989C102.261 9.50284 102.731 9.36932 103.257 9.36932C103.663 9.36932 103.99 9.4375 104.237 9.57386C104.487 9.70739 104.68 9.86364 104.816 10.0426C104.956 10.2216 105.064 10.3793 105.14 10.5156H105.217V7.27273H106.491V16H105.247V14.9815H105.14C105.064 15.1207 104.953 15.2798 104.808 15.4588C104.666 15.6378 104.47 15.794 104.22 15.9276C103.97 16.0611 103.646 16.1278 103.248 16.1278ZM103.529 15.0412C103.896 15.0412 104.206 14.9446 104.458 14.7514C104.714 14.5554 104.907 14.2841 105.038 13.9375C105.172 13.5909 105.238 13.1875 105.238 12.7273C105.238 12.2727 105.173 11.875 105.042 11.5341C104.912 11.1932 104.72 10.9276 104.467 10.7372C104.214 10.5469 103.902 10.4517 103.529 10.4517C103.146 10.4517 102.826 10.5511 102.571 10.75C102.315 10.9489 102.122 11.2202 101.991 11.5639C101.863 11.9077 101.799 12.2955 101.799 12.7273C101.799 13.1648 101.865 13.5582 101.995 13.9077C102.126 14.2571 102.319 14.5341 102.575 14.7386C102.833 14.9403 103.152 15.0412 103.529 15.0412Z", fill: "#D92D20" })
|
|
2510
|
+
] });
|
|
2511
|
+
}
|
|
2512
|
+
|
|
2513
|
+
// src/components/Badge/Badge.tsx
|
|
2514
|
+
import { jsx as jsx19, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2515
|
+
var Badge = memo3(function Badge2({ variant, label }) {
|
|
2516
|
+
if (variant === "uploading") return /* @__PURE__ */ jsx19(UploadingIcon, {});
|
|
2517
|
+
if (variant === "analysing") return /* @__PURE__ */ jsx19(AnalysingIcon, {});
|
|
2518
|
+
if (variant === "upload_failure") return /* @__PURE__ */ jsx19(FailedUploadIcon, {});
|
|
2519
|
+
return /* @__PURE__ */ jsxs17("span", { className: "mr-badge mr-badge--smart", children: [
|
|
2520
|
+
/* @__PURE__ */ jsx19(Star, { className: "mr-badge__icon", "aria-hidden": true }),
|
|
2521
|
+
label
|
|
2522
|
+
] });
|
|
2523
|
+
});
|
|
2524
|
+
|
|
2525
|
+
// src/components/IconButton/IconButton.tsx
|
|
2526
|
+
import { memo as memo4 } from "react";
|
|
2527
|
+
import { jsx as jsx20 } from "react/jsx-runtime";
|
|
2528
|
+
var IconButton = memo4(function IconButton2({
|
|
2529
|
+
icon,
|
|
2530
|
+
variant = "default",
|
|
2531
|
+
disabled,
|
|
2532
|
+
onClick,
|
|
2533
|
+
title,
|
|
2534
|
+
"aria-label": ariaLabel
|
|
2535
|
+
}) {
|
|
2536
|
+
return /* @__PURE__ */ jsx20(
|
|
2537
|
+
"button",
|
|
2538
|
+
{
|
|
2539
|
+
type: "button",
|
|
2540
|
+
className: `mr-icon-button mr-icon-button--${variant}`,
|
|
2541
|
+
"aria-label": ariaLabel,
|
|
2542
|
+
title,
|
|
2543
|
+
disabled,
|
|
2544
|
+
onClick,
|
|
2545
|
+
children: icon
|
|
2546
|
+
}
|
|
2547
|
+
);
|
|
2548
|
+
});
|
|
2549
|
+
|
|
2550
|
+
// src/components/TagChip/TagChip.tsx
|
|
2551
|
+
import { memo as memo5 } from "react";
|
|
2552
|
+
import { X as X3 } from "lucide-react";
|
|
2553
|
+
import { jsx as jsx21, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
2554
|
+
var TagChip = memo5(function TagChip2({ label, removable, onRemove, onClick }) {
|
|
2555
|
+
return /* @__PURE__ */ jsxs18("span", { className: "mr-tag-chip", onClick, children: [
|
|
2556
|
+
/* @__PURE__ */ jsx21("span", { className: "mr-tag-chip__label", children: label }),
|
|
2557
|
+
removable && /* @__PURE__ */ jsx21(
|
|
2558
|
+
"button",
|
|
2559
|
+
{
|
|
2560
|
+
type: "button",
|
|
2561
|
+
className: "mr-tag-chip__remove",
|
|
2562
|
+
"aria-label": `Remove ${label}`,
|
|
2563
|
+
onClick: (e) => {
|
|
2564
|
+
e.stopPropagation();
|
|
2565
|
+
onRemove?.();
|
|
2566
|
+
},
|
|
2567
|
+
children: /* @__PURE__ */ jsx21(X3, { size: 12, "aria-hidden": true })
|
|
2568
|
+
}
|
|
2569
|
+
)
|
|
2570
|
+
] });
|
|
2571
|
+
});
|
|
2572
|
+
|
|
2573
|
+
// src/components/Thumbnail/Thumbnail.tsx
|
|
2574
|
+
import { memo as memo6, useEffect as useEffect12, useRef as useRef10, useState as useState10 } from "react";
|
|
2575
|
+
import { jsx as jsx22, jsxs as jsxs19 } from "react/jsx-runtime";
|
|
2576
|
+
var blobCache = /* @__PURE__ */ new Map();
|
|
2577
|
+
var Thumbnail = memo6(function Thumbnail2({ url, size, alt }) {
|
|
2578
|
+
const wrapRef = useRef10(null);
|
|
2579
|
+
const canvasRef = useRef10(null);
|
|
2580
|
+
const bitmapRef = useRef10(null);
|
|
2581
|
+
const [decoded, setDecoded] = useState10(false);
|
|
2582
|
+
const [errored, setErrored] = useState10(false);
|
|
2583
|
+
const decodedUrlRef = useRef10(null);
|
|
2584
|
+
useEffect12(() => {
|
|
2585
|
+
if (url && decoded && decodedUrlRef.current !== null) return;
|
|
2586
|
+
setErrored(false);
|
|
2587
|
+
if (!url) {
|
|
2588
|
+
setDecoded(false);
|
|
2589
|
+
return;
|
|
2590
|
+
}
|
|
2591
|
+
let cancelled = false;
|
|
2592
|
+
const controller = new AbortController();
|
|
2593
|
+
const paint = (bitmap) => {
|
|
2594
|
+
const canvas = canvasRef.current;
|
|
2595
|
+
if (!canvas) return;
|
|
2596
|
+
canvas.width = bitmap.width;
|
|
2597
|
+
canvas.height = bitmap.height;
|
|
2598
|
+
const bmpCtx = canvas.getContext("bitmaprenderer");
|
|
2599
|
+
if (bmpCtx) {
|
|
2600
|
+
bmpCtx.transferFromImageBitmap(bitmap);
|
|
2601
|
+
bitmapRef.current = null;
|
|
2602
|
+
} else {
|
|
2603
|
+
const ctx2d = canvas.getContext("2d");
|
|
2604
|
+
ctx2d?.drawImage(bitmap, 0, 0);
|
|
2605
|
+
bitmap.close();
|
|
2606
|
+
bitmapRef.current = null;
|
|
2607
|
+
}
|
|
2608
|
+
setDecoded(true);
|
|
2609
|
+
};
|
|
2610
|
+
const nextFrame = () => new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
2611
|
+
(async () => {
|
|
2612
|
+
try {
|
|
2613
|
+
let blob = blobCache.get(url) ?? null;
|
|
2614
|
+
if (!blob) {
|
|
2615
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
2616
|
+
if (!res.ok) throw new Error(`thumbnail fetch ${res.status}`);
|
|
2617
|
+
blob = await res.blob();
|
|
2618
|
+
blobCache.set(url, blob);
|
|
2619
|
+
}
|
|
2620
|
+
if (cancelled) return;
|
|
2621
|
+
const probe = await createImageBitmap(blob);
|
|
2622
|
+
if (cancelled) {
|
|
2623
|
+
probe.close();
|
|
2624
|
+
return;
|
|
2625
|
+
}
|
|
2626
|
+
await nextFrame();
|
|
2627
|
+
if (cancelled) {
|
|
2628
|
+
probe.close();
|
|
2629
|
+
return;
|
|
2630
|
+
}
|
|
2631
|
+
const dpr = typeof window === "undefined" ? 1 : window.devicePixelRatio || 1;
|
|
2632
|
+
const box = wrapRef.current;
|
|
2633
|
+
const boxW = size || box?.clientWidth || probe.width;
|
|
2634
|
+
const boxH = size || box?.clientHeight || probe.height;
|
|
2635
|
+
const boxRatio = boxW > 0 && boxH > 0 ? boxW / boxH : probe.width / probe.height;
|
|
2636
|
+
const srcRatio = probe.width / probe.height;
|
|
2637
|
+
let sw = probe.width;
|
|
2638
|
+
let sh = probe.height;
|
|
2639
|
+
if (srcRatio > boxRatio) {
|
|
2640
|
+
sw = Math.max(1, Math.round(probe.height * boxRatio));
|
|
2641
|
+
} else {
|
|
2642
|
+
sh = Math.max(1, Math.round(probe.width / boxRatio));
|
|
2643
|
+
}
|
|
2644
|
+
const sx = Math.round((probe.width - sw) / 2);
|
|
2645
|
+
const sy = 0;
|
|
2646
|
+
const targetW = Math.max(1, Math.round(boxW * dpr));
|
|
2647
|
+
const targetH = Math.max(1, Math.round(boxH * dpr));
|
|
2648
|
+
const bitmap = await createImageBitmap(blob, sx, sy, sw, sh, {
|
|
2649
|
+
resizeWidth: targetW,
|
|
2650
|
+
resizeHeight: targetH,
|
|
2651
|
+
resizeQuality: "high"
|
|
2652
|
+
});
|
|
2653
|
+
probe.close();
|
|
2654
|
+
if (cancelled) {
|
|
2655
|
+
bitmap.close();
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
bitmapRef.current = bitmap;
|
|
2659
|
+
decodedUrlRef.current = url;
|
|
2660
|
+
paint(bitmap);
|
|
2661
|
+
} catch (err) {
|
|
2662
|
+
if (cancelled || err instanceof DOMException && err.name === "AbortError") return;
|
|
2663
|
+
setErrored(true);
|
|
2664
|
+
}
|
|
2665
|
+
})();
|
|
2666
|
+
return () => {
|
|
2667
|
+
cancelled = true;
|
|
2668
|
+
controller.abort();
|
|
2669
|
+
bitmapRef.current?.close();
|
|
2670
|
+
bitmapRef.current = null;
|
|
2671
|
+
};
|
|
2672
|
+
}, [url, size]);
|
|
2673
|
+
const style = size ? { width: size, height: size } : void 0;
|
|
2674
|
+
if (!url || errored) {
|
|
2675
|
+
return /* @__PURE__ */ jsx22("div", { className: "mr-thumbnail mr-thumbnail--empty", style, role: "img", "aria-label": alt ?? "", children: /* @__PURE__ */ jsx22(ThumbnailFallbackIcon, {}) });
|
|
2676
|
+
}
|
|
2677
|
+
return /* @__PURE__ */ jsxs19("div", { ref: wrapRef, className: "mr-thumbnail", style, role: "img", "aria-label": alt ?? "", children: [
|
|
2678
|
+
!decoded && /* @__PURE__ */ jsx22("div", { className: "mr-thumbnail__placeholder mr-skeleton" }),
|
|
2679
|
+
/* @__PURE__ */ jsx22(
|
|
2680
|
+
"canvas",
|
|
2681
|
+
{
|
|
2682
|
+
ref: canvasRef,
|
|
2683
|
+
className: `mr-thumbnail__img${decoded ? " mr-thumbnail__img--ready" : ""}`,
|
|
2684
|
+
"aria-hidden": true
|
|
2685
|
+
}
|
|
2686
|
+
)
|
|
2687
|
+
] });
|
|
2688
|
+
});
|
|
2689
|
+
function ThumbnailFallbackIcon() {
|
|
2690
|
+
return /* @__PURE__ */ jsxs19(
|
|
2691
|
+
"svg",
|
|
2692
|
+
{
|
|
2693
|
+
className: "mr-thumbnail__fallback-icon",
|
|
2694
|
+
viewBox: "0 0 46 46",
|
|
2695
|
+
fill: "none",
|
|
2696
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2697
|
+
"aria-hidden": true,
|
|
2698
|
+
children: [
|
|
2699
|
+
/* @__PURE__ */ jsx22(
|
|
2700
|
+
"path",
|
|
2701
|
+
{
|
|
2702
|
+
d: "M26.8333 3.83333H11.5C9.38433 3.83333 7.66667 5.55099 7.66667 7.66667V38.3333C7.66667 40.449 9.38433 42.1667 11.5 42.1667H34.5C36.6157 42.1667 38.3333 40.449 38.3333 38.3333V15.3333L26.8333 3.83333",
|
|
2703
|
+
stroke: "currentColor",
|
|
2704
|
+
strokeWidth: "3.06667",
|
|
2705
|
+
strokeLinecap: "round"
|
|
2706
|
+
}
|
|
2707
|
+
),
|
|
2708
|
+
/* @__PURE__ */ jsx22(
|
|
2709
|
+
"path",
|
|
2710
|
+
{
|
|
2711
|
+
d: "M26.8333 3.83333V15.3333H38.3333",
|
|
2712
|
+
stroke: "currentColor",
|
|
2713
|
+
strokeWidth: "3.06667",
|
|
2714
|
+
strokeLinecap: "round"
|
|
2715
|
+
}
|
|
2716
|
+
),
|
|
2717
|
+
/* @__PURE__ */ jsx22("path", { d: "M17.25 24.9167H28.75", stroke: "currentColor", strokeWidth: "3.06667", strokeLinecap: "round" }),
|
|
2718
|
+
/* @__PURE__ */ jsx22("path", { d: "M17.25 32.5833H24.9167", stroke: "currentColor", strokeWidth: "3.06667", strokeLinecap: "round" })
|
|
2719
|
+
]
|
|
2720
|
+
}
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2724
|
+
// src/components/OverflowMenu/OverflowMenu.tsx
|
|
2725
|
+
import { useEffect as useEffect13, useRef as useRef11, useState as useState11 } from "react";
|
|
2726
|
+
import { createPortal as createPortal6 } from "react-dom";
|
|
2727
|
+
import { ChevronLeft as ChevronLeft3, EllipsisVertical } from "lucide-react";
|
|
2728
|
+
import { Fragment as Fragment2, jsx as jsx23, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
2729
|
+
var ITEM_HEIGHT = 36;
|
|
2730
|
+
var MENU_PADDING = 8;
|
|
2731
|
+
var GAP = 4;
|
|
2732
|
+
function OverflowMenu({ items, "aria-label": ariaLabel = "More options" }) {
|
|
2733
|
+
const [coords, setCoords] = useState11(null);
|
|
2734
|
+
const [activeSubPanel, setActiveSubPanel] = useState11(null);
|
|
2735
|
+
const triggerRef = useRef11(null);
|
|
2736
|
+
const menuRef = useRef11(null);
|
|
2737
|
+
const open = coords !== null;
|
|
2738
|
+
const close = () => {
|
|
2739
|
+
setCoords(null);
|
|
2740
|
+
setActiveSubPanel(null);
|
|
2741
|
+
};
|
|
2742
|
+
const place = () => {
|
|
2743
|
+
const el = triggerRef.current;
|
|
2744
|
+
if (!el) return;
|
|
2745
|
+
const r = el.getBoundingClientRect();
|
|
2746
|
+
const right = window.innerWidth - r.right;
|
|
2747
|
+
const estHeight = items.length * ITEM_HEIGHT + MENU_PADDING;
|
|
2748
|
+
const spaceBelow = window.innerHeight - r.bottom;
|
|
2749
|
+
if (spaceBelow < estHeight + GAP && r.top > estHeight + GAP) {
|
|
2750
|
+
setCoords({ right, bottom: window.innerHeight - r.top + GAP });
|
|
2751
|
+
} else {
|
|
2752
|
+
setCoords({ right, top: r.bottom + GAP });
|
|
2753
|
+
}
|
|
2754
|
+
};
|
|
2755
|
+
useEffect13(() => {
|
|
2756
|
+
if (!open) return;
|
|
2757
|
+
const onDown = (e) => {
|
|
2758
|
+
const node = e.target;
|
|
2759
|
+
if (triggerRef.current?.contains(node) || menuRef.current?.contains(node)) return;
|
|
2760
|
+
if (node.closest?.("[data-mr-portal]")) return;
|
|
2761
|
+
close();
|
|
2762
|
+
};
|
|
2763
|
+
const onKey = (e) => {
|
|
2764
|
+
if (e.key === "Escape") close();
|
|
2765
|
+
};
|
|
2766
|
+
document.addEventListener("mousedown", onDown);
|
|
2767
|
+
document.addEventListener("keydown", onKey);
|
|
2768
|
+
window.addEventListener("scroll", close, true);
|
|
2769
|
+
return () => {
|
|
2770
|
+
document.removeEventListener("mousedown", onDown);
|
|
2771
|
+
document.removeEventListener("keydown", onKey);
|
|
2772
|
+
window.removeEventListener("scroll", close, true);
|
|
2773
|
+
};
|
|
2774
|
+
}, [open]);
|
|
2775
|
+
const activeItem = activeSubPanel ? items.find((i) => i.key === activeSubPanel) : null;
|
|
2776
|
+
return /* @__PURE__ */ jsxs20(Fragment2, { children: [
|
|
2777
|
+
/* @__PURE__ */ jsx23(
|
|
2778
|
+
"button",
|
|
2779
|
+
{
|
|
2780
|
+
ref: triggerRef,
|
|
2781
|
+
type: "button",
|
|
2782
|
+
className: `mr-overflow-btn${open ? " mr-overflow-btn--active" : ""}`,
|
|
2783
|
+
"aria-label": ariaLabel,
|
|
2784
|
+
"aria-haspopup": "menu",
|
|
2785
|
+
"aria-expanded": open,
|
|
2786
|
+
onClick: (e) => {
|
|
2787
|
+
e.stopPropagation();
|
|
2788
|
+
if (open) close();
|
|
2789
|
+
else place();
|
|
2790
|
+
},
|
|
2791
|
+
children: /* @__PURE__ */ jsx23(EllipsisVertical, { size: 16, "aria-hidden": true })
|
|
2792
|
+
}
|
|
2793
|
+
),
|
|
2794
|
+
open && typeof document !== "undefined" && createPortal6(
|
|
2795
|
+
/* @__PURE__ */ jsx23(
|
|
2796
|
+
"div",
|
|
2797
|
+
{
|
|
2798
|
+
ref: menuRef,
|
|
2799
|
+
className: "mr-overflow-menu-wrap",
|
|
2800
|
+
"data-mr-portal": true,
|
|
2801
|
+
style: { top: coords.top, bottom: coords.bottom, right: coords.right },
|
|
2802
|
+
onClick: (e) => e.stopPropagation(),
|
|
2803
|
+
children: activeItem?.subPanel ? /* @__PURE__ */ jsxs20("div", { className: "mr-overflow-subpanel", children: [
|
|
2804
|
+
/* @__PURE__ */ jsx23("div", { className: "mr-overflow-subpanel__back", children: /* @__PURE__ */ jsxs20(
|
|
2805
|
+
"button",
|
|
2806
|
+
{
|
|
2807
|
+
type: "button",
|
|
2808
|
+
className: "mr-overflow-subpanel__back-btn",
|
|
2809
|
+
onClick: () => setActiveSubPanel(null),
|
|
2810
|
+
children: [
|
|
2811
|
+
/* @__PURE__ */ jsx23(ChevronLeft3, { size: 16, "aria-hidden": true }),
|
|
2812
|
+
"Back"
|
|
2813
|
+
]
|
|
2814
|
+
}
|
|
2815
|
+
) }),
|
|
2816
|
+
activeItem.subPanel(() => setActiveSubPanel(null), close)
|
|
2817
|
+
] }) : /* @__PURE__ */ jsx23("ul", { className: "mr-overflow-menu", role: "menu", children: items.map((item) => /* @__PURE__ */ jsx23("li", { children: /* @__PURE__ */ jsxs20(
|
|
2818
|
+
"button",
|
|
2819
|
+
{
|
|
2820
|
+
type: "button",
|
|
2821
|
+
role: "menuitem",
|
|
2822
|
+
className: `mr-overflow-menu__item${item.destructive ? " mr-overflow-menu__item--destructive" : ""}`,
|
|
2823
|
+
onClick: (e) => {
|
|
2824
|
+
e.stopPropagation();
|
|
2825
|
+
if (item.subPanel) {
|
|
2826
|
+
setActiveSubPanel(item.key);
|
|
2827
|
+
} else if (item.onSelect) {
|
|
2828
|
+
const triggerRect = triggerRef.current?.getBoundingClientRect() ?? new DOMRect();
|
|
2829
|
+
close();
|
|
2830
|
+
item.onSelect(triggerRect);
|
|
2831
|
+
}
|
|
2832
|
+
},
|
|
2833
|
+
children: [
|
|
2834
|
+
item.icon && /* @__PURE__ */ jsx23("span", { className: "mr-overflow-menu__icon", children: item.icon }),
|
|
2835
|
+
item.label
|
|
2836
|
+
]
|
|
2837
|
+
}
|
|
2838
|
+
) }, item.key)) })
|
|
2839
|
+
}
|
|
2840
|
+
),
|
|
2841
|
+
document.body
|
|
2842
|
+
)
|
|
2843
|
+
] });
|
|
2844
|
+
}
|
|
2845
|
+
|
|
2846
|
+
// src/components/icons/AttachContextIcon.tsx
|
|
2847
|
+
import { jsx as jsx24, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
2848
|
+
function AttachContextIcon({ size = 28 }) {
|
|
2849
|
+
return /* @__PURE__ */ jsxs21("span", { className: "mr-attach-orbit", style: { width: size, height: size }, children: [
|
|
2850
|
+
/* @__PURE__ */ jsx24("span", { className: "mr-attach-orbit__ring", "aria-hidden": true }),
|
|
2851
|
+
/* @__PURE__ */ jsx24("span", { className: "mr-attach-orbit__face", children: /* @__PURE__ */ jsx24(
|
|
2852
|
+
"svg",
|
|
2853
|
+
{
|
|
2854
|
+
width: "16",
|
|
2855
|
+
height: "16",
|
|
2856
|
+
viewBox: "0 0 16 16",
|
|
2857
|
+
fill: "none",
|
|
2858
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2859
|
+
"aria-hidden": true,
|
|
2860
|
+
children: /* @__PURE__ */ jsx24(
|
|
2861
|
+
"path",
|
|
2862
|
+
{
|
|
2863
|
+
d: "M9.3333 1.3335V4.0002C9.3333 4.3538 9.4738 4.6929 9.7238 4.943C9.9739 5.193 10.313 5.3335 10.6667 5.3335H13.3333M6 10.0002H10M8 12.0002V8.0002M10 1.3335H3.99999C3.64637 1.3335 3.30723 1.47397 3.05718 1.72402C2.80713 1.97407 2.66666 2.31321 2.66666 2.66683V13.3335C2.66666 13.6871 2.80713 14.0263 3.05718 14.2763C3.30723 14.5264 3.64637 14.6668 3.99999 14.6668H12C12.3536 14.6668 12.6928 14.5264 12.9428 14.2763C13.1928 14.0263 13.3333 13.6871 13.3333 13.3335V4.6668L10 1.3335Z",
|
|
2864
|
+
stroke: "#215FFF",
|
|
2865
|
+
strokeLinecap: "round",
|
|
2866
|
+
strokeLinejoin: "round"
|
|
2867
|
+
}
|
|
2868
|
+
)
|
|
2869
|
+
}
|
|
2870
|
+
) })
|
|
2871
|
+
] });
|
|
2872
|
+
}
|
|
2873
|
+
|
|
2874
|
+
// src/views/RecordsView/AddToContextSubPanel.tsx
|
|
2875
|
+
import { useEffect as useEffect14, useMemo as useMemo8, useRef as useRef12, useState as useState12 } from "react";
|
|
2876
|
+
import { createPortal as createPortal7 } from "react-dom";
|
|
2877
|
+
import { useStore as useStore9 } from "zustand";
|
|
2878
|
+
import { Check as Check4, Search as Search3, Plus as Plus3, ChevronsUpDown as ChevronsUpDown3 } from "lucide-react";
|
|
2879
|
+
|
|
2880
|
+
// src/views/RecordsView/RecordsActionsContext.ts
|
|
2881
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
2882
|
+
var RecordsActionsContext = createContext2({});
|
|
2883
|
+
var RecordsActionsProvider = RecordsActionsContext.Provider;
|
|
2884
|
+
function useRecordsActions() {
|
|
2885
|
+
return useContext2(RecordsActionsContext);
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
// src/views/RecordsView/AddToContextSubPanel.tsx
|
|
2889
|
+
import { Fragment as Fragment3, jsx as jsx25, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
2890
|
+
var CASE_TYPE_OPTIONS2 = [
|
|
2891
|
+
{ value: "OP", label: "Out-patient" },
|
|
2892
|
+
{ value: "IP", label: "In-patient" },
|
|
2893
|
+
{ value: "EM", label: "Emergency" },
|
|
2894
|
+
{ value: "HH", label: "Home Health" },
|
|
2895
|
+
{ value: "DC", label: "Day Care" }
|
|
2896
|
+
];
|
|
2897
|
+
var todayISO2 = () => (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
2898
|
+
function AddToContextSubPanel({
|
|
2899
|
+
recordId,
|
|
2900
|
+
linkedCaseIds,
|
|
2901
|
+
onClose
|
|
2902
|
+
}) {
|
|
2903
|
+
const { store } = useSdk();
|
|
2904
|
+
const { createCase } = useCasesConnection();
|
|
2905
|
+
const { editRecord } = useRecordsConnection();
|
|
2906
|
+
const { onToast } = useRecordsActions();
|
|
2907
|
+
const caseIds = useStore9(store, (s) => s.cases.ids);
|
|
2908
|
+
const casesById = useStore9(store, (s) => s.cases.byId);
|
|
2909
|
+
const cases = useMemo8(
|
|
2910
|
+
() => caseIds.map((id) => casesById[id]).filter(Boolean),
|
|
2911
|
+
[caseIds, casesById]
|
|
2912
|
+
);
|
|
2913
|
+
const [selected, setSelected] = useState12(
|
|
2914
|
+
linkedCaseIds.length > 0 ? linkedCaseIds[0] : null
|
|
2915
|
+
);
|
|
2916
|
+
const [dropPos, setDropPos] = useState12(null);
|
|
2917
|
+
const [query, setQuery] = useState12("");
|
|
2918
|
+
const [creating, setCreating] = useState12(false);
|
|
2919
|
+
const [newName, setNewName] = useState12("");
|
|
2920
|
+
const [newType, setNewType] = useState12("OP");
|
|
2921
|
+
const [newDate, setNewDate] = useState12(todayISO2());
|
|
2922
|
+
const [saving, setSaving] = useState12(false);
|
|
2923
|
+
const fieldRef = useRef12(null);
|
|
2924
|
+
const dropRef = useRef12(null);
|
|
2925
|
+
const dropOpen = dropPos !== null;
|
|
2926
|
+
const selectedCase = selected ? casesById[selected] : null;
|
|
2927
|
+
const filtered = useMemo8(() => {
|
|
2928
|
+
const q = query.trim().toLowerCase();
|
|
2929
|
+
return q ? cases.filter((c) => c.name.toLowerCase().includes(q)) : cases;
|
|
2930
|
+
}, [cases, query]);
|
|
2931
|
+
const openDrop = () => {
|
|
2932
|
+
const el = fieldRef.current;
|
|
2933
|
+
if (!el) return;
|
|
2934
|
+
const r = el.getBoundingClientRect();
|
|
2935
|
+
const MARGIN = 16;
|
|
2936
|
+
const GAP2 = 4;
|
|
2937
|
+
const spaceBelow = window.innerHeight - r.bottom - MARGIN;
|
|
2938
|
+
const spaceAbove = r.top - MARGIN;
|
|
2939
|
+
if (spaceAbove > spaceBelow && spaceAbove >= 120) {
|
|
2940
|
+
const maxH = Math.min(280, spaceAbove);
|
|
2941
|
+
setDropPos({ bottom: window.innerHeight - r.top + GAP2, left: r.left, width: r.width, maxH });
|
|
2942
|
+
} else {
|
|
2943
|
+
const maxH = Math.min(280, Math.max(120, spaceBelow));
|
|
2944
|
+
setDropPos({ top: r.bottom + GAP2, left: r.left, width: r.width, maxH });
|
|
2945
|
+
}
|
|
2946
|
+
};
|
|
2947
|
+
useEffect14(() => {
|
|
2948
|
+
if (!dropOpen) {
|
|
2949
|
+
setQuery("");
|
|
2950
|
+
setCreating(false);
|
|
2951
|
+
setNewName("");
|
|
2952
|
+
return;
|
|
2953
|
+
}
|
|
2954
|
+
const onDown = (e) => {
|
|
2955
|
+
const t = e.target;
|
|
2956
|
+
if (fieldRef.current?.contains(t) || dropRef.current?.contains(t)) return;
|
|
2957
|
+
if (t.closest?.("[data-mr-portal]")) return;
|
|
2958
|
+
setDropPos(null);
|
|
2959
|
+
};
|
|
2960
|
+
document.addEventListener("mousedown", onDown);
|
|
2961
|
+
return () => document.removeEventListener("mousedown", onDown);
|
|
2962
|
+
}, [dropOpen]);
|
|
2963
|
+
const handleAdd = async () => {
|
|
2964
|
+
if (!selected) return;
|
|
2965
|
+
try {
|
|
2966
|
+
await editRecord(recordId, { cases: [selected] });
|
|
2967
|
+
onToast?.(`Moved to ${selectedCase?.name ?? "care context"}`, "success");
|
|
2968
|
+
onClose();
|
|
2969
|
+
} catch {
|
|
2970
|
+
onToast?.("Failed to add to care context", "error");
|
|
2971
|
+
}
|
|
2972
|
+
};
|
|
2973
|
+
const handleCreate = async () => {
|
|
2974
|
+
const name = newName.trim();
|
|
2975
|
+
if (!name) return;
|
|
2976
|
+
setSaving(true);
|
|
2977
|
+
try {
|
|
2978
|
+
const occurred_at = newDate ? Math.floor((/* @__PURE__ */ new Date(newDate + "T00:00:00")).getTime() / 1e3) : void 0;
|
|
2979
|
+
const id = await createCase({ display_name: name, type: newType, occurred_at });
|
|
2980
|
+
await editRecord(recordId, { cases: [id] });
|
|
2981
|
+
onToast?.(`Created and added to "${name}"`, "success");
|
|
2982
|
+
onClose();
|
|
2983
|
+
} catch {
|
|
2984
|
+
onToast?.("Failed to create care context", "error");
|
|
2985
|
+
} finally {
|
|
2986
|
+
setSaving(false);
|
|
2987
|
+
}
|
|
2988
|
+
};
|
|
2989
|
+
return /* @__PURE__ */ jsxs22("div", { className: "mr-ctx-subpanel", children: [
|
|
2990
|
+
/* @__PURE__ */ jsxs22("div", { className: "mr-ctx-subpanel__body", children: [
|
|
2991
|
+
/* @__PURE__ */ jsx25("p", { className: "mr-ctx-subpanel__label", children: "Adding to care context" }),
|
|
2992
|
+
/* @__PURE__ */ jsxs22(
|
|
2993
|
+
"button",
|
|
2994
|
+
{
|
|
2995
|
+
ref: fieldRef,
|
|
2996
|
+
type: "button",
|
|
2997
|
+
className: `mr-ctx-subpanel__field${dropOpen ? " mr-ctx-subpanel__field--open" : ""}`,
|
|
2998
|
+
onClick: () => dropOpen ? setDropPos(null) : openDrop(),
|
|
2999
|
+
children: [
|
|
3000
|
+
/* @__PURE__ */ jsx25("span", { className: selectedCase ? "mr-ctx-subpanel__field-value" : "mr-ctx-subpanel__field-placeholder", children: selectedCase?.name ?? "Search or select" }),
|
|
3001
|
+
/* @__PURE__ */ jsx25(ChevronsUpDown3, { size: 16, "aria-hidden": true, className: "mr-ctx-subpanel__field-chevron" })
|
|
3002
|
+
]
|
|
3003
|
+
}
|
|
3004
|
+
)
|
|
3005
|
+
] }),
|
|
3006
|
+
/* @__PURE__ */ jsx25("div", { className: "mr-ctx-subpanel__footer", children: /* @__PURE__ */ jsx25(
|
|
3007
|
+
"button",
|
|
3008
|
+
{
|
|
3009
|
+
type: "button",
|
|
3010
|
+
className: "mr-ctx-subpanel__add-btn",
|
|
3011
|
+
disabled: !selected || linkedCaseIds.length === 1 && linkedCaseIds[0] === selected,
|
|
3012
|
+
onClick: () => void handleAdd(),
|
|
3013
|
+
children: "Add to care context"
|
|
3014
|
+
}
|
|
3015
|
+
) }),
|
|
3016
|
+
dropOpen && typeof document !== "undefined" && createPortal7(
|
|
3017
|
+
/* @__PURE__ */ jsx25(
|
|
3018
|
+
"div",
|
|
3019
|
+
{
|
|
3020
|
+
ref: dropRef,
|
|
3021
|
+
className: "mr-ctx-subpanel__drop",
|
|
3022
|
+
"data-mr-portal": true,
|
|
3023
|
+
style: {
|
|
3024
|
+
...dropPos.top !== void 0 ? { top: dropPos.top } : { bottom: dropPos.bottom },
|
|
3025
|
+
left: dropPos.left,
|
|
3026
|
+
width: dropPos.width,
|
|
3027
|
+
maxHeight: dropPos.maxH
|
|
3028
|
+
},
|
|
3029
|
+
children: !creating ? /* @__PURE__ */ jsxs22(Fragment3, { children: [
|
|
3030
|
+
/* @__PURE__ */ jsxs22("div", { className: "mr-ctx-subpanel__search-row", children: [
|
|
3031
|
+
/* @__PURE__ */ jsx25(Search3, { size: 14, className: "mr-ctx-subpanel__search-icon", "aria-hidden": true }),
|
|
3032
|
+
/* @__PURE__ */ jsx25(
|
|
3033
|
+
"input",
|
|
3034
|
+
{
|
|
3035
|
+
type: "text",
|
|
3036
|
+
className: "mr-ctx-subpanel__search-input",
|
|
3037
|
+
placeholder: "Search care context...",
|
|
3038
|
+
autoFocus: true,
|
|
3039
|
+
value: query,
|
|
3040
|
+
onChange: (e) => setQuery(e.target.value)
|
|
3041
|
+
}
|
|
3042
|
+
)
|
|
3043
|
+
] }),
|
|
3044
|
+
/* @__PURE__ */ jsx25("ul", { className: "mr-ctx-subpanel__list", children: filtered.length === 0 ? /* @__PURE__ */ jsx25("li", { className: "mr-ctx-subpanel__empty", children: "No cases found" }) : filtered.map((c) => {
|
|
3045
|
+
const isCurrent = linkedCaseIds.includes(c.id);
|
|
3046
|
+
return /* @__PURE__ */ jsx25("li", { children: /* @__PURE__ */ jsxs22(
|
|
3047
|
+
"button",
|
|
3048
|
+
{
|
|
3049
|
+
type: "button",
|
|
3050
|
+
className: `mr-ctx-subpanel__option${selected === c.id ? " mr-ctx-subpanel__option--active" : ""}`,
|
|
3051
|
+
onClick: () => {
|
|
3052
|
+
setSelected(c.id);
|
|
3053
|
+
setDropPos(null);
|
|
3054
|
+
},
|
|
3055
|
+
children: [
|
|
3056
|
+
/* @__PURE__ */ jsx25("span", { children: c.name }),
|
|
3057
|
+
isCurrent ? /* @__PURE__ */ jsx25("span", { className: "mr-ctx-subpanel__option-tag", children: "Current" }) : selected === c.id && /* @__PURE__ */ jsx25(Check4, { size: 14, "aria-hidden": true })
|
|
3058
|
+
]
|
|
3059
|
+
}
|
|
3060
|
+
) }, c.id);
|
|
3061
|
+
}) }),
|
|
3062
|
+
/* @__PURE__ */ jsx25("div", { className: "mr-ctx-subpanel__panel-footer", children: /* @__PURE__ */ jsxs22(
|
|
3063
|
+
"button",
|
|
3064
|
+
{
|
|
3065
|
+
type: "button",
|
|
3066
|
+
className: "mr-ctx-subpanel__create-btn",
|
|
3067
|
+
onClick: () => setCreating(true),
|
|
3068
|
+
children: [
|
|
3069
|
+
/* @__PURE__ */ jsx25(Plus3, { size: 14, "aria-hidden": true }),
|
|
3070
|
+
"Add new care context"
|
|
3071
|
+
]
|
|
3072
|
+
}
|
|
3073
|
+
) })
|
|
3074
|
+
] }) : /* @__PURE__ */ jsxs22("div", { className: "mr-ctx-subpanel__create-form", children: [
|
|
3075
|
+
/* @__PURE__ */ jsx25(
|
|
3076
|
+
"input",
|
|
3077
|
+
{
|
|
3078
|
+
type: "text",
|
|
3079
|
+
className: "mr-ctx-subpanel__create-input",
|
|
3080
|
+
placeholder: "Case name",
|
|
3081
|
+
autoFocus: true,
|
|
3082
|
+
value: newName,
|
|
3083
|
+
onChange: (e) => setNewName(e.target.value),
|
|
3084
|
+
onKeyDown: (e) => {
|
|
3085
|
+
if (e.key === "Escape") {
|
|
3086
|
+
setCreating(false);
|
|
3087
|
+
setNewName("");
|
|
3088
|
+
}
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
),
|
|
3092
|
+
/* @__PURE__ */ jsx25(
|
|
3093
|
+
PresetSelect,
|
|
3094
|
+
{
|
|
3095
|
+
value: newType,
|
|
3096
|
+
options: CASE_TYPE_OPTIONS2,
|
|
3097
|
+
onChange: setNewType,
|
|
3098
|
+
active: newType !== "OP"
|
|
3099
|
+
}
|
|
3100
|
+
),
|
|
3101
|
+
/* @__PURE__ */ jsx25(
|
|
3102
|
+
"input",
|
|
3103
|
+
{
|
|
3104
|
+
type: "date",
|
|
3105
|
+
className: "mr-ctx-subpanel__create-input",
|
|
3106
|
+
value: newDate,
|
|
3107
|
+
max: todayISO2(),
|
|
3108
|
+
onChange: (e) => setNewDate(e.target.value)
|
|
3109
|
+
}
|
|
3110
|
+
),
|
|
3111
|
+
/* @__PURE__ */ jsxs22("div", { className: "mr-ctx-subpanel__create-actions", children: [
|
|
3112
|
+
/* @__PURE__ */ jsx25(
|
|
3113
|
+
"button",
|
|
3114
|
+
{
|
|
3115
|
+
type: "button",
|
|
3116
|
+
className: "mr-ctx-subpanel__create-cancel",
|
|
3117
|
+
onClick: () => {
|
|
3118
|
+
setCreating(false);
|
|
3119
|
+
setNewName("");
|
|
3120
|
+
},
|
|
3121
|
+
children: "Cancel"
|
|
3122
|
+
}
|
|
3123
|
+
),
|
|
3124
|
+
/* @__PURE__ */ jsx25(
|
|
3125
|
+
"button",
|
|
3126
|
+
{
|
|
3127
|
+
type: "button",
|
|
3128
|
+
className: "mr-ctx-subpanel__create-save",
|
|
3129
|
+
disabled: !newName.trim() || saving,
|
|
3130
|
+
onClick: () => void handleCreate(),
|
|
3131
|
+
children: saving ? "\u2026" : "Create and Add"
|
|
3132
|
+
}
|
|
3133
|
+
)
|
|
3134
|
+
] })
|
|
3135
|
+
] })
|
|
3136
|
+
}
|
|
3137
|
+
),
|
|
3138
|
+
document.body
|
|
3139
|
+
)
|
|
3140
|
+
] });
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
// src/components/RecordCard/RecordCard.tsx
|
|
3144
|
+
import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3145
|
+
var RecordCard = memo7(
|
|
3146
|
+
function RecordCard2({
|
|
3147
|
+
record,
|
|
3148
|
+
selected,
|
|
3149
|
+
selectionMode,
|
|
3150
|
+
thumbnailUrl,
|
|
3151
|
+
inContext,
|
|
3152
|
+
attachDisabled,
|
|
3153
|
+
selectDisabled,
|
|
3154
|
+
isUploading,
|
|
3155
|
+
isUploadFailed,
|
|
3156
|
+
isAnalysing,
|
|
3157
|
+
isSmart,
|
|
3158
|
+
dateDisplay,
|
|
3159
|
+
onSelect,
|
|
3160
|
+
onOpen,
|
|
3161
|
+
onDelete,
|
|
3162
|
+
onAddToContext,
|
|
3163
|
+
onCopyNotes
|
|
3164
|
+
}) {
|
|
3165
|
+
const [firstTag, ...restTags] = record.tags;
|
|
3166
|
+
const overflowItems = useMemo9(() => [
|
|
3167
|
+
{
|
|
3168
|
+
key: "case",
|
|
3169
|
+
label: "Add to care context",
|
|
3170
|
+
icon: /* @__PURE__ */ jsx26(FolderPlus, { size: 16, "aria-hidden": true }),
|
|
3171
|
+
subPanel: (_onBack, onClose) => /* @__PURE__ */ jsx26(
|
|
3172
|
+
AddToContextSubPanel,
|
|
3173
|
+
{
|
|
3174
|
+
recordId: record.id,
|
|
3175
|
+
linkedCaseIds: record.cases,
|
|
3176
|
+
onClose
|
|
3177
|
+
}
|
|
3178
|
+
)
|
|
3179
|
+
},
|
|
3180
|
+
{
|
|
3181
|
+
key: "delete",
|
|
3182
|
+
label: "Delete record",
|
|
3183
|
+
icon: /* @__PURE__ */ jsx26(Trash2, { size: 16, "aria-hidden": true }),
|
|
3184
|
+
destructive: true,
|
|
3185
|
+
onSelect: () => onDelete(record.id)
|
|
3186
|
+
}
|
|
3187
|
+
], [record.id, record.cases, onDelete]);
|
|
3188
|
+
const selectBlocked = selectionMode && selectDisabled && !selected;
|
|
3189
|
+
const handleCardClick = () => {
|
|
3190
|
+
if (isUploading || isUploadFailed) return;
|
|
3191
|
+
if (selectionMode) {
|
|
3192
|
+
if (!selectBlocked) onSelect(record.id);
|
|
3193
|
+
} else {
|
|
3194
|
+
onOpen(record.id);
|
|
3195
|
+
}
|
|
3196
|
+
};
|
|
3197
|
+
const badge = isUploading ? /* @__PURE__ */ jsx26(Badge, { variant: "uploading", label: "Uploading" }) : isUploadFailed ? /* @__PURE__ */ jsx26(Badge, { variant: "upload_failure", label: "Upload failure" }) : isAnalysing ? /* @__PURE__ */ jsx26(Badge, { variant: "analysing", label: "Analysing" }) : isSmart ? /* @__PURE__ */ jsx26(Badge, { variant: "smart", label: "Smart" }) : null;
|
|
3198
|
+
return /* @__PURE__ */ jsxs23(
|
|
3199
|
+
"article",
|
|
3200
|
+
{
|
|
3201
|
+
className: `mr-record-card${selected ? " mr-record-card--selected" : ""}${selectBlocked ? " mr-record-card--disabled" : ""}${isUploadFailed ? " mr-record-card--failed" : ""}`,
|
|
3202
|
+
onClick: handleCardClick,
|
|
3203
|
+
children: [
|
|
3204
|
+
/* @__PURE__ */ jsxs23("header", { className: "mr-record-card__header", children: [
|
|
3205
|
+
selectionMode && !isUploading && !isUploadFailed && /* @__PURE__ */ jsx26(
|
|
3206
|
+
"span",
|
|
3207
|
+
{
|
|
3208
|
+
className: `mr-record-card__checkbox${selected ? " mr-record-card__checkbox--checked" : ""}${selectBlocked ? " mr-record-card__checkbox--disabled" : ""}`,
|
|
3209
|
+
"aria-hidden": true,
|
|
3210
|
+
children: selected && /* @__PURE__ */ jsx26(Check5, { size: 14, strokeWidth: 3 })
|
|
3211
|
+
}
|
|
3212
|
+
),
|
|
3213
|
+
/* @__PURE__ */ jsxs23("div", { className: "mr-record-card__heading", children: [
|
|
3214
|
+
/* @__PURE__ */ jsx26("span", { className: "mr-record-card__title", children: record.title }),
|
|
3215
|
+
/* @__PURE__ */ jsx26("span", { className: "mr-record-card__date", children: dateDisplay })
|
|
3216
|
+
] }),
|
|
3217
|
+
badge
|
|
3218
|
+
] }),
|
|
3219
|
+
/* @__PURE__ */ jsxs23("div", { className: "mr-record-card__preview", children: [
|
|
3220
|
+
/* @__PURE__ */ jsx26(Thumbnail, { url: thumbnailUrl ?? null, alt: record.title }),
|
|
3221
|
+
record.fileType && /* @__PURE__ */ jsx26("span", { className: "mr-record-card__filetype", children: record.fileType })
|
|
3222
|
+
] }),
|
|
3223
|
+
/* @__PURE__ */ jsxs23("footer", { className: "mr-record-card__footer", children: [
|
|
3224
|
+
record.tags.length > 0 ? /* @__PURE__ */ jsxs23("div", { className: "mr-record-card__tags", children: [
|
|
3225
|
+
/* @__PURE__ */ jsx26(TagChip, { label: firstTag }),
|
|
3226
|
+
restTags.length > 0 && /* @__PURE__ */ jsx26(Tooltip, { content: record.tags.join(", "), children: /* @__PURE__ */ jsx26(TagChip, { label: `+${restTags.length}`, onClick: (e) => e.stopPropagation() }) })
|
|
3227
|
+
] }) : /* @__PURE__ */ jsx26("span", { className: "mr-record-card__tags-spacer" }),
|
|
3228
|
+
/* @__PURE__ */ jsxs23("div", { className: "mr-record-card__actions", children: [
|
|
3229
|
+
isUploading && /* @__PURE__ */ jsx26(Tooltip, { content: "Cancel upload", children: /* @__PURE__ */ jsx26(
|
|
3230
|
+
IconButton,
|
|
3231
|
+
{
|
|
3232
|
+
variant: "destructive",
|
|
3233
|
+
"aria-label": "Cancel upload",
|
|
3234
|
+
icon: /* @__PURE__ */ jsx26(Trash2, { size: 16, "aria-hidden": true }),
|
|
3235
|
+
onClick: (e) => {
|
|
3236
|
+
e.stopPropagation();
|
|
3237
|
+
onDelete(record.id);
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
) }),
|
|
3241
|
+
isUploadFailed && /* @__PURE__ */ jsx26(Fragment4, { children: /* @__PURE__ */ jsx26(Tooltip, { content: "Delete record", children: /* @__PURE__ */ jsx26(
|
|
3242
|
+
IconButton,
|
|
3243
|
+
{
|
|
3244
|
+
variant: "destructive",
|
|
3245
|
+
"aria-label": "Delete record",
|
|
3246
|
+
icon: /* @__PURE__ */ jsx26(Trash2, { size: 16, "aria-hidden": true }),
|
|
3247
|
+
onClick: (e) => {
|
|
3248
|
+
e.stopPropagation();
|
|
3249
|
+
onDelete(record.id);
|
|
3250
|
+
}
|
|
3251
|
+
}
|
|
3252
|
+
) }) }),
|
|
3253
|
+
!isUploading && !isUploadFailed && /* @__PURE__ */ jsxs23(Fragment4, { children: [
|
|
3254
|
+
selectionMode ? /* @__PURE__ */ jsx26(Tooltip, { content: "View record", children: /* @__PURE__ */ jsx26(
|
|
3255
|
+
IconButton,
|
|
3256
|
+
{
|
|
3257
|
+
variant: "primary",
|
|
3258
|
+
"aria-label": "View record",
|
|
3259
|
+
icon: /* @__PURE__ */ jsx26(Eye, { size: 16, "aria-hidden": true }),
|
|
3260
|
+
onClick: (e) => {
|
|
3261
|
+
e.stopPropagation();
|
|
3262
|
+
onOpen(record.id);
|
|
3263
|
+
}
|
|
3264
|
+
}
|
|
3265
|
+
) }) : inContext ? /* @__PURE__ */ jsx26(Tooltip, { content: "Remove from Context", children: /* @__PURE__ */ jsx26(
|
|
3266
|
+
IconButton,
|
|
3267
|
+
{
|
|
3268
|
+
variant: "solid",
|
|
3269
|
+
"aria-label": "Remove from Context",
|
|
3270
|
+
icon: /* @__PURE__ */ jsx26(Check5, { size: 16, strokeWidth: 3, "aria-hidden": true }),
|
|
3271
|
+
onClick: (e) => {
|
|
3272
|
+
e.stopPropagation();
|
|
3273
|
+
onAddToContext(record.id);
|
|
3274
|
+
}
|
|
3275
|
+
}
|
|
3276
|
+
) }) : /* @__PURE__ */ jsx26(Tooltip, { content: "Add to session context", children: /* @__PURE__ */ jsx26(
|
|
3277
|
+
"button",
|
|
3278
|
+
{
|
|
3279
|
+
type: "button",
|
|
3280
|
+
className: "mr-attach-context-btn",
|
|
3281
|
+
"aria-label": "Add to care context",
|
|
3282
|
+
disabled: attachDisabled,
|
|
3283
|
+
onClick: (e) => {
|
|
3284
|
+
e.stopPropagation();
|
|
3285
|
+
onAddToContext(record.id);
|
|
3286
|
+
},
|
|
3287
|
+
children: /* @__PURE__ */ jsx26(AttachContextIcon, { size: 28 })
|
|
3288
|
+
}
|
|
3289
|
+
) }),
|
|
3290
|
+
!selectionMode && /* @__PURE__ */ jsxs23(Fragment4, { children: [
|
|
3291
|
+
isSmart && /* @__PURE__ */ jsx26(Tooltip, { content: "Copy to note", children: /* @__PURE__ */ jsx26(
|
|
3292
|
+
IconButton,
|
|
3293
|
+
{
|
|
3294
|
+
variant: "primary",
|
|
3295
|
+
"aria-label": "Copy to note",
|
|
3296
|
+
icon: /* @__PURE__ */ jsx26(Copy, { size: 16 }),
|
|
3297
|
+
onClick: (e) => {
|
|
3298
|
+
e.stopPropagation();
|
|
3299
|
+
onCopyNotes(record.id, { x: e.clientX, y: e.clientY });
|
|
3300
|
+
}
|
|
3301
|
+
}
|
|
3302
|
+
) }),
|
|
3303
|
+
/* @__PURE__ */ jsx26(OverflowMenu, { items: overflowItems })
|
|
3304
|
+
] })
|
|
3305
|
+
] })
|
|
3306
|
+
] })
|
|
3307
|
+
] })
|
|
3308
|
+
]
|
|
3309
|
+
}
|
|
3310
|
+
);
|
|
3311
|
+
},
|
|
3312
|
+
(prev, next) => prev.selected === next.selected && prev.selectionMode === next.selectionMode && prev.inContext === next.inContext && prev.attachDisabled === next.attachDisabled && prev.selectDisabled === next.selectDisabled && prev.isUploading === next.isUploading && prev.isUploadFailed === next.isUploadFailed && prev.isAnalysing === next.isAnalysing && prev.isSmart === next.isSmart && prev.thumbnailUrl === next.thumbnailUrl && prev.dateDisplay === next.dateDisplay && prev.record.id === next.record.id && prev.record.updatedAtEpoch === next.record.updatedAtEpoch
|
|
3313
|
+
);
|
|
3314
|
+
|
|
3315
|
+
// src/views/RecordsView/useRecordItem.ts
|
|
3316
|
+
import { useCallback as useCallback6 } from "react";
|
|
3317
|
+
import { useStore as useStore10 } from "zustand";
|
|
3318
|
+
|
|
3319
|
+
// src/views/RecordsView/copyRecordNotes.ts
|
|
3320
|
+
async function copyRecordNotes(record) {
|
|
3321
|
+
const text = `${record.title} \xB7 ${record.type}`;
|
|
3322
|
+
await navigator.clipboard.writeText(text);
|
|
3323
|
+
}
|
|
3324
|
+
|
|
3325
|
+
// src/views/RecordsView/useInViewport.ts
|
|
3326
|
+
import { useEffect as useEffect15, useRef as useRef13, useState as useState13 } from "react";
|
|
3327
|
+
function useInViewport() {
|
|
3328
|
+
const ref = useRef13(null);
|
|
3329
|
+
const [seen, setSeen] = useState13(false);
|
|
3330
|
+
useEffect15(() => {
|
|
3331
|
+
if (seen) return;
|
|
3332
|
+
const el = ref.current;
|
|
3333
|
+
if (!el) return;
|
|
3334
|
+
const observer = new IntersectionObserver(
|
|
3335
|
+
(entries) => {
|
|
3336
|
+
if (entries.some((e) => e.isIntersecting)) {
|
|
3337
|
+
setSeen(true);
|
|
3338
|
+
observer.disconnect();
|
|
3339
|
+
}
|
|
3340
|
+
},
|
|
3341
|
+
{ rootMargin: "100px" }
|
|
3342
|
+
);
|
|
3343
|
+
observer.observe(el);
|
|
3344
|
+
return () => observer.disconnect();
|
|
3345
|
+
}, [seen]);
|
|
3346
|
+
return { ref, seen };
|
|
3347
|
+
}
|
|
3348
|
+
|
|
3349
|
+
// src/views/RecordsView/useRecordItem.ts
|
|
3350
|
+
function useRecordItem({ id, selectionMode, maxSelectable }) {
|
|
3351
|
+
const { store, bid, patientId } = useSdk();
|
|
3352
|
+
const { onCopyToNote, attachedIds, onAttachToContext, onRemoveAttachment, onRequestDelete } = useRecordsActions();
|
|
3353
|
+
const { ref, seen } = useInViewport();
|
|
3354
|
+
const record = useRecordById2(id);
|
|
3355
|
+
const thumbnailUrl = useThumbnailUrl2(id);
|
|
3356
|
+
const pendingSelected = useIsSelected2(id);
|
|
3357
|
+
const pendingCount = useStore10(store, (s) => s.selection.recordIds.size);
|
|
3358
|
+
const attachedCount = attachedIds?.size ?? 0;
|
|
3359
|
+
const attached = attachedIds?.has(id) ?? false;
|
|
3360
|
+
const checked = pendingSelected || attached;
|
|
3361
|
+
const attachDisabled = attachedCount >= maxSelectable && !attached;
|
|
3362
|
+
const selectDisabled = attachedCount + pendingCount >= maxSelectable && !checked;
|
|
3363
|
+
const pendingLimit = Math.max(0, maxSelectable - attachedCount);
|
|
3364
|
+
const handleOpen = useCallback6(
|
|
3365
|
+
() => store.getState().selection.openDetail(id),
|
|
3366
|
+
[store, id]
|
|
3367
|
+
);
|
|
3368
|
+
const handleSelect = useCallback6(() => {
|
|
3369
|
+
if (attached) {
|
|
3370
|
+
void onRemoveAttachment?.(id);
|
|
3371
|
+
} else {
|
|
3372
|
+
store.getState().selection.toggleRecord(id, pendingLimit);
|
|
3373
|
+
}
|
|
3374
|
+
}, [store, id, pendingLimit, attached, onRemoveAttachment]);
|
|
3375
|
+
const handleAddToContext = useCallback6(() => {
|
|
3376
|
+
if (attached) {
|
|
3377
|
+
void onRemoveAttachment?.(id);
|
|
3378
|
+
} else {
|
|
3379
|
+
const r = store.getState().records.byId[id];
|
|
3380
|
+
if (r && onAttachToContext) void onAttachToContext([{ documentId: id, name: r.title }]);
|
|
3381
|
+
}
|
|
3382
|
+
}, [store, id, attached, onAttachToContext, onRemoveAttachment]);
|
|
3383
|
+
const handleCopyNotes = useCallback6(
|
|
3384
|
+
async (_id, anchor) => {
|
|
3385
|
+
const r = store.getState().records.byId[id];
|
|
3386
|
+
if (!r) return;
|
|
3387
|
+
let text = `${r.title} \xB7 ${r.type}`;
|
|
3388
|
+
try {
|
|
3389
|
+
const report = await getCore().getSmartReport({ documentId: id, bid, patientId });
|
|
3390
|
+
if (report) {
|
|
3391
|
+
const vitals = parseVitals(report);
|
|
3392
|
+
if (vitals.length > 0) {
|
|
3393
|
+
text = vitalsToNoteText(vitals, {
|
|
3394
|
+
reportName: r.title,
|
|
3395
|
+
date: epochToDisplay(r.createdAtEpoch)
|
|
3396
|
+
});
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
} catch {
|
|
3400
|
+
}
|
|
3401
|
+
if (onCopyToNote) void onCopyToNote(text, anchor);
|
|
3402
|
+
else void copyRecordNotes(r);
|
|
3403
|
+
},
|
|
3404
|
+
[store, id, bid, patientId, onCopyToNote]
|
|
3405
|
+
);
|
|
3406
|
+
const handleDelete = useCallback6(() => {
|
|
3407
|
+
onRequestDelete?.(id);
|
|
3408
|
+
}, [onRequestDelete, id]);
|
|
3409
|
+
if (!record) return null;
|
|
3410
|
+
return {
|
|
3411
|
+
ref,
|
|
3412
|
+
props: {
|
|
3413
|
+
record,
|
|
3414
|
+
selectionMode,
|
|
3415
|
+
selected: checked,
|
|
3416
|
+
thumbnailUrl: seen ? thumbnailUrl : null,
|
|
3417
|
+
inContext: attached,
|
|
3418
|
+
attachDisabled,
|
|
3419
|
+
selectDisabled,
|
|
3420
|
+
isUploading: record.syncState === "uploading",
|
|
3421
|
+
isUploadFailed: record.syncState === "upload_failure",
|
|
3422
|
+
isAnalysing: record.isAnalysing,
|
|
3423
|
+
isSmart: record.isSmart,
|
|
3424
|
+
dateDisplay: epochToDisplay(record.createdAtEpoch),
|
|
3425
|
+
onOpen: handleOpen,
|
|
3426
|
+
onSelect: handleSelect,
|
|
3427
|
+
onAddToContext: handleAddToContext,
|
|
3428
|
+
onCopyNotes: handleCopyNotes,
|
|
3429
|
+
onDelete: handleDelete
|
|
3430
|
+
}
|
|
3431
|
+
};
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
// src/views/RecordsView/RecordCardContainer.tsx
|
|
3435
|
+
import { jsx as jsx27 } from "react/jsx-runtime";
|
|
3436
|
+
var RecordCardContainer = memo8(function RecordCardContainer2(props) {
|
|
3437
|
+
const item = useRecordItem(props);
|
|
3438
|
+
if (!item) return null;
|
|
3439
|
+
return /* @__PURE__ */ jsx27("div", { ref: item.ref, className: "mr-record-slot", children: /* @__PURE__ */ jsx27(RecordCard, { ...item.props }) });
|
|
3440
|
+
});
|
|
3441
|
+
|
|
3442
|
+
// src/views/RecordsView/RecordRowContainer.tsx
|
|
3443
|
+
import { memo as memo10 } from "react";
|
|
3444
|
+
|
|
3445
|
+
// src/components/RecordRow/RecordRow.tsx
|
|
3446
|
+
import { memo as memo9, useMemo as useMemo10 } from "react";
|
|
3447
|
+
import { Check as Check6, Copy as Copy2, Eye as Eye2, FolderPlus as FolderPlus2, Trash2 as Trash22 } from "lucide-react";
|
|
3448
|
+
import { Fragment as Fragment5, jsx as jsx28, jsxs as jsxs24 } from "react/jsx-runtime";
|
|
3449
|
+
var MAX_VISIBLE_TAGS = 4;
|
|
3450
|
+
var RecordRow = memo9(
|
|
3451
|
+
function RecordRow2({
|
|
3452
|
+
record,
|
|
3453
|
+
selected,
|
|
3454
|
+
selectionMode,
|
|
3455
|
+
thumbnailUrl,
|
|
3456
|
+
inContext,
|
|
3457
|
+
attachDisabled,
|
|
3458
|
+
selectDisabled,
|
|
3459
|
+
isUploading,
|
|
3460
|
+
isUploadFailed,
|
|
3461
|
+
isSmart,
|
|
3462
|
+
isAnalysing,
|
|
3463
|
+
dateDisplay,
|
|
3464
|
+
onSelect,
|
|
3465
|
+
onOpen,
|
|
3466
|
+
onAddToContext,
|
|
3467
|
+
onCopyNotes,
|
|
3468
|
+
onDelete
|
|
3469
|
+
}) {
|
|
3470
|
+
const overflowItems = useMemo10(() => [
|
|
3471
|
+
{
|
|
3472
|
+
key: "case",
|
|
3473
|
+
label: "Add to care context",
|
|
3474
|
+
icon: /* @__PURE__ */ jsx28(FolderPlus2, { size: 16, "aria-hidden": true }),
|
|
3475
|
+
subPanel: (_onBack, onClose) => /* @__PURE__ */ jsx28(
|
|
3476
|
+
AddToContextSubPanel,
|
|
3477
|
+
{
|
|
3478
|
+
recordId: record.id,
|
|
3479
|
+
linkedCaseIds: record.cases,
|
|
3480
|
+
onClose
|
|
3481
|
+
}
|
|
3482
|
+
)
|
|
3483
|
+
},
|
|
3484
|
+
{
|
|
3485
|
+
key: "delete",
|
|
3486
|
+
label: "Delete record",
|
|
3487
|
+
icon: /* @__PURE__ */ jsx28(Trash22, { size: 16, "aria-hidden": true }),
|
|
3488
|
+
destructive: true,
|
|
3489
|
+
onSelect: () => onDelete(record.id)
|
|
3490
|
+
}
|
|
3491
|
+
], [record.id, record.cases, onDelete]);
|
|
3492
|
+
const visibleTags = record.tags.slice(0, MAX_VISIBLE_TAGS);
|
|
3493
|
+
const overflowCount = record.tags.length - visibleTags.length;
|
|
3494
|
+
const selectBlocked = selectionMode && selectDisabled && !selected;
|
|
3495
|
+
const handleRowClick = () => {
|
|
3496
|
+
if (selectionMode) {
|
|
3497
|
+
if (!selectBlocked) onSelect(record.id);
|
|
3498
|
+
} else {
|
|
3499
|
+
onOpen(record.id);
|
|
3500
|
+
}
|
|
3501
|
+
};
|
|
3502
|
+
return /* @__PURE__ */ jsxs24(
|
|
3503
|
+
"article",
|
|
3504
|
+
{
|
|
3505
|
+
className: `mr-record-row${selected ? " mr-record-row--selected" : ""}${selectBlocked ? " mr-record-row--disabled" : ""}`,
|
|
3506
|
+
onClick: handleRowClick,
|
|
3507
|
+
children: [
|
|
3508
|
+
selectionMode && /* @__PURE__ */ jsx28(
|
|
3509
|
+
"span",
|
|
3510
|
+
{
|
|
3511
|
+
className: `mr-record-row__checkbox${selected ? " mr-record-row__checkbox--checked" : ""}${selectBlocked ? " mr-record-row__checkbox--disabled" : ""}`,
|
|
3512
|
+
"aria-hidden": true,
|
|
3513
|
+
children: selected && /* @__PURE__ */ jsx28(Check6, { size: 14, strokeWidth: 3 })
|
|
3514
|
+
}
|
|
3515
|
+
),
|
|
3516
|
+
/* @__PURE__ */ jsx28("div", { className: "mr-record-row__thumb", children: /* @__PURE__ */ jsx28(Thumbnail, { url: thumbnailUrl ?? null, alt: record.title }) }),
|
|
3517
|
+
/* @__PURE__ */ jsxs24("div", { className: "mr-record-row__main", children: [
|
|
3518
|
+
/* @__PURE__ */ jsxs24("div", { className: "mr-record-row__heading", children: [
|
|
3519
|
+
/* @__PURE__ */ jsx28("span", { className: "mr-record-row__title", children: record.title }),
|
|
3520
|
+
isUploading ? /* @__PURE__ */ jsx28(Badge, { variant: "uploading", label: "Uploading" }) : isUploadFailed ? /* @__PURE__ */ jsx28(Badge, { variant: "upload_failure", label: "Upload failure" }) : isAnalysing ? /* @__PURE__ */ jsx28(Badge, { variant: "analysing", label: "Analysing" }) : isSmart && /* @__PURE__ */ jsx28(Badge, { variant: "smart", label: "Smart" })
|
|
3521
|
+
] }),
|
|
3522
|
+
/* @__PURE__ */ jsx28("span", { className: "mr-record-row__date", children: dateDisplay })
|
|
3523
|
+
] }),
|
|
3524
|
+
/* @__PURE__ */ jsxs24("div", { className: "mr-record-row__meta", children: [
|
|
3525
|
+
record.tags.length > 0 && /* @__PURE__ */ jsxs24("div", { className: "mr-record-row__tags", children: [
|
|
3526
|
+
visibleTags.map((t) => /* @__PURE__ */ jsx28(TagChip, { label: t }, t)),
|
|
3527
|
+
overflowCount > 0 && /* @__PURE__ */ jsx28(Tooltip, { content: record.tags.join(", "), children: /* @__PURE__ */ jsx28(TagChip, { label: `+${overflowCount}`, onClick: (e) => e.stopPropagation() }) })
|
|
3528
|
+
] }),
|
|
3529
|
+
/* @__PURE__ */ jsxs24("div", { className: "mr-record-row__actions", children: [
|
|
3530
|
+
selectionMode ? /* @__PURE__ */ jsx28(Tooltip, { content: "View record", children: /* @__PURE__ */ jsx28(
|
|
3531
|
+
IconButton,
|
|
3532
|
+
{
|
|
3533
|
+
variant: "primary",
|
|
3534
|
+
"aria-label": "View record",
|
|
3535
|
+
icon: /* @__PURE__ */ jsx28(Eye2, { size: 16, "aria-hidden": true }),
|
|
3536
|
+
onClick: (e) => {
|
|
3537
|
+
e.stopPropagation();
|
|
3538
|
+
onOpen(record.id);
|
|
3539
|
+
}
|
|
3540
|
+
}
|
|
3541
|
+
) }) : inContext ? /* @__PURE__ */ jsx28(Tooltip, { content: "Remove from Context", children: /* @__PURE__ */ jsx28(
|
|
3542
|
+
IconButton,
|
|
3543
|
+
{
|
|
3544
|
+
variant: "solid",
|
|
3545
|
+
"aria-label": "Remove from Context",
|
|
3546
|
+
icon: /* @__PURE__ */ jsx28(Check6, { size: 16, strokeWidth: 3, "aria-hidden": true }),
|
|
3547
|
+
onClick: (e) => {
|
|
3548
|
+
e.stopPropagation();
|
|
3549
|
+
onAddToContext(record.id);
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
) }) : /* @__PURE__ */ jsx28(Tooltip, { content: "Add to session context", children: /* @__PURE__ */ jsx28(
|
|
3553
|
+
"button",
|
|
3554
|
+
{
|
|
3555
|
+
type: "button",
|
|
3556
|
+
className: "mr-attach-context-btn",
|
|
3557
|
+
"aria-label": "Attach to Session Context",
|
|
3558
|
+
disabled: attachDisabled,
|
|
3559
|
+
onClick: (e) => {
|
|
3560
|
+
e.stopPropagation();
|
|
3561
|
+
onAddToContext(record.id);
|
|
3562
|
+
},
|
|
3563
|
+
children: /* @__PURE__ */ jsx28(AttachContextIcon, { size: 28 })
|
|
3564
|
+
}
|
|
3565
|
+
) }),
|
|
3566
|
+
!selectionMode && /* @__PURE__ */ jsxs24(Fragment5, { children: [
|
|
3567
|
+
isSmart && /* @__PURE__ */ jsx28(Tooltip, { content: "Copy to note", children: /* @__PURE__ */ jsx28(
|
|
3568
|
+
IconButton,
|
|
3569
|
+
{
|
|
3570
|
+
variant: "primary",
|
|
3571
|
+
"aria-label": "Copy to note",
|
|
3572
|
+
icon: /* @__PURE__ */ jsx28(Copy2, { size: 16 }),
|
|
3573
|
+
onClick: (e) => {
|
|
3574
|
+
e.stopPropagation();
|
|
3575
|
+
onCopyNotes(record.id, { x: e.clientX, y: e.clientY });
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
3578
|
+
) }),
|
|
3579
|
+
/* @__PURE__ */ jsx28(OverflowMenu, { items: overflowItems })
|
|
3580
|
+
] })
|
|
3581
|
+
] })
|
|
3582
|
+
] })
|
|
3583
|
+
]
|
|
3584
|
+
}
|
|
3585
|
+
);
|
|
3586
|
+
},
|
|
3587
|
+
(prev, next) => prev.selected === next.selected && prev.selectionMode === next.selectionMode && prev.inContext === next.inContext && prev.attachDisabled === next.attachDisabled && prev.selectDisabled === next.selectDisabled && prev.isUploading === next.isUploading && prev.isUploadFailed === next.isUploadFailed && prev.isSmart === next.isSmart && prev.isAnalysing === next.isAnalysing && prev.thumbnailUrl === next.thumbnailUrl && prev.dateDisplay === next.dateDisplay && prev.record.id === next.record.id && prev.record.updatedAtEpoch === next.record.updatedAtEpoch
|
|
3588
|
+
);
|
|
3589
|
+
|
|
3590
|
+
// src/views/RecordsView/RecordRowContainer.tsx
|
|
3591
|
+
import { jsx as jsx29 } from "react/jsx-runtime";
|
|
3592
|
+
var RecordRowContainer = memo10(function RecordRowContainer2(props) {
|
|
3593
|
+
const item = useRecordItem(props);
|
|
3594
|
+
if (!item) return null;
|
|
3595
|
+
return /* @__PURE__ */ jsx29("div", { ref: item.ref, className: "mr-record-slot", children: /* @__PURE__ */ jsx29(RecordRow, { ...item.props }) });
|
|
3596
|
+
});
|
|
3597
|
+
|
|
3598
|
+
// src/views/RecordsView/RecordsGrid.tsx
|
|
3599
|
+
import { jsx as jsx30, jsxs as jsxs25 } from "react/jsx-runtime";
|
|
3600
|
+
function RecordsGrid({
|
|
3601
|
+
sections,
|
|
3602
|
+
viewMode,
|
|
3603
|
+
selectionMode,
|
|
3604
|
+
maxSelectable,
|
|
3605
|
+
showMonths,
|
|
3606
|
+
scrollToKey
|
|
3607
|
+
}) {
|
|
3608
|
+
const isList = viewMode === "list";
|
|
3609
|
+
const headerRefs = useRef14(/* @__PURE__ */ new Map());
|
|
3610
|
+
useEffect16(() => {
|
|
3611
|
+
if (!scrollToKey) return;
|
|
3612
|
+
headerRefs.current.get(scrollToKey)?.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
3613
|
+
}, [scrollToKey]);
|
|
3614
|
+
return /* @__PURE__ */ jsx30("div", { className: "mr-records-grid", children: sections.map((section, i) => {
|
|
3615
|
+
const showMonth = showMonths && (i === 0 || sections[i - 1].monthKey !== section.monthKey);
|
|
3616
|
+
const active = section.key === scrollToKey;
|
|
3617
|
+
return /* @__PURE__ */ jsxs25("section", { className: "mr-records-grid__section gap-20", children: [
|
|
3618
|
+
showMonth && /* @__PURE__ */ jsx30("div", { className: "mr-records-sidebar__month", children: section.monthLabel }),
|
|
3619
|
+
/* @__PURE__ */ jsx30(
|
|
3620
|
+
"header",
|
|
3621
|
+
{
|
|
3622
|
+
className: `mr-records-grid__section-header${active ? " mr-records-grid__section-header--active" : ""}`,
|
|
3623
|
+
"data-section-key": section.key,
|
|
3624
|
+
ref: (el) => {
|
|
3625
|
+
if (el) headerRefs.current.set(section.key, el);
|
|
3626
|
+
else headerRefs.current.delete(section.key);
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
),
|
|
3630
|
+
/* @__PURE__ */ jsx30("div", { className: isList ? "mr-records-grid__rows" : "mr-records-grid__cards", children: section.recordIds.map(
|
|
3631
|
+
(id) => isList ? /* @__PURE__ */ jsx30(
|
|
3632
|
+
RecordRowContainer,
|
|
3633
|
+
{
|
|
3634
|
+
id,
|
|
3635
|
+
selectionMode,
|
|
3636
|
+
maxSelectable
|
|
3637
|
+
},
|
|
3638
|
+
id
|
|
3639
|
+
) : /* @__PURE__ */ jsx30(
|
|
3640
|
+
RecordCardContainer,
|
|
3641
|
+
{
|
|
3642
|
+
id,
|
|
3643
|
+
selectionMode,
|
|
3644
|
+
maxSelectable
|
|
3645
|
+
},
|
|
3646
|
+
id
|
|
3647
|
+
)
|
|
3648
|
+
) })
|
|
3649
|
+
] }, section.key);
|
|
3650
|
+
}) });
|
|
3651
|
+
}
|
|
3652
|
+
|
|
3653
|
+
// src/views/RecordsView/RecordsSelectionFooter.tsx
|
|
3654
|
+
import { jsx as jsx31, jsxs as jsxs26 } from "react/jsx-runtime";
|
|
3655
|
+
function RecordsSelectionFooter({
|
|
3656
|
+
selectedCount,
|
|
3657
|
+
maxCount,
|
|
3658
|
+
actionsDisabled,
|
|
3659
|
+
onClear,
|
|
3660
|
+
onAttach
|
|
3661
|
+
}) {
|
|
3662
|
+
const disabled = actionsDisabled ?? selectedCount === 0;
|
|
3663
|
+
return /* @__PURE__ */ jsxs26("div", { className: "mr-selection-footer", children: [
|
|
3664
|
+
/* @__PURE__ */ jsxs26("div", { className: "mr-selection-footer__text", children: [
|
|
3665
|
+
/* @__PURE__ */ jsxs26("p", { className: "mr-selection-footer__count", children: [
|
|
3666
|
+
selectedCount,
|
|
3667
|
+
" of ",
|
|
3668
|
+
maxCount,
|
|
3669
|
+
" records selected"
|
|
3670
|
+
] }),
|
|
3671
|
+
/* @__PURE__ */ jsxs26("p", { className: "mr-selection-footer__hint", children: [
|
|
3672
|
+
"You can attach upto ",
|
|
3673
|
+
maxCount,
|
|
3674
|
+
" files to a session context"
|
|
3675
|
+
] })
|
|
3676
|
+
] }),
|
|
3677
|
+
/* @__PURE__ */ jsxs26("div", { className: "mr-selection-footer__actions", children: [
|
|
3678
|
+
/* @__PURE__ */ jsx31(
|
|
3679
|
+
"button",
|
|
3680
|
+
{
|
|
3681
|
+
type: "button",
|
|
3682
|
+
className: "mr-selection-footer__clear",
|
|
3683
|
+
disabled,
|
|
3684
|
+
onClick: onClear,
|
|
3685
|
+
children: "Clear selection"
|
|
3686
|
+
}
|
|
3687
|
+
),
|
|
3688
|
+
/* @__PURE__ */ jsx31(
|
|
3689
|
+
"button",
|
|
3690
|
+
{
|
|
3691
|
+
type: "button",
|
|
3692
|
+
className: "mr-selection-footer__attach",
|
|
3693
|
+
disabled,
|
|
3694
|
+
onClick: onAttach,
|
|
3695
|
+
children: "Attach to session context"
|
|
3696
|
+
}
|
|
3697
|
+
)
|
|
3698
|
+
] })
|
|
3699
|
+
] });
|
|
3700
|
+
}
|
|
3701
|
+
|
|
3702
|
+
// src/views/RecordPreview/RecordPreview.tsx
|
|
3703
|
+
import { lazy, Suspense, useState as useState15 } from "react";
|
|
3704
|
+
import { ChevronLeft as ChevronLeft4, FilePlus, Check as Check8, Copy as Copy4 } from "lucide-react";
|
|
3705
|
+
import TurndownService from "turndown";
|
|
3706
|
+
|
|
3707
|
+
// src/views/RecordPreview/SmartReportPanel.tsx
|
|
3708
|
+
import { useMemo as useMemo11, useState as useState14 } from "react";
|
|
3709
|
+
import { Search as Search4, ChevronRight as ChevronRight3, ArrowRight, Check as Check7, Copy as Copy3 } from "lucide-react";
|
|
3710
|
+
import { jsx as jsx32, jsxs as jsxs27 } from "react/jsx-runtime";
|
|
3711
|
+
var STATUS_LABEL = {
|
|
3712
|
+
high: "HIGH",
|
|
3713
|
+
low: "LOW",
|
|
3714
|
+
normal: "NORMAL",
|
|
3715
|
+
unknown: ""
|
|
3716
|
+
};
|
|
3717
|
+
function SmartReportPanel({
|
|
3718
|
+
vitals,
|
|
3719
|
+
reportName,
|
|
3720
|
+
reportDate,
|
|
3721
|
+
onHide,
|
|
3722
|
+
onCopyToNote
|
|
3723
|
+
}) {
|
|
3724
|
+
const [tab, setTab] = useState14("all");
|
|
3725
|
+
const [search, setSearch] = useState14("");
|
|
3726
|
+
const [selected, setSelected] = useState14(/* @__PURE__ */ new Set());
|
|
3727
|
+
const outOfRangeCount = useMemo11(() => vitals.filter(isOutOfRange).length, [vitals]);
|
|
3728
|
+
const shown = useMemo11(() => {
|
|
3729
|
+
const q = search.trim().toLowerCase();
|
|
3730
|
+
return vitals.filter((v) => {
|
|
3731
|
+
if (tab === "outOfRange" && !isOutOfRange(v)) return false;
|
|
3732
|
+
if (q && !v.name.toLowerCase().includes(q)) return false;
|
|
3733
|
+
return true;
|
|
3734
|
+
});
|
|
3735
|
+
}, [vitals, tab, search]);
|
|
3736
|
+
const allShownSelected = shown.length > 0 && shown.every((v) => selected.has(v.id));
|
|
3737
|
+
const toggle = (id) => setSelected((prev) => {
|
|
3738
|
+
const next = new Set(prev);
|
|
3739
|
+
if (next.has(id)) next.delete(id);
|
|
3740
|
+
else next.add(id);
|
|
3741
|
+
return next;
|
|
3742
|
+
});
|
|
3743
|
+
const toggleAll = () => setSelected((prev) => {
|
|
3744
|
+
const next = new Set(prev);
|
|
3745
|
+
if (allShownSelected) shown.forEach((v) => next.delete(v.id));
|
|
3746
|
+
else shown.forEach((v) => next.add(v.id));
|
|
3747
|
+
return next;
|
|
3748
|
+
});
|
|
3749
|
+
const handleCopy = (e) => {
|
|
3750
|
+
const chosen = vitals.filter((v) => selected.has(v.id));
|
|
3751
|
+
if (chosen.length && onCopyToNote) {
|
|
3752
|
+
const text = vitalsToNoteText(chosen, { reportName, date: reportDate });
|
|
3753
|
+
void onCopyToNote(text, { x: e.clientX, y: e.clientY });
|
|
3754
|
+
}
|
|
3755
|
+
};
|
|
3756
|
+
return /* @__PURE__ */ jsxs27("aside", { className: "mr-smart-panel", children: [
|
|
3757
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-smart-panel__top", children: [
|
|
3758
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-smart-panel__header", children: [
|
|
3759
|
+
/* @__PURE__ */ jsx32("span", { className: "mr-smart-panel__title", children: "Smart Report" }),
|
|
3760
|
+
/* @__PURE__ */ jsxs27("button", { type: "button", className: "mr-smart-panel__hide", onClick: onHide, children: [
|
|
3761
|
+
/* @__PURE__ */ jsx32(ChevronRight3, { size: 16, "aria-hidden": true }),
|
|
3762
|
+
"Hide"
|
|
3763
|
+
] })
|
|
3764
|
+
] }),
|
|
3765
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-smart-panel__search", children: [
|
|
3766
|
+
/* @__PURE__ */ jsx32(Search4, { size: 16, "aria-hidden": true }),
|
|
3767
|
+
/* @__PURE__ */ jsx32(
|
|
3768
|
+
"input",
|
|
3769
|
+
{
|
|
3770
|
+
type: "text",
|
|
3771
|
+
placeholder: "Search vitals or parameters",
|
|
3772
|
+
value: search,
|
|
3773
|
+
onChange: (e) => setSearch(e.target.value)
|
|
3774
|
+
}
|
|
3775
|
+
)
|
|
3776
|
+
] }),
|
|
3777
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-smart-panel__tabs", role: "tablist", children: [
|
|
3778
|
+
/* @__PURE__ */ jsx32(
|
|
3779
|
+
"button",
|
|
3780
|
+
{
|
|
3781
|
+
type: "button",
|
|
3782
|
+
role: "tab",
|
|
3783
|
+
"aria-selected": tab === "all",
|
|
3784
|
+
className: `mr-smart-panel__tab${tab === "all" ? " mr-smart-panel__tab--active" : ""}`,
|
|
3785
|
+
onClick: () => setTab("all"),
|
|
3786
|
+
children: "All vitals"
|
|
3787
|
+
}
|
|
3788
|
+
),
|
|
3789
|
+
/* @__PURE__ */ jsxs27(
|
|
3790
|
+
"button",
|
|
3791
|
+
{
|
|
3792
|
+
type: "button",
|
|
3793
|
+
role: "tab",
|
|
3794
|
+
"aria-selected": tab === "outOfRange",
|
|
3795
|
+
className: `mr-smart-panel__tab${tab === "outOfRange" ? " mr-smart-panel__tab--active" : ""}`,
|
|
3796
|
+
onClick: () => setTab("outOfRange"),
|
|
3797
|
+
children: [
|
|
3798
|
+
"Out of range (",
|
|
3799
|
+
outOfRangeCount,
|
|
3800
|
+
")"
|
|
3801
|
+
]
|
|
3802
|
+
}
|
|
3803
|
+
)
|
|
3804
|
+
] })
|
|
3805
|
+
] }),
|
|
3806
|
+
/* @__PURE__ */ jsx32("div", { className: "mr-smart-panel__list", children: shown.length === 0 ? /* @__PURE__ */ jsx32("p", { className: "mr-smart-panel__empty", children: "No vitals to show." }) : shown.map((v) => /* @__PURE__ */ jsx32(VitalCard, { vital: v, selected: selected.has(v.id), onToggle: toggle }, v.id)) }),
|
|
3807
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-smart-panel__cta", children: [
|
|
3808
|
+
/* @__PURE__ */ jsxs27("label", { className: "mr-smart-panel__selectall", children: [
|
|
3809
|
+
/* @__PURE__ */ jsx32(
|
|
3810
|
+
"span",
|
|
3811
|
+
{
|
|
3812
|
+
className: `mr-smart-panel__checkbox${allShownSelected ? " mr-smart-panel__checkbox--checked" : ""}`,
|
|
3813
|
+
"aria-hidden": true,
|
|
3814
|
+
children: allShownSelected && /* @__PURE__ */ jsx32(Check7, { size: 12, strokeWidth: 3 })
|
|
3815
|
+
}
|
|
3816
|
+
),
|
|
3817
|
+
/* @__PURE__ */ jsx32(
|
|
3818
|
+
"input",
|
|
3819
|
+
{
|
|
3820
|
+
type: "checkbox",
|
|
3821
|
+
checked: allShownSelected,
|
|
3822
|
+
onChange: toggleAll,
|
|
3823
|
+
className: "mr-visually-hidden"
|
|
3824
|
+
}
|
|
3825
|
+
),
|
|
3826
|
+
"Select all"
|
|
3827
|
+
] }),
|
|
3828
|
+
/* @__PURE__ */ jsxs27(
|
|
3829
|
+
"button",
|
|
3830
|
+
{
|
|
3831
|
+
type: "button",
|
|
3832
|
+
className: "mr-smart-panel__copy",
|
|
3833
|
+
disabled: selected.size === 0,
|
|
3834
|
+
onClick: handleCopy,
|
|
3835
|
+
children: [
|
|
3836
|
+
/* @__PURE__ */ jsx32(Copy3, { size: 16, "aria-hidden": true }),
|
|
3837
|
+
"Copy to note"
|
|
3838
|
+
]
|
|
3839
|
+
}
|
|
3840
|
+
)
|
|
3841
|
+
] })
|
|
3842
|
+
] });
|
|
3843
|
+
}
|
|
3844
|
+
function VitalCard({
|
|
3845
|
+
vital,
|
|
3846
|
+
selected,
|
|
3847
|
+
onToggle
|
|
3848
|
+
}) {
|
|
3849
|
+
return /* @__PURE__ */ jsxs27(
|
|
3850
|
+
"div",
|
|
3851
|
+
{
|
|
3852
|
+
className: `mr-vital-card mr-vital-card--${vital.status}${selected ? " mr-vital-card--selected" : ""}`,
|
|
3853
|
+
role: "button",
|
|
3854
|
+
"aria-pressed": selected,
|
|
3855
|
+
onClick: () => onToggle(vital.id),
|
|
3856
|
+
children: [
|
|
3857
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__header", children: [
|
|
3858
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__left", children: [
|
|
3859
|
+
/* @__PURE__ */ jsx32("span", { className: "mr-vital-card__name", children: vital.name }),
|
|
3860
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__subtitle", children: [
|
|
3861
|
+
/* @__PURE__ */ jsxs27("span", { className: "mr-vital-card__value", children: [
|
|
3862
|
+
vital.value,
|
|
3863
|
+
vital.unit && /* @__PURE__ */ jsxs27("span", { className: "mr-vital-card__unit", children: [
|
|
3864
|
+
" ",
|
|
3865
|
+
vital.unit
|
|
3866
|
+
] })
|
|
3867
|
+
] }),
|
|
3868
|
+
vital.refRange && /* @__PURE__ */ jsxs27("span", { className: "mr-vital-card__ref", children: [
|
|
3869
|
+
"(Ref: ",
|
|
3870
|
+
vital.refRange,
|
|
3871
|
+
")"
|
|
3872
|
+
] })
|
|
3873
|
+
] })
|
|
3874
|
+
] }),
|
|
3875
|
+
/* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__right", children: [
|
|
3876
|
+
STATUS_LABEL[vital.status] && /* @__PURE__ */ jsx32("span", { className: `mr-vital-card__badge mr-vital-card__badge--${vital.status}`, children: STATUS_LABEL[vital.status] }),
|
|
3877
|
+
/* @__PURE__ */ jsx32(
|
|
3878
|
+
"span",
|
|
3879
|
+
{
|
|
3880
|
+
className: `mr-vital-card__checkbox${selected ? " mr-vital-card__checkbox--checked" : ""}`,
|
|
3881
|
+
"aria-hidden": true,
|
|
3882
|
+
children: selected && /* @__PURE__ */ jsx32(Check7, { size: 14, strokeWidth: 3, "aria-hidden": true })
|
|
3883
|
+
}
|
|
3884
|
+
)
|
|
3885
|
+
] })
|
|
3886
|
+
] }),
|
|
3887
|
+
vital.history.length > 0 && /* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__history", children: [
|
|
3888
|
+
/* @__PURE__ */ jsx32("span", { className: "mr-vital-card__history-label", children: "From previous records" }),
|
|
3889
|
+
/* @__PURE__ */ jsx32("div", { className: "mr-vital-card__history-row", children: vital.history.map((h, i) => /* @__PURE__ */ jsxs27("div", { className: "mr-vital-card__history-point", children: [
|
|
3890
|
+
i > 0 && /* @__PURE__ */ jsx32(ArrowRight, { size: 16, "aria-hidden": true, className: "mr-vital-card__history-arrow" }),
|
|
3891
|
+
/* @__PURE__ */ jsx32("span", { className: "mr-vital-card__history-value", children: h.value }),
|
|
3892
|
+
h.label && /* @__PURE__ */ jsx32("span", { className: "mr-vital-card__history-date", children: h.label })
|
|
3893
|
+
] }, i)) })
|
|
3894
|
+
] })
|
|
3895
|
+
]
|
|
3896
|
+
}
|
|
3897
|
+
);
|
|
3898
|
+
}
|
|
3899
|
+
|
|
3900
|
+
// src/views/RecordPreview/RecordPreview.tsx
|
|
3901
|
+
import { jsx as jsx33, jsxs as jsxs28 } from "react/jsx-runtime";
|
|
3902
|
+
var turndown = new TurndownService({ headingStyle: "atx", bulletListMarker: "-" });
|
|
3903
|
+
var DocumentViewer = lazy(
|
|
3904
|
+
() => import("./DocumentViewer-WXL7OZXK.mjs").then((m) => ({ default: m.DocumentViewer }))
|
|
3905
|
+
);
|
|
3906
|
+
var MAX_PREVIEW_TAGS = 2;
|
|
3907
|
+
function RecordPreview({ recordId, onBack }) {
|
|
3908
|
+
const record = useRecordById2(recordId);
|
|
3909
|
+
const preview = useRecordPreview(recordId);
|
|
3910
|
+
const { attachedIds, onAttachToContext, onRemoveAttachment, onCopyToNote } = useRecordsActions();
|
|
3911
|
+
const [smartOpen, setSmartOpen] = useState15(true);
|
|
3912
|
+
if (!record) return null;
|
|
3913
|
+
const attached = attachedIds?.has(recordId) ?? false;
|
|
3914
|
+
const attachFull = !attached && (attachedIds?.size ?? 0) >= MAX_CONTEXT_ATTACHMENTS;
|
|
3915
|
+
const handleAttach = () => {
|
|
3916
|
+
if (attachFull) return;
|
|
3917
|
+
if (attached) void onRemoveAttachment?.(recordId);
|
|
3918
|
+
else void onAttachToContext?.([{ documentId: recordId, name: record.title }]);
|
|
3919
|
+
};
|
|
3920
|
+
return /* @__PURE__ */ jsxs28("div", { className: "mr-record-preview", children: [
|
|
3921
|
+
/* @__PURE__ */ jsxs28("header", { className: "mr-record-preview__header", children: [
|
|
3922
|
+
/* @__PURE__ */ jsxs28("div", { className: "mr-record-preview__left", children: [
|
|
3923
|
+
/* @__PURE__ */ jsxs28("button", { type: "button", className: "mr-record-preview__back", onClick: onBack, children: [
|
|
3924
|
+
/* @__PURE__ */ jsx33(ChevronLeft4, { size: 16, "aria-hidden": true }),
|
|
3925
|
+
"Back to records"
|
|
3926
|
+
] }),
|
|
3927
|
+
/* @__PURE__ */ jsxs28("div", { className: "mr-record-preview__heading", children: [
|
|
3928
|
+
/* @__PURE__ */ jsx33("span", { className: "mr-record-preview__title", children: record.title }),
|
|
3929
|
+
/* @__PURE__ */ jsx33("span", { className: "mr-record-preview__date", children: epochToDisplay(record.createdAtEpoch) })
|
|
3930
|
+
] })
|
|
3931
|
+
] }),
|
|
3932
|
+
record.tags.length > 0 && /* @__PURE__ */ jsxs28("div", { className: "mr-record-preview__tags", children: [
|
|
3933
|
+
record.tags.slice(0, MAX_PREVIEW_TAGS).map((t) => /* @__PURE__ */ jsx33(TagChip, { label: t }, t)),
|
|
3934
|
+
record.tags.length > MAX_PREVIEW_TAGS && /* @__PURE__ */ jsx33(Tooltip, { content: record.tags.join(", "), children: /* @__PURE__ */ jsx33(TagChip, { label: `+${record.tags.length - MAX_PREVIEW_TAGS}` }) })
|
|
3935
|
+
] }),
|
|
3936
|
+
/* @__PURE__ */ jsxs28("div", { className: "mr-record-preview__actions", children: [
|
|
3937
|
+
preview.hasSmartReport && !smartOpen && /* @__PURE__ */ jsx33(
|
|
3938
|
+
"button",
|
|
3939
|
+
{
|
|
3940
|
+
type: "button",
|
|
3941
|
+
className: "mr-record-preview__smart-cta",
|
|
3942
|
+
onClick: () => setSmartOpen(true),
|
|
3943
|
+
children: "Show smart report"
|
|
3944
|
+
}
|
|
3945
|
+
),
|
|
3946
|
+
record.fileType?.toUpperCase() === "HTML" && onCopyToNote && /* @__PURE__ */ jsxs28(
|
|
3947
|
+
"button",
|
|
3948
|
+
{
|
|
3949
|
+
type: "button",
|
|
3950
|
+
className: "mr-record-preview__copy-btn",
|
|
3951
|
+
onClick: async (e) => {
|
|
3952
|
+
const url = preview.files[0]?.url;
|
|
3953
|
+
if (!url) return;
|
|
3954
|
+
const res = await fetch(url);
|
|
3955
|
+
const html = await res.text();
|
|
3956
|
+
const plain = turndown.turndown(html).trim();
|
|
3957
|
+
void onCopyToNote(plain, { x: e.clientX, y: e.clientY });
|
|
3958
|
+
},
|
|
3959
|
+
children: [
|
|
3960
|
+
/* @__PURE__ */ jsx33(Copy4, { size: 16, "aria-hidden": true }),
|
|
3961
|
+
"Copy to note"
|
|
3962
|
+
]
|
|
3963
|
+
}
|
|
3964
|
+
),
|
|
3965
|
+
attachFull ? /* @__PURE__ */ jsx33(Tooltip, { content: `You can attach up to ${MAX_CONTEXT_ATTACHMENTS} records. Remove one to add this.`, children: /* @__PURE__ */ jsxs28("button", { type: "button", className: "mr-record-preview__attach", disabled: true, children: [
|
|
3966
|
+
/* @__PURE__ */ jsx33(FilePlus, { size: 16, "aria-hidden": true }),
|
|
3967
|
+
"Add to session context"
|
|
3968
|
+
] }) }) : attached ? /* @__PURE__ */ jsxs28(
|
|
3969
|
+
"button",
|
|
3970
|
+
{
|
|
3971
|
+
type: "button",
|
|
3972
|
+
className: "mr-record-preview__attach mr-record-preview__attach--on",
|
|
3973
|
+
onClick: handleAttach,
|
|
3974
|
+
children: [
|
|
3975
|
+
/* @__PURE__ */ jsx33(Check8, { size: 16, "aria-hidden": true }),
|
|
3976
|
+
"Remove from context"
|
|
3977
|
+
]
|
|
3978
|
+
}
|
|
3979
|
+
) : /* @__PURE__ */ jsx33(
|
|
3980
|
+
"button",
|
|
3981
|
+
{
|
|
3982
|
+
type: "button",
|
|
3983
|
+
className: "mr-record-preview__attach-orbit",
|
|
3984
|
+
onClick: handleAttach,
|
|
3985
|
+
children: /* @__PURE__ */ jsxs28("span", { className: "mr-record-preview__attach-face", children: [
|
|
3986
|
+
/* @__PURE__ */ jsx33(FilePlus, { size: 16, "aria-hidden": true }),
|
|
3987
|
+
"Add to session context"
|
|
3988
|
+
] })
|
|
3989
|
+
}
|
|
3990
|
+
)
|
|
3991
|
+
] })
|
|
3992
|
+
] }),
|
|
3993
|
+
/* @__PURE__ */ jsxs28("div", { className: "mr-record-preview__body", children: [
|
|
3994
|
+
preview.status === "loading" ? /* @__PURE__ */ jsx33("div", { className: "mr-record-preview__loading", children: /* @__PURE__ */ jsx33(Skeleton, { variant: "card" }) }) : /* @__PURE__ */ jsx33(Suspense, { fallback: /* @__PURE__ */ jsx33("div", { className: "mr-doc-viewer__status", children: "Loading viewer\u2026" }), children: /* @__PURE__ */ jsx33(
|
|
3995
|
+
DocumentViewer,
|
|
3996
|
+
{
|
|
3997
|
+
files: preview.files,
|
|
3998
|
+
title: record.title,
|
|
3999
|
+
isHtml: record.fileType?.toUpperCase() === "HTML"
|
|
4000
|
+
}
|
|
4001
|
+
) }),
|
|
4002
|
+
preview.hasSmartReport && smartOpen && /* @__PURE__ */ jsx33(
|
|
4003
|
+
SmartReportPanel,
|
|
4004
|
+
{
|
|
4005
|
+
vitals: preview.vitals,
|
|
4006
|
+
reportName: record.title,
|
|
4007
|
+
reportDate: epochToDisplay(record.createdAtEpoch),
|
|
4008
|
+
onHide: () => setSmartOpen(false),
|
|
4009
|
+
onCopyToNote
|
|
4010
|
+
}
|
|
4011
|
+
)
|
|
4012
|
+
] })
|
|
4013
|
+
] });
|
|
4014
|
+
}
|
|
4015
|
+
|
|
4016
|
+
// src/views/RecordsView/UploadModal.tsx
|
|
4017
|
+
import { useEffect as useEffect17, useMemo as useMemo12, useRef as useRef15, useState as useState16 } from "react";
|
|
4018
|
+
import { Upload as Upload2, X as X4 } from "lucide-react";
|
|
4019
|
+
import { jsx as jsx34, jsxs as jsxs29 } from "react/jsx-runtime";
|
|
4020
|
+
var ACCEPT = ".pdf,.jpg,.jpeg,.png,image/*,application/pdf";
|
|
4021
|
+
var fileSeq = 0;
|
|
4022
|
+
function UploadModal({ onUpload, onError, onSuccess, onClose }) {
|
|
4023
|
+
const { documentTypes } = useSdk();
|
|
4024
|
+
const [files, setFiles] = useState16([]);
|
|
4025
|
+
const [dragging, setDragging] = useState16(false);
|
|
4026
|
+
const inputRef = useRef15(null);
|
|
4027
|
+
const docTypeOptions = useMemo12(
|
|
4028
|
+
() => documentTypes.map((t) => ({ value: t.id, label: t.display_name })),
|
|
4029
|
+
[documentTypes]
|
|
4030
|
+
);
|
|
4031
|
+
useEffect17(() => {
|
|
4032
|
+
const onKey = (e) => {
|
|
4033
|
+
if (e.key === "Escape") onClose();
|
|
4034
|
+
};
|
|
4035
|
+
document.addEventListener("keydown", onKey);
|
|
4036
|
+
return () => document.removeEventListener("keydown", onKey);
|
|
4037
|
+
}, [onClose]);
|
|
4038
|
+
const fileKey = (f) => `${f.name}::${f.size}::${f.lastModified}`;
|
|
4039
|
+
const addFiles = (incoming) => {
|
|
4040
|
+
setFiles((prev) => {
|
|
4041
|
+
const existing = new Set(prev.map((f) => fileKey(f.file)));
|
|
4042
|
+
const deduped = Array.from(incoming).filter((f) => !existing.has(fileKey(f)));
|
|
4043
|
+
if (!deduped.length) return prev;
|
|
4044
|
+
const next = deduped.map((file) => ({
|
|
4045
|
+
id: `f-${fileSeq += 1}`,
|
|
4046
|
+
file,
|
|
4047
|
+
documentType: "",
|
|
4048
|
+
date: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
4049
|
+
caseId: null
|
|
4050
|
+
}));
|
|
4051
|
+
return [...prev, ...next];
|
|
4052
|
+
});
|
|
4053
|
+
};
|
|
4054
|
+
const patch = (id, p) => setFiles((prev) => prev.map((f) => f.id === id ? { ...f, ...p } : f));
|
|
4055
|
+
const removeFile = (id) => setFiles((prev) => prev.filter((f) => f.id !== id));
|
|
4056
|
+
const allValid = files.length > 0 && files.every((f) => f.documentType);
|
|
4057
|
+
const handleUpload = () => {
|
|
4058
|
+
if (files.length === 0) return;
|
|
4059
|
+
if (!allValid) {
|
|
4060
|
+
onError("Add a document type and investigation date for every file.");
|
|
4061
|
+
return;
|
|
4062
|
+
}
|
|
4063
|
+
const items = files.map((f) => ({
|
|
4064
|
+
file: f.file,
|
|
4065
|
+
documentType: f.documentType,
|
|
4066
|
+
documentDateMs: (/* @__PURE__ */ new Date(`${f.date}T00:00:00`)).getTime(),
|
|
4067
|
+
caseIds: f.caseId ? [f.caseId] : void 0
|
|
4068
|
+
}));
|
|
4069
|
+
onClose();
|
|
4070
|
+
void onUpload(items).then(() => {
|
|
4071
|
+
onSuccess?.(items.length > 1 ? `${items.length} records uploaded` : "Record uploaded");
|
|
4072
|
+
}).catch((e) => {
|
|
4073
|
+
onError(e instanceof Error ? e.message : "Upload failed. Please try again.");
|
|
4074
|
+
});
|
|
4075
|
+
};
|
|
4076
|
+
const onDrop = (e) => {
|
|
4077
|
+
e.preventDefault();
|
|
4078
|
+
setDragging(false);
|
|
4079
|
+
if (e.dataTransfer.files?.length) addFiles(e.dataTransfer.files);
|
|
4080
|
+
};
|
|
4081
|
+
return /* @__PURE__ */ jsx34("div", { className: "mr-upload-modal", role: "presentation", onClick: onClose, children: /* @__PURE__ */ jsxs29(
|
|
4082
|
+
"div",
|
|
4083
|
+
{
|
|
4084
|
+
className: `mr-upload-modal__dialog${dragging ? " mr-upload-modal__dialog--dragging" : ""}`,
|
|
4085
|
+
role: "dialog",
|
|
4086
|
+
"aria-modal": "true",
|
|
4087
|
+
"aria-label": "Upload a new record",
|
|
4088
|
+
onClick: (e) => e.stopPropagation(),
|
|
4089
|
+
onDragOver: (e) => {
|
|
4090
|
+
e.preventDefault();
|
|
4091
|
+
setDragging(true);
|
|
4092
|
+
},
|
|
4093
|
+
onDragLeave: (e) => {
|
|
4094
|
+
if (e.currentTarget === e.target) setDragging(false);
|
|
4095
|
+
},
|
|
4096
|
+
onDrop,
|
|
4097
|
+
children: [
|
|
4098
|
+
/* @__PURE__ */ jsxs29("div", { className: "mr-upload-modal__header", children: [
|
|
4099
|
+
/* @__PURE__ */ jsxs29("div", { children: [
|
|
4100
|
+
/* @__PURE__ */ jsx34("p", { className: "mr-upload-modal__title", children: "Upload a new record" }),
|
|
4101
|
+
/* @__PURE__ */ jsx34("p", { className: "mr-upload-modal__subtitle", children: "Add a document or photo to this patient's medical records." })
|
|
4102
|
+
] }),
|
|
4103
|
+
/* @__PURE__ */ jsx34("button", { type: "button", className: "mr-upload-modal__close", "aria-label": "Close", onClick: onClose, children: /* @__PURE__ */ jsx34(X4, { size: 18, "aria-hidden": true }) })
|
|
4104
|
+
] }),
|
|
4105
|
+
/* @__PURE__ */ jsxs29("button", { type: "button", className: "mr-upload-dropzone", onClick: () => inputRef.current?.click(), children: [
|
|
4106
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-dropzone__icon", children: /* @__PURE__ */ jsx34(Upload2, { size: 20, "aria-hidden": true }) }),
|
|
4107
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-dropzone__title", children: "Drop files here or click to browse" }),
|
|
4108
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-dropzone__hint", children: "PDF, JPG, PNG \xB7 up to 25 MB each \xB7 multiple files supported" })
|
|
4109
|
+
] }),
|
|
4110
|
+
/* @__PURE__ */ jsx34(
|
|
4111
|
+
"input",
|
|
4112
|
+
{
|
|
4113
|
+
ref: inputRef,
|
|
4114
|
+
type: "file",
|
|
4115
|
+
accept: ACCEPT,
|
|
4116
|
+
multiple: true,
|
|
4117
|
+
hidden: true,
|
|
4118
|
+
onChange: (e) => {
|
|
4119
|
+
if (e.target.files) addFiles(e.target.files);
|
|
4120
|
+
e.target.value = "";
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
),
|
|
4124
|
+
/* @__PURE__ */ jsx34("div", { className: "mr-upload-modal__files", children: files.map((f) => /* @__PURE__ */ jsxs29("div", { className: "mr-upload-file", children: [
|
|
4125
|
+
/* @__PURE__ */ jsxs29("div", { className: "mr-upload-file__head", children: [
|
|
4126
|
+
/* @__PURE__ */ jsxs29("div", { className: "mr-upload-file__titles", children: [
|
|
4127
|
+
/* @__PURE__ */ jsx34("p", { className: "mr-upload-file__title", children: f.file.name }),
|
|
4128
|
+
/* @__PURE__ */ jsxs29("p", { className: "mr-upload-file__meta", children: [
|
|
4129
|
+
f.file.name,
|
|
4130
|
+
" \xB7 ",
|
|
4131
|
+
formatFileSize(f.file.size)
|
|
4132
|
+
] })
|
|
4133
|
+
] }),
|
|
4134
|
+
/* @__PURE__ */ jsx34("button", { type: "button", className: "mr-upload-file__remove", "aria-label": "Remove file", onClick: () => removeFile(f.id), children: /* @__PURE__ */ jsx34(X4, { size: 16, "aria-hidden": true }) })
|
|
4135
|
+
] }),
|
|
4136
|
+
/* @__PURE__ */ jsxs29("div", { className: "mr-upload-file__fields", children: [
|
|
4137
|
+
/* @__PURE__ */ jsxs29("label", { className: "mr-upload-field", children: [
|
|
4138
|
+
/* @__PURE__ */ jsxs29("span", { className: "mr-upload-field__label", children: [
|
|
4139
|
+
"Document type",
|
|
4140
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-field__req", children: "*" })
|
|
4141
|
+
] }),
|
|
4142
|
+
/* @__PURE__ */ jsx34(
|
|
4143
|
+
PresetSelect,
|
|
4144
|
+
{
|
|
4145
|
+
value: f.documentType,
|
|
4146
|
+
options: docTypeOptions,
|
|
4147
|
+
placeholder: "Select type",
|
|
4148
|
+
active: !!f.documentType,
|
|
4149
|
+
onChange: (v) => patch(f.id, { documentType: v })
|
|
4150
|
+
}
|
|
4151
|
+
)
|
|
4152
|
+
] }),
|
|
4153
|
+
/* @__PURE__ */ jsxs29("label", { className: "mr-upload-field", children: [
|
|
4154
|
+
/* @__PURE__ */ jsxs29("span", { className: "mr-upload-field__label", children: [
|
|
4155
|
+
"Investigation date",
|
|
4156
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-field__req", children: "*" })
|
|
4157
|
+
] }),
|
|
4158
|
+
/* @__PURE__ */ jsx34(
|
|
4159
|
+
"input",
|
|
4160
|
+
{
|
|
4161
|
+
type: "date",
|
|
4162
|
+
className: "mr-upload-field__date",
|
|
4163
|
+
value: f.date,
|
|
4164
|
+
max: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10),
|
|
4165
|
+
onChange: (e) => patch(f.id, { date: e.target.value })
|
|
4166
|
+
}
|
|
4167
|
+
)
|
|
4168
|
+
] }),
|
|
4169
|
+
/* @__PURE__ */ jsxs29("div", { className: "mr-upload-field", children: [
|
|
4170
|
+
/* @__PURE__ */ jsx34("span", { className: "mr-upload-field__label", children: "Care context" }),
|
|
4171
|
+
/* @__PURE__ */ jsx34(
|
|
4172
|
+
CasePicker,
|
|
4173
|
+
{
|
|
4174
|
+
selected: f.caseId,
|
|
4175
|
+
onChange: (id) => patch(f.id, { caseId: id }),
|
|
4176
|
+
mode: "dropdown"
|
|
4177
|
+
}
|
|
4178
|
+
)
|
|
4179
|
+
] })
|
|
4180
|
+
] })
|
|
4181
|
+
] }, f.id)) }),
|
|
4182
|
+
/* @__PURE__ */ jsx34("div", { className: "mr-upload-modal__footer", children: /* @__PURE__ */ jsxs29(
|
|
4183
|
+
"button",
|
|
4184
|
+
{
|
|
4185
|
+
type: "button",
|
|
4186
|
+
className: "mr-upload-modal__submit",
|
|
4187
|
+
disabled: !allValid,
|
|
4188
|
+
onClick: handleUpload,
|
|
4189
|
+
children: [
|
|
4190
|
+
/* @__PURE__ */ jsx34(Upload2, { size: 16, "aria-hidden": true }),
|
|
4191
|
+
"Upload"
|
|
4192
|
+
]
|
|
4193
|
+
}
|
|
4194
|
+
) })
|
|
4195
|
+
]
|
|
4196
|
+
}
|
|
4197
|
+
) });
|
|
4198
|
+
}
|
|
4199
|
+
|
|
4200
|
+
// src/views/RecordsView/useRecordsView.ts
|
|
4201
|
+
import { useCallback as useCallback7, useEffect as useEffect18, useMemo as useMemo15, useRef as useRef16, useState as useState17 } from "react";
|
|
4202
|
+
import { useStore as useStore12 } from "zustand";
|
|
4203
|
+
|
|
4204
|
+
// src/views/RecordsView/useRecordSections.ts
|
|
4205
|
+
import { useMemo as useMemo13 } from "react";
|
|
4206
|
+
import { useStore as useStore11 } from "zustand";
|
|
4207
|
+
var WEEKDAYS = ["SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"];
|
|
4208
|
+
var MONTHS = [
|
|
4209
|
+
"JANUARY",
|
|
4210
|
+
"FEBRUARY",
|
|
4211
|
+
"MARCH",
|
|
4212
|
+
"APRIL",
|
|
4213
|
+
"MAY",
|
|
4214
|
+
"JUNE",
|
|
4215
|
+
"JULY",
|
|
4216
|
+
"AUGUST",
|
|
4217
|
+
"SEPTEMBER",
|
|
4218
|
+
"OCTOBER",
|
|
4219
|
+
"NOVEMBER",
|
|
4220
|
+
"DECEMBER"
|
|
4221
|
+
];
|
|
4222
|
+
var dayBox = (epoch) => {
|
|
4223
|
+
const d = new Date(epoch);
|
|
4224
|
+
return { dayNumber: String(d.getDate()), weekday: WEEKDAYS[d.getDay()] };
|
|
4225
|
+
};
|
|
4226
|
+
var dayKeyOf = (epoch) => {
|
|
4227
|
+
const d = new Date(epoch);
|
|
4228
|
+
return `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
4229
|
+
};
|
|
4230
|
+
function useRecordSections(tab, ids) {
|
|
4231
|
+
const { store } = useSdk();
|
|
4232
|
+
const byId = useStore11(store, (s) => s.records.byId);
|
|
4233
|
+
const caseIds = useStore11(store, (s) => s.cases.ids);
|
|
4234
|
+
const casesById = useStore11(store, (s) => s.cases.byId);
|
|
4235
|
+
const filters = useStore11(store, (s) => s.filters);
|
|
4236
|
+
return useMemo13(() => {
|
|
4237
|
+
const matchCount = (recordIds) => recordIds.reduce((n, id) => {
|
|
4238
|
+
const r = byId[id];
|
|
4239
|
+
return r && recordMatchesFilters(r, filters) ? n + 1 : n;
|
|
4240
|
+
}, 0);
|
|
4241
|
+
const recordsLabel = (n) => `${n} record${n === 1 ? "" : "s"}`;
|
|
4242
|
+
if (tab === "careContext") {
|
|
4243
|
+
return caseIds.map((caseId) => {
|
|
4244
|
+
const c = casesById[caseId];
|
|
4245
|
+
if (!c) return null;
|
|
4246
|
+
const recordIds = ids.filter((id) => byId[id]?.cases.includes(caseId));
|
|
4247
|
+
const type = (c.typeCode ?? "").toUpperCase();
|
|
4248
|
+
return {
|
|
4249
|
+
key: caseId,
|
|
4250
|
+
recordIds,
|
|
4251
|
+
dayNumber: type,
|
|
4252
|
+
weekday: "",
|
|
4253
|
+
monthLabel: "",
|
|
4254
|
+
monthKey: "",
|
|
4255
|
+
countLabel: c.name,
|
|
4256
|
+
summary: recordsLabel(matchCount(recordIds))
|
|
4257
|
+
};
|
|
4258
|
+
}).filter((s) => s !== null);
|
|
4259
|
+
}
|
|
4260
|
+
const map = /* @__PURE__ */ new Map();
|
|
4261
|
+
for (const id of ids) {
|
|
4262
|
+
const r = byId[id];
|
|
4263
|
+
if (!r) continue;
|
|
4264
|
+
const key = dayKeyOf(r.createdAtEpoch);
|
|
4265
|
+
let entry = map.get(key);
|
|
4266
|
+
if (!entry) {
|
|
4267
|
+
entry = { date: new Date(r.createdAtEpoch), types: /* @__PURE__ */ new Set(), recordIds: [] };
|
|
4268
|
+
map.set(key, entry);
|
|
4269
|
+
}
|
|
4270
|
+
entry.recordIds.push(id);
|
|
4271
|
+
entry.types.add(r.type);
|
|
4272
|
+
}
|
|
4273
|
+
return [...map.entries()].sort((a, b) => b[1].date.getTime() - a[1].date.getTime()).map(([key, { date, types, recordIds }]) => ({
|
|
4274
|
+
key,
|
|
4275
|
+
recordIds,
|
|
4276
|
+
...dayBox(date.getTime()),
|
|
4277
|
+
monthLabel: `${MONTHS[date.getMonth()]} ${date.getFullYear()}`,
|
|
4278
|
+
monthKey: `${date.getFullYear()}-${date.getMonth()}`,
|
|
4279
|
+
countLabel: recordsLabel(matchCount(recordIds)),
|
|
4280
|
+
summary: [...types].join(" \xB7 ")
|
|
4281
|
+
}));
|
|
4282
|
+
}, [tab, ids, byId, caseIds, casesById, filters]);
|
|
4283
|
+
}
|
|
4284
|
+
|
|
4285
|
+
// src/views/RecordsView/useSectionPages.ts
|
|
4286
|
+
import { useMemo as useMemo14 } from "react";
|
|
4287
|
+
var MONTHS_PER_PAGE = 5;
|
|
4288
|
+
var CASES_PER_PAGE = 10;
|
|
4289
|
+
function useSectionPages(tab, sections, page) {
|
|
4290
|
+
return useMemo14(() => {
|
|
4291
|
+
if (sections.length === 0) {
|
|
4292
|
+
return { pageSections: [], pageCount: 1, page: 0 };
|
|
4293
|
+
}
|
|
4294
|
+
if (tab === "date") {
|
|
4295
|
+
const monthKeys = [];
|
|
4296
|
+
for (const s of sections) {
|
|
4297
|
+
if (monthKeys[monthKeys.length - 1] !== s.monthKey) monthKeys.push(s.monthKey);
|
|
4298
|
+
}
|
|
4299
|
+
const pageCount2 = Math.max(1, Math.ceil(monthKeys.length / MONTHS_PER_PAGE));
|
|
4300
|
+
const clamped2 = Math.min(Math.max(page, 0), pageCount2 - 1);
|
|
4301
|
+
const windowKeys = new Set(
|
|
4302
|
+
monthKeys.slice(clamped2 * MONTHS_PER_PAGE, (clamped2 + 1) * MONTHS_PER_PAGE)
|
|
4303
|
+
);
|
|
4304
|
+
return {
|
|
4305
|
+
pageSections: sections.filter((s) => windowKeys.has(s.monthKey)),
|
|
4306
|
+
pageCount: pageCount2,
|
|
4307
|
+
page: clamped2
|
|
4308
|
+
};
|
|
4309
|
+
}
|
|
4310
|
+
const pageCount = Math.max(1, Math.ceil(sections.length / CASES_PER_PAGE));
|
|
4311
|
+
const clamped = Math.min(Math.max(page, 0), pageCount - 1);
|
|
4312
|
+
return {
|
|
4313
|
+
pageSections: sections.slice(clamped * CASES_PER_PAGE, (clamped + 1) * CASES_PER_PAGE),
|
|
4314
|
+
pageCount,
|
|
4315
|
+
page: clamped
|
|
4316
|
+
};
|
|
4317
|
+
}, [tab, sections, page]);
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
// src/views/RecordsView/useRecordsView.ts
|
|
4321
|
+
function useRecordsView({
|
|
4322
|
+
onUpload,
|
|
4323
|
+
allowUpload = true,
|
|
4324
|
+
onCopyToNote,
|
|
4325
|
+
attachedIds,
|
|
4326
|
+
onAttachManyToContext,
|
|
4327
|
+
onRemoveAttachment,
|
|
4328
|
+
onToast
|
|
4329
|
+
}) {
|
|
4330
|
+
const { store, labelOf } = useSdk();
|
|
4331
|
+
const { refresh, sourceRefreshedAt, deleteRecord } = useRecordsConnection();
|
|
4332
|
+
const { upload } = useUploadConnection();
|
|
4333
|
+
const status = useRecordsStatus2();
|
|
4334
|
+
const filteredIds = useFilteredRecordIds2();
|
|
4335
|
+
const allIds = useStore12(store, (s) => s.records.ids);
|
|
4336
|
+
const selectedCount = useStore12(store, (s) => s.selection.recordIds.size);
|
|
4337
|
+
const openDetailId = useStore12(store, (s) => s.selection.openDetailId);
|
|
4338
|
+
const activeFilters = useStore12(store, (s) => s.filters);
|
|
4339
|
+
const attachedIdSet = useMemo15(() => new Set(attachedIds ?? []), [attachedIds]);
|
|
4340
|
+
const [viewMode, setViewMode] = useState17("grid");
|
|
4341
|
+
const [sidebarTab, setSidebarTab] = useState17("date");
|
|
4342
|
+
const [activeKey, setActiveKey] = useState17(null);
|
|
4343
|
+
const [selectionMode, setSelectionMode] = useState17(false);
|
|
4344
|
+
const [page, setPage] = useState17(0);
|
|
4345
|
+
const [deleteTargetId, setDeleteTargetId] = useState17(null);
|
|
4346
|
+
const [deleting, setDeleting] = useState17(false);
|
|
4347
|
+
const [uploadOpen, setUploadOpen] = useState17(false);
|
|
4348
|
+
useCasesConnection();
|
|
4349
|
+
const sections = useRecordSections(sidebarTab, allIds);
|
|
4350
|
+
const autoSelectedRef = useRef16(false);
|
|
4351
|
+
useEffect18(() => {
|
|
4352
|
+
if (sidebarTab !== "careContext") {
|
|
4353
|
+
autoSelectedRef.current = false;
|
|
4354
|
+
return;
|
|
4355
|
+
}
|
|
4356
|
+
if (autoSelectedRef.current || sections.length === 0) return;
|
|
4357
|
+
autoSelectedRef.current = true;
|
|
4358
|
+
setActiveKey(sections[0].key);
|
|
4359
|
+
}, [sidebarTab, sections]);
|
|
4360
|
+
const { pageSections, pageCount, page: safePage } = useSectionPages(sidebarTab, sections, page);
|
|
4361
|
+
const resolvedActiveKey = activeKey && pageSections.some((s) => s.key === activeKey) ? activeKey : null;
|
|
4362
|
+
const filteredSections = useMemo15(() => {
|
|
4363
|
+
const allowed = new Set(filteredIds);
|
|
4364
|
+
const source = resolvedActiveKey ? pageSections.filter((s) => s.key === resolvedActiveKey) : pageSections;
|
|
4365
|
+
const trimmed = source.map((s) => ({ ...s, recordIds: s.recordIds.filter((id) => allowed.has(id)) })).filter((s) => s.recordIds.length > 0);
|
|
4366
|
+
if (sidebarTab !== "date" || resolvedActiveKey) return trimmed;
|
|
4367
|
+
const byMonth = /* @__PURE__ */ new Map();
|
|
4368
|
+
for (const s of trimmed) {
|
|
4369
|
+
const existing = byMonth.get(s.monthKey);
|
|
4370
|
+
if (existing) existing.recordIds.push(...s.recordIds);
|
|
4371
|
+
else byMonth.set(s.monthKey, { ...s, key: s.monthKey, recordIds: [...s.recordIds] });
|
|
4372
|
+
}
|
|
4373
|
+
return [...byMonth.values()];
|
|
4374
|
+
}, [pageSections, resolvedActiveKey, filteredIds, sidebarTab]);
|
|
4375
|
+
const handleTabChange = useCallback7((tab) => {
|
|
4376
|
+
setSidebarTab(tab);
|
|
4377
|
+
setActiveKey(null);
|
|
4378
|
+
setPage(0);
|
|
4379
|
+
store.getState().selection.clearSelection();
|
|
4380
|
+
}, [store]);
|
|
4381
|
+
const handleSelectSection = useCallback7((key) => {
|
|
4382
|
+
setActiveKey((prev) => prev === key ? null : key);
|
|
4383
|
+
}, []);
|
|
4384
|
+
const handleToggleSelectionMode = useCallback7(() => {
|
|
4385
|
+
setSelectionMode((on) => {
|
|
4386
|
+
if (on) store.getState().selection.clearSelection();
|
|
4387
|
+
return !on;
|
|
4388
|
+
});
|
|
4389
|
+
}, [store]);
|
|
4390
|
+
const clearSelection = useCallback7(() => {
|
|
4391
|
+
store.getState().selection.clearSelection();
|
|
4392
|
+
}, [store]);
|
|
4393
|
+
const handlePageChange = useCallback7((p) => {
|
|
4394
|
+
setPage(p);
|
|
4395
|
+
setActiveKey(null);
|
|
4396
|
+
store.getState().selection.clearSelection();
|
|
4397
|
+
store.getState().selection.openDetail(null);
|
|
4398
|
+
}, [store]);
|
|
4399
|
+
const handleAttachMany = useCallback7(() => {
|
|
4400
|
+
const state = store.getState();
|
|
4401
|
+
const byId = state.records.byId;
|
|
4402
|
+
const records = [...state.selection.recordIds].map((rid) => byId[rid]).filter(Boolean).map((r) => ({ documentId: r.id, name: r.title }));
|
|
4403
|
+
state.selection.clearSelection();
|
|
4404
|
+
setSelectionMode(false);
|
|
4405
|
+
if (records.length && onAttachManyToContext) void onAttachManyToContext(records);
|
|
4406
|
+
}, [store, onAttachManyToContext]);
|
|
4407
|
+
const openUpload = useCallback7(() => {
|
|
4408
|
+
onUpload?.();
|
|
4409
|
+
setUploadOpen(true);
|
|
4410
|
+
}, [onUpload]);
|
|
4411
|
+
const requestDelete = useCallback7((id) => setDeleteTargetId(id), []);
|
|
4412
|
+
const cancelDelete = useCallback7(() => {
|
|
4413
|
+
if (!deleting) setDeleteTargetId(null);
|
|
4414
|
+
}, [deleting]);
|
|
4415
|
+
const confirmDelete = useCallback7(async () => {
|
|
4416
|
+
if (!deleteTargetId) return;
|
|
4417
|
+
const target = store.getState().records.byId[deleteTargetId];
|
|
4418
|
+
setDeleting(true);
|
|
4419
|
+
try {
|
|
4420
|
+
await deleteRecord(deleteTargetId);
|
|
4421
|
+
onToast?.(`${target?.title ?? "Record"} deleted`, "success");
|
|
4422
|
+
setDeleteTargetId(null);
|
|
4423
|
+
} catch (e) {
|
|
4424
|
+
const msg = e instanceof Error ? e.message : "Delete failed";
|
|
4425
|
+
onToast?.(`Could not delete record. ${msg}`, "error");
|
|
4426
|
+
} finally {
|
|
4427
|
+
setDeleting(false);
|
|
4428
|
+
}
|
|
4429
|
+
}, [deleteTargetId, deleteRecord, store, onToast]);
|
|
4430
|
+
const deleteTarget = useStore12(
|
|
4431
|
+
store,
|
|
4432
|
+
(s) => deleteTargetId ? s.records.byId[deleteTargetId] : void 0
|
|
4433
|
+
);
|
|
4434
|
+
const actions = useMemo15(
|
|
4435
|
+
() => ({
|
|
4436
|
+
onCopyToNote,
|
|
4437
|
+
attachedIds: attachedIdSet,
|
|
4438
|
+
onAttachToContext: onAttachManyToContext,
|
|
4439
|
+
onRemoveAttachment,
|
|
4440
|
+
onRequestDelete: requestDelete,
|
|
4441
|
+
onToast
|
|
4442
|
+
}),
|
|
4443
|
+
[onCopyToNote, attachedIdSet, onAttachManyToContext, onRemoveAttachment, requestDelete, onToast]
|
|
4444
|
+
);
|
|
4445
|
+
const noRecords = allIds.length === 0;
|
|
4446
|
+
const isInitialLoading = status === "loading" && noRecords;
|
|
4447
|
+
const isLoadFailed = status === "error" && noRecords;
|
|
4448
|
+
const isTabEmpty = !isInitialLoading && !isLoadFailed && noRecords;
|
|
4449
|
+
return {
|
|
4450
|
+
// state
|
|
4451
|
+
store,
|
|
4452
|
+
labelOf,
|
|
4453
|
+
viewMode,
|
|
4454
|
+
setViewMode,
|
|
4455
|
+
sidebarTab,
|
|
4456
|
+
activeKey: resolvedActiveKey,
|
|
4457
|
+
selectionMode,
|
|
4458
|
+
page: safePage,
|
|
4459
|
+
pageCount,
|
|
4460
|
+
uploadOpen,
|
|
4461
|
+
setUploadOpen,
|
|
4462
|
+
openDetailId,
|
|
4463
|
+
activeFilters,
|
|
4464
|
+
// derived
|
|
4465
|
+
allIds,
|
|
4466
|
+
selectedCount,
|
|
4467
|
+
attachedIdSet,
|
|
4468
|
+
filteredSections,
|
|
4469
|
+
pageSections,
|
|
4470
|
+
sections,
|
|
4471
|
+
deleteTarget,
|
|
4472
|
+
deleting,
|
|
4473
|
+
isInitialLoading,
|
|
4474
|
+
isLoadFailed,
|
|
4475
|
+
isTabEmpty,
|
|
4476
|
+
// data
|
|
4477
|
+
upload,
|
|
4478
|
+
refresh,
|
|
4479
|
+
sourceRefreshedAt,
|
|
4480
|
+
actions,
|
|
4481
|
+
allowUpload,
|
|
4482
|
+
// handlers
|
|
4483
|
+
handleTabChange,
|
|
4484
|
+
handleSelectSection,
|
|
4485
|
+
handleToggleSelectionMode,
|
|
4486
|
+
clearSelection,
|
|
4487
|
+
handleAttachMany,
|
|
4488
|
+
openUpload,
|
|
4489
|
+
requestDelete,
|
|
4490
|
+
cancelDelete,
|
|
4491
|
+
confirmDelete,
|
|
4492
|
+
setPage: handlePageChange
|
|
4493
|
+
};
|
|
4494
|
+
}
|
|
4495
|
+
|
|
4496
|
+
// src/views/RecordsView/RecordsView.tsx
|
|
4497
|
+
import { Fragment as Fragment6, jsx as jsx35, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
4498
|
+
var MAX_CONTEXT_ATTACHMENTS = 1;
|
|
4499
|
+
function RecordsView({
|
|
4500
|
+
className,
|
|
4501
|
+
onUpload,
|
|
4502
|
+
allowUpload = true,
|
|
4503
|
+
onCopyToNote,
|
|
4504
|
+
attachedIds,
|
|
4505
|
+
onAttachManyToContext,
|
|
4506
|
+
onRemoveAttachment,
|
|
4507
|
+
onToast
|
|
4508
|
+
}) {
|
|
4509
|
+
const {
|
|
4510
|
+
store,
|
|
4511
|
+
labelOf,
|
|
4512
|
+
viewMode,
|
|
4513
|
+
setViewMode,
|
|
4514
|
+
sidebarTab,
|
|
4515
|
+
activeKey,
|
|
4516
|
+
selectionMode,
|
|
4517
|
+
page,
|
|
4518
|
+
pageCount,
|
|
4519
|
+
uploadOpen,
|
|
4520
|
+
setUploadOpen,
|
|
4521
|
+
openDetailId,
|
|
4522
|
+
activeFilters,
|
|
4523
|
+
selectedCount,
|
|
4524
|
+
attachedIdSet,
|
|
4525
|
+
filteredSections,
|
|
4526
|
+
pageSections,
|
|
4527
|
+
deleteTarget,
|
|
4528
|
+
deleting,
|
|
4529
|
+
isInitialLoading,
|
|
4530
|
+
isLoadFailed,
|
|
4531
|
+
isTabEmpty,
|
|
4532
|
+
upload,
|
|
4533
|
+
refresh,
|
|
4534
|
+
sourceRefreshedAt,
|
|
4535
|
+
actions,
|
|
4536
|
+
handleTabChange,
|
|
4537
|
+
handleSelectSection,
|
|
4538
|
+
handleToggleSelectionMode,
|
|
4539
|
+
clearSelection,
|
|
4540
|
+
handleAttachMany,
|
|
4541
|
+
openUpload,
|
|
4542
|
+
cancelDelete,
|
|
4543
|
+
confirmDelete,
|
|
4544
|
+
setPage
|
|
4545
|
+
} = useRecordsView({
|
|
4546
|
+
onUpload,
|
|
4547
|
+
allowUpload,
|
|
4548
|
+
onCopyToNote,
|
|
4549
|
+
attachedIds,
|
|
4550
|
+
onAttachManyToContext,
|
|
4551
|
+
onRemoveAttachment,
|
|
4552
|
+
onToast
|
|
4553
|
+
});
|
|
4554
|
+
if (isInitialLoading) {
|
|
4555
|
+
return /* @__PURE__ */ jsx35("div", { className: `mr-records-view${className ? ` ${className}` : ""}`, children: /* @__PURE__ */ jsx35(RecordsLoadingState, {}) });
|
|
4556
|
+
}
|
|
4557
|
+
if (isLoadFailed || isTabEmpty) {
|
|
4558
|
+
return /* @__PURE__ */ jsxs30(Fragment6, { children: [
|
|
4559
|
+
/* @__PURE__ */ jsx35("div", { className: `mr-records-view mr-records-view--state${className ? ` ${className}` : ""}`, children: isLoadFailed ? /* @__PURE__ */ jsx35(RecordsErrorState, { onRetry: refresh }) : /* @__PURE__ */ jsx35(RecordsEmptyState, { onUpload: allowUpload ? openUpload : void 0 }) }),
|
|
4560
|
+
uploadOpen && /* @__PURE__ */ jsx35(
|
|
4561
|
+
UploadModal,
|
|
4562
|
+
{
|
|
4563
|
+
onUpload: upload,
|
|
4564
|
+
onError: (msg) => onToast?.(msg, "error"),
|
|
4565
|
+
onSuccess: (msg) => onToast?.(msg, "success"),
|
|
4566
|
+
onClose: () => setUploadOpen(false)
|
|
4567
|
+
}
|
|
4568
|
+
)
|
|
4569
|
+
] });
|
|
4570
|
+
}
|
|
4571
|
+
return /* @__PURE__ */ jsx35(RecordsActionsProvider, { value: actions, children: /* @__PURE__ */ jsxs30("div", { className: `mr-records-view${className ? ` ${className}` : ""}`, children: [
|
|
4572
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-view__grid", hidden: !!openDetailId, children: [
|
|
4573
|
+
/* @__PURE__ */ jsx35(
|
|
4574
|
+
RecordsToolbar,
|
|
4575
|
+
{
|
|
4576
|
+
viewMode,
|
|
4577
|
+
onViewModeChange: setViewMode,
|
|
4578
|
+
onUpload: allowUpload ? openUpload : void 0,
|
|
4579
|
+
onRefresh: refresh,
|
|
4580
|
+
sourceRefreshedAt,
|
|
4581
|
+
selectionMode,
|
|
4582
|
+
onToggleSelect: handleToggleSelectionMode
|
|
4583
|
+
}
|
|
4584
|
+
),
|
|
4585
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-view__body", children: [
|
|
4586
|
+
/* @__PURE__ */ jsx35(
|
|
4587
|
+
RecordsSidebar,
|
|
4588
|
+
{
|
|
4589
|
+
tab: sidebarTab,
|
|
4590
|
+
onTabChange: handleTabChange,
|
|
4591
|
+
sections: pageSections,
|
|
4592
|
+
activeKey,
|
|
4593
|
+
onSelectSection: handleSelectSection,
|
|
4594
|
+
page,
|
|
4595
|
+
pageCount,
|
|
4596
|
+
onPageChange: setPage
|
|
4597
|
+
}
|
|
4598
|
+
),
|
|
4599
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-view__main", children: [
|
|
4600
|
+
/* @__PURE__ */ jsx35(
|
|
4601
|
+
ActiveFiltersBar,
|
|
4602
|
+
{
|
|
4603
|
+
filters: activeFilters,
|
|
4604
|
+
labelOf,
|
|
4605
|
+
onRemoveType: () => store.getState().filters.setType(null),
|
|
4606
|
+
onRemoveTags: (tag) => store.getState().filters.applyPopoverFilters({ ...activeFilters, tags: activeFilters.tags.filter((t) => t !== tag) }),
|
|
4607
|
+
onRemoveDocDate: () => store.getState().filters.applyPopoverFilters({ ...activeFilters, documentDateFrom: null, documentDateTo: null, documentDatePreset: "anytime" }),
|
|
4608
|
+
onRemoveUploadDate: () => store.getState().filters.applyPopoverFilters({ ...activeFilters, uploadDateFrom: null, uploadDateTo: null, uploadDatePreset: "anytime" }),
|
|
4609
|
+
onClearAll: () => {
|
|
4610
|
+
store.getState().filters.setType(null);
|
|
4611
|
+
store.getState().filters.clearPopoverFilters();
|
|
4612
|
+
}
|
|
4613
|
+
}
|
|
4614
|
+
),
|
|
4615
|
+
/* @__PURE__ */ jsx35("div", { className: "mr-records-view__content", children: filteredSections.length === 0 ? /* @__PURE__ */ jsx35(RecordsFilteredEmpty, {}) : /* @__PURE__ */ jsx35(
|
|
4616
|
+
RecordsGrid,
|
|
4617
|
+
{
|
|
4618
|
+
sections: filteredSections,
|
|
4619
|
+
viewMode,
|
|
4620
|
+
selectionMode,
|
|
4621
|
+
maxSelectable: MAX_CONTEXT_ATTACHMENTS,
|
|
4622
|
+
showMonths: sidebarTab === "date",
|
|
4623
|
+
scrollToKey: activeKey
|
|
4624
|
+
}
|
|
4625
|
+
) }),
|
|
4626
|
+
selectionMode && /* @__PURE__ */ jsx35(
|
|
4627
|
+
RecordsSelectionFooter,
|
|
4628
|
+
{
|
|
4629
|
+
selectedCount: attachedIdSet.size + selectedCount,
|
|
4630
|
+
maxCount: MAX_CONTEXT_ATTACHMENTS,
|
|
4631
|
+
actionsDisabled: selectedCount === 0 || attachedIdSet.size >= MAX_CONTEXT_ATTACHMENTS,
|
|
4632
|
+
onClear: clearSelection,
|
|
4633
|
+
onAttach: handleAttachMany
|
|
4634
|
+
}
|
|
4635
|
+
)
|
|
4636
|
+
] })
|
|
4637
|
+
] })
|
|
4638
|
+
] }),
|
|
4639
|
+
openDetailId && /* @__PURE__ */ jsx35("div", { className: "mr-records-view__preview", children: /* @__PURE__ */ jsx35(
|
|
4640
|
+
RecordPreview,
|
|
4641
|
+
{
|
|
4642
|
+
recordId: openDetailId,
|
|
4643
|
+
onBack: () => store.getState().selection.openDetail(null)
|
|
4644
|
+
}
|
|
4645
|
+
) }),
|
|
4646
|
+
deleteTarget && /* @__PURE__ */ jsx35(
|
|
4647
|
+
DeleteConfirmModal,
|
|
4648
|
+
{
|
|
4649
|
+
recordLabel: `${deleteTarget.type} (${epochToDisplay(deleteTarget.createdAtEpoch)})`,
|
|
4650
|
+
deleting,
|
|
4651
|
+
onConfirm: confirmDelete,
|
|
4652
|
+
onCancel: cancelDelete
|
|
4653
|
+
}
|
|
4654
|
+
),
|
|
4655
|
+
uploadOpen && /* @__PURE__ */ jsx35(
|
|
4656
|
+
UploadModal,
|
|
4657
|
+
{
|
|
4658
|
+
onUpload: upload,
|
|
4659
|
+
onError: (msg) => onToast?.(msg, "error"),
|
|
4660
|
+
onSuccess: (msg) => onToast?.(msg, "success"),
|
|
4661
|
+
onClose: () => setUploadOpen(false)
|
|
4662
|
+
}
|
|
4663
|
+
)
|
|
4664
|
+
] }) });
|
|
4665
|
+
}
|
|
4666
|
+
function RecordsEmptyState({ onUpload }) {
|
|
4667
|
+
return /* @__PURE__ */ jsxs30("div", { className: "mr-records-view__empty", children: [
|
|
4668
|
+
/* @__PURE__ */ jsx35(EmptyRecordsIcon, { size: 96 }),
|
|
4669
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__empty-title", children: "No records yet" }),
|
|
4670
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__empty-desc", children: "Upload your first record to get started \u2014 lab reports, scans, prescriptions, anything works." }),
|
|
4671
|
+
onUpload && /* @__PURE__ */ jsxs30("button", { type: "button", className: "mr-records-view__upload-cta", onClick: onUpload, children: [
|
|
4672
|
+
/* @__PURE__ */ jsx35(Upload3, { size: 16, "aria-hidden": true }),
|
|
4673
|
+
"Upload"
|
|
4674
|
+
] })
|
|
4675
|
+
] });
|
|
4676
|
+
}
|
|
4677
|
+
function RecordsFilteredEmpty() {
|
|
4678
|
+
return /* @__PURE__ */ jsxs30("div", { className: "mr-records-view__filtered-empty", children: [
|
|
4679
|
+
/* @__PURE__ */ jsx35(FilteredEmptyIcon, { size: 96 }),
|
|
4680
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-view__filtered-empty-text", children: [
|
|
4681
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__filtered-empty-title", children: "No records found" }),
|
|
4682
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__filtered-empty-desc", children: "Nothing matched your filters. Try adjusting or clearing them." })
|
|
4683
|
+
] })
|
|
4684
|
+
] });
|
|
4685
|
+
}
|
|
4686
|
+
function RecordsLoadingState() {
|
|
4687
|
+
return /* @__PURE__ */ jsxs30("div", { className: "mr-records-loading", children: [
|
|
4688
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__toolbar", children: [
|
|
4689
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "circle", width: 36, height: 36 }),
|
|
4690
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 220, height: 32 }),
|
|
4691
|
+
/* @__PURE__ */ jsx35("div", { className: "mr-records-loading__toolbar-spacer" }),
|
|
4692
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 72, height: 36 }),
|
|
4693
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 92, height: 36 })
|
|
4694
|
+
] }),
|
|
4695
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__body", children: [
|
|
4696
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__sidebar", children: [
|
|
4697
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 120, height: 20 }),
|
|
4698
|
+
Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__sidebar-item", children: [
|
|
4699
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "card", width: 40, height: 40 }),
|
|
4700
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__sidebar-lines", children: [
|
|
4701
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 90, height: 14 }),
|
|
4702
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 130, height: 12 })
|
|
4703
|
+
] })
|
|
4704
|
+
] }, i))
|
|
4705
|
+
] }),
|
|
4706
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__grid", children: [
|
|
4707
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 100, height: 16 }),
|
|
4708
|
+
/* @__PURE__ */ jsx35("div", { className: "mr-records-loading__cards", children: Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__card", children: [
|
|
4709
|
+
/* @__PURE__ */ jsxs30("div", { className: "mr-records-loading__card-head", children: [
|
|
4710
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 120, height: 16 }),
|
|
4711
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: 70, height: 12 })
|
|
4712
|
+
] }),
|
|
4713
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "card", height: 118 }),
|
|
4714
|
+
/* @__PURE__ */ jsx35(Skeleton, { variant: "text", width: "60%", height: 16 })
|
|
4715
|
+
] }, i)) })
|
|
4716
|
+
] })
|
|
4717
|
+
] })
|
|
4718
|
+
] });
|
|
4719
|
+
}
|
|
4720
|
+
function ActiveFiltersBar({ filters, labelOf, onRemoveType, onRemoveTags, onRemoveDocDate, onRemoveUploadDate, onClearAll }) {
|
|
4721
|
+
const fmt = (ms) => ms == null ? "" : new Date(ms).toLocaleDateString(void 0, { day: "2-digit", month: "2-digit", year: "numeric" });
|
|
4722
|
+
const chips = [];
|
|
4723
|
+
if (filters.type) chips.push({ key: "type", label: labelOf(filters.type), onRemove: onRemoveType });
|
|
4724
|
+
if (filters.documentDateFrom != null || filters.documentDateTo != null) {
|
|
4725
|
+
const from = fmt(filters.documentDateFrom);
|
|
4726
|
+
const to = fmt(filters.documentDateTo);
|
|
4727
|
+
const label = from && to ? `Date: ${from} to ${to}` : from ? `Date: from ${from}` : `Date: until ${to}`;
|
|
4728
|
+
chips.push({ key: "docDate", label, onRemove: onRemoveDocDate });
|
|
4729
|
+
}
|
|
4730
|
+
if (filters.uploadDateFrom != null || filters.uploadDateTo != null) {
|
|
4731
|
+
const from = fmt(filters.uploadDateFrom);
|
|
4732
|
+
const to = fmt(filters.uploadDateTo);
|
|
4733
|
+
const label = from && to ? `Upload: ${from} to ${to}` : from ? `Upload: from ${from}` : `Upload: until ${to}`;
|
|
4734
|
+
chips.push({ key: "upDate", label, onRemove: onRemoveUploadDate });
|
|
4735
|
+
}
|
|
4736
|
+
filters.tags.forEach((tag) => chips.push({ key: `tag:${tag}`, label: `Tag: ${tag}`, onRemove: () => onRemoveTags(tag) }));
|
|
4737
|
+
if (chips.length === 0) return null;
|
|
4738
|
+
return /* @__PURE__ */ jsxs30("div", { className: "mr-active-filters", children: [
|
|
4739
|
+
chips.map((chip) => /* @__PURE__ */ jsxs30("span", { className: "mr-active-filters__chip", children: [
|
|
4740
|
+
/* @__PURE__ */ jsx35("span", { className: "mr-active-filters__chip-label", children: chip.label }),
|
|
4741
|
+
/* @__PURE__ */ jsx35("button", { type: "button", className: "mr-active-filters__chip-x", "aria-label": `Remove ${chip.label}`, onClick: chip.onRemove, children: /* @__PURE__ */ jsx35("svg", { width: "12", height: "12", viewBox: "0 0 12 12", fill: "none", "aria-hidden": true, children: /* @__PURE__ */ jsx35("path", { d: "M9 3L3 9M3 3l6 6", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round" }) }) })
|
|
4742
|
+
] }, chip.key)),
|
|
4743
|
+
/* @__PURE__ */ jsx35("button", { type: "button", className: "mr-active-filters__clear", onClick: onClearAll, children: "Clear all filters" })
|
|
4744
|
+
] });
|
|
4745
|
+
}
|
|
4746
|
+
function RecordsErrorState({ onRetry }) {
|
|
4747
|
+
return /* @__PURE__ */ jsxs30("div", { className: "mr-records-view__empty mr-records-view__empty--error", children: [
|
|
4748
|
+
/* @__PURE__ */ jsx35("span", { className: "mr-records-view__empty-icon mr-records-view__empty-icon--error", children: /* @__PURE__ */ jsx35(TriangleAlert, { size: 24, "aria-hidden": true }) }),
|
|
4749
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__empty-title", children: "Couldn't load records" }),
|
|
4750
|
+
/* @__PURE__ */ jsx35("p", { className: "mr-records-view__empty-desc", children: "Something went wrong while loading this patient's records." }),
|
|
4751
|
+
/* @__PURE__ */ jsxs30(
|
|
4752
|
+
"button",
|
|
4753
|
+
{
|
|
4754
|
+
type: "button",
|
|
4755
|
+
className: "mr-records-view__retry",
|
|
4756
|
+
onClick: () => void onRetry(),
|
|
4757
|
+
children: [
|
|
4758
|
+
/* @__PURE__ */ jsx35(RefreshCcw2, { size: 16, "aria-hidden": true }),
|
|
4759
|
+
"Try again"
|
|
4760
|
+
]
|
|
4761
|
+
}
|
|
4762
|
+
)
|
|
4763
|
+
] });
|
|
4764
|
+
}
|
|
4765
|
+
export {
|
|
4766
|
+
Badge,
|
|
4767
|
+
CORE_SDK_AVAILABLE,
|
|
4768
|
+
EmptyRecordsIcon,
|
|
4769
|
+
FilterChip,
|
|
4770
|
+
IconButton,
|
|
4771
|
+
RecordCard,
|
|
4772
|
+
RecordRow,
|
|
4773
|
+
RecordsView,
|
|
4774
|
+
SdkProvider,
|
|
4775
|
+
SidebarItem,
|
|
4776
|
+
Skeleton,
|
|
4777
|
+
TagChip,
|
|
4778
|
+
Thumbnail,
|
|
4779
|
+
logoutMedicalRecords,
|
|
4780
|
+
useCaseById2 as useCaseById,
|
|
4781
|
+
useCaseIds2 as useCaseIds,
|
|
4782
|
+
useCasesConnection,
|
|
4783
|
+
useCasesStatus2 as useCasesStatus,
|
|
4784
|
+
useFilteredRecordIds2 as useFilteredRecordIds,
|
|
4785
|
+
useIsSelected2 as useIsSelected,
|
|
4786
|
+
useLogout,
|
|
4787
|
+
useRecordById2 as useRecordById,
|
|
4788
|
+
useRecordIdRange2 as useRecordIdRange,
|
|
4789
|
+
useRecordsConnection,
|
|
4790
|
+
useRecordsCount2 as useRecordsCount,
|
|
4791
|
+
useRecordsStatus2 as useRecordsStatus,
|
|
4792
|
+
useSdk,
|
|
4793
|
+
useThumbnailUrl2 as useThumbnailUrl,
|
|
4794
|
+
useUploadConnection
|
|
4795
|
+
};
|
|
4796
|
+
//# sourceMappingURL=index.mjs.map
|