@natoe/colab 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +21 -13
- package/dist/index.d.ts +21 -13
- package/dist/index.js +452 -186
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +453 -187
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
var React4 = require('react');
|
|
4
4
|
var phoenix = require('phoenix');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var reactDom = require('react-dom');
|
|
6
7
|
|
|
7
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
8
9
|
|
|
@@ -376,7 +377,9 @@ function CollabProvider({ config, apiBaseUrl, children }) {
|
|
|
376
377
|
const data = snakeToCamel(await response.json());
|
|
377
378
|
orderIds.forEach((orderId) => {
|
|
378
379
|
const preview = data.previews[orderId] ?? null;
|
|
379
|
-
|
|
380
|
+
if (preview !== null) {
|
|
381
|
+
previewCache.current.set(orderId, preview);
|
|
382
|
+
}
|
|
380
383
|
resolvers.get(orderId)?.forEach((resolve) => resolve(preview));
|
|
381
384
|
});
|
|
382
385
|
} catch (error) {
|
|
@@ -423,7 +426,8 @@ function CollabProvider({ config, apiBaseUrl, children }) {
|
|
|
423
426
|
if (!response.ok) {
|
|
424
427
|
throw { code: "FETCH_ERROR", message: "Failed to fetch messages", status: response.status };
|
|
425
428
|
}
|
|
426
|
-
|
|
429
|
+
const msgs = snakeToCamel(await response.json());
|
|
430
|
+
return msgs.sort((a, b) => a.insertedAt.localeCompare(b.insertedAt));
|
|
427
431
|
},
|
|
428
432
|
[apiBaseUrl, authHeaders]
|
|
429
433
|
);
|
|
@@ -897,8 +901,8 @@ function useConversation({
|
|
|
897
901
|
const payload = {
|
|
898
902
|
body: "Voice message",
|
|
899
903
|
type: "audio",
|
|
900
|
-
|
|
901
|
-
|
|
904
|
+
media_url: url,
|
|
905
|
+
media_duration: duration
|
|
902
906
|
};
|
|
903
907
|
const { conv, persistedByCreate } = await ensureConversation(payload);
|
|
904
908
|
if (persistedByCreate) return;
|
|
@@ -914,8 +918,8 @@ function useConversation({
|
|
|
914
918
|
const payload = {
|
|
915
919
|
body: file.name,
|
|
916
920
|
type: isImage ? "image" : "file",
|
|
917
|
-
|
|
918
|
-
|
|
921
|
+
media_url: url,
|
|
922
|
+
file_name: file.name
|
|
919
923
|
};
|
|
920
924
|
const { conv, persistedByCreate } = await ensureConversation(payload);
|
|
921
925
|
if (persistedByCreate) return;
|
|
@@ -1147,71 +1151,190 @@ function useDeepLinks() {
|
|
|
1147
1151
|
function escapeRegex(string) {
|
|
1148
1152
|
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1149
1153
|
}
|
|
1154
|
+
function DicomIcon({ size = 18, color = "currentColor" }) {
|
|
1155
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1156
|
+
"svg",
|
|
1157
|
+
{
|
|
1158
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1159
|
+
width: size,
|
|
1160
|
+
height: size,
|
|
1161
|
+
viewBox: "0 0 24 24",
|
|
1162
|
+
fill: "none",
|
|
1163
|
+
stroke: color,
|
|
1164
|
+
strokeWidth: "2",
|
|
1165
|
+
strokeLinecap: "round",
|
|
1166
|
+
strokeLinejoin: "round",
|
|
1167
|
+
"aria-hidden": "true",
|
|
1168
|
+
children: [
|
|
1169
|
+
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "4", y: "4", width: "13", height: "13", rx: "2" }),
|
|
1170
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 7h13a2 2 0 0 1 2 2v11", opacity: "0.6" }),
|
|
1171
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "9", cy: "9.5", r: "1.2", fill: color, stroke: "none" }),
|
|
1172
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 14l3-3 4 4 2-2 3 3" })
|
|
1173
|
+
]
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
}
|
|
1177
|
+
function SettingsIcon({ size = 18, color = "currentColor" }) {
|
|
1178
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1179
|
+
"svg",
|
|
1180
|
+
{
|
|
1181
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1182
|
+
width: size,
|
|
1183
|
+
height: size,
|
|
1184
|
+
viewBox: "0 0 24 24",
|
|
1185
|
+
fill: color,
|
|
1186
|
+
"aria-hidden": "true",
|
|
1187
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58a.49.49 0 0 0 .12-.61l-1.92-3.32a.488.488 0 0 0-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54a.484.484 0 0 0-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.09.63-.09.94s.02.64.07.94l-2.03 1.58a.49.49 0 0 0-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z" })
|
|
1188
|
+
}
|
|
1189
|
+
);
|
|
1190
|
+
}
|
|
1191
|
+
function BackIcon({ size = 22, color = "currentColor" }) {
|
|
1192
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1193
|
+
"svg",
|
|
1194
|
+
{
|
|
1195
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1196
|
+
width: size,
|
|
1197
|
+
height: size,
|
|
1198
|
+
viewBox: "0 0 24 24",
|
|
1199
|
+
fill: color,
|
|
1200
|
+
"aria-hidden": "true",
|
|
1201
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" })
|
|
1202
|
+
}
|
|
1203
|
+
);
|
|
1204
|
+
}
|
|
1150
1205
|
function PatientHeader({
|
|
1151
1206
|
patientData,
|
|
1152
1207
|
onOpenDicom,
|
|
1153
1208
|
onOpenSettings,
|
|
1209
|
+
onBack,
|
|
1154
1210
|
className
|
|
1155
1211
|
}) {
|
|
1156
1212
|
const hasDicom = !!(patientData.studyId && patientData.storageId);
|
|
1213
|
+
const meta = [];
|
|
1214
|
+
if (patientData.patientAge) meta.push({ label: "Age", value: String(patientData.patientAge) });
|
|
1215
|
+
if (patientData.patientSex) meta.push({ label: "Sex", value: String(patientData.patientSex) });
|
|
1216
|
+
if (patientData.studyType) meta.push({ label: "Modality", value: patientData.studyType });
|
|
1217
|
+
if (patientData.bodyParts && patientData.bodyParts.length > 0) {
|
|
1218
|
+
meta.push({ label: "Body part", value: patientData.bodyParts.join(", ") });
|
|
1219
|
+
}
|
|
1220
|
+
if (patientData.referringPhysician) {
|
|
1221
|
+
meta.push({ label: "Ref", value: patientData.referringPhysician });
|
|
1222
|
+
}
|
|
1157
1223
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles.container, children: [
|
|
1158
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1224
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.nameRow, children: [
|
|
1225
|
+
onBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1226
|
+
"button",
|
|
1227
|
+
{
|
|
1228
|
+
type: "button",
|
|
1229
|
+
onClick: onBack,
|
|
1230
|
+
style: styles.backButton,
|
|
1231
|
+
"aria-label": "Back to conversations",
|
|
1232
|
+
title: "Back to conversations",
|
|
1233
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(BackIcon, { size: 22, color: "#1f2937" })
|
|
1234
|
+
}
|
|
1235
|
+
),
|
|
1236
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.nameText, children: buildChannelName(patientData) })
|
|
1170
1237
|
] }),
|
|
1171
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1238
|
+
meta.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles.metaRow, children: meta.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles.metaItem, children: [
|
|
1239
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles.metaLabel, children: [
|
|
1240
|
+
item.label,
|
|
1241
|
+
":"
|
|
1242
|
+
] }),
|
|
1243
|
+
" ",
|
|
1244
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles.metaValue, children: item.value })
|
|
1245
|
+
] }, item.label)) }),
|
|
1246
|
+
hasDicom && onOpenDicom || onOpenSettings ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles.actions, children: [
|
|
1247
|
+
hasDicom && onOpenDicom && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1248
|
+
"button",
|
|
1249
|
+
{
|
|
1250
|
+
onClick: onOpenDicom,
|
|
1251
|
+
style: styles.dicomButton,
|
|
1252
|
+
type: "button",
|
|
1253
|
+
"aria-label": "View DICOM study",
|
|
1254
|
+
children: [
|
|
1255
|
+
/* @__PURE__ */ jsxRuntime.jsx(DicomIcon, { size: 18, color: "#ffffff" }),
|
|
1256
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "View DICOM" })
|
|
1257
|
+
]
|
|
1258
|
+
}
|
|
1259
|
+
),
|
|
1260
|
+
onOpenSettings && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1261
|
+
"button",
|
|
1262
|
+
{
|
|
1263
|
+
onClick: onOpenSettings,
|
|
1264
|
+
style: styles.settingsButton,
|
|
1265
|
+
type: "button",
|
|
1266
|
+
"aria-label": "Open channel settings",
|
|
1267
|
+
children: [
|
|
1268
|
+
/* @__PURE__ */ jsxRuntime.jsx(SettingsIcon, { size: 18, color: "#374151" }),
|
|
1269
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Settings" })
|
|
1270
|
+
]
|
|
1271
|
+
}
|
|
1272
|
+
)
|
|
1273
|
+
] }) : null
|
|
1175
1274
|
] });
|
|
1176
1275
|
}
|
|
1177
1276
|
var styles = {
|
|
1178
1277
|
container: {
|
|
1179
|
-
padding: "
|
|
1278
|
+
padding: "14px 16px",
|
|
1180
1279
|
borderBottom: "1px solid #e5e7eb",
|
|
1181
1280
|
backgroundColor: "#f9fafb"
|
|
1182
1281
|
},
|
|
1183
|
-
|
|
1282
|
+
nameRow: {
|
|
1184
1283
|
display: "flex",
|
|
1185
|
-
|
|
1186
|
-
|
|
1284
|
+
alignItems: "center",
|
|
1285
|
+
gap: "6px"
|
|
1187
1286
|
},
|
|
1188
|
-
|
|
1287
|
+
backButton: {
|
|
1288
|
+
width: "36px",
|
|
1289
|
+
height: "36px",
|
|
1189
1290
|
display: "flex",
|
|
1190
1291
|
alignItems: "center",
|
|
1191
|
-
|
|
1192
|
-
|
|
1292
|
+
justifyContent: "center",
|
|
1293
|
+
marginLeft: "-8px",
|
|
1294
|
+
backgroundColor: "transparent",
|
|
1295
|
+
border: "none",
|
|
1296
|
+
borderRadius: "50%",
|
|
1297
|
+
cursor: "pointer",
|
|
1298
|
+
flexShrink: 0
|
|
1193
1299
|
},
|
|
1194
|
-
|
|
1300
|
+
nameText: {
|
|
1301
|
+
fontSize: "18px",
|
|
1195
1302
|
fontWeight: 600,
|
|
1196
|
-
|
|
1197
|
-
|
|
1303
|
+
color: "#111827",
|
|
1304
|
+
lineHeight: 1.3,
|
|
1305
|
+
minWidth: 0,
|
|
1306
|
+
overflow: "hidden",
|
|
1307
|
+
textOverflow: "ellipsis",
|
|
1308
|
+
whiteSpace: "nowrap"
|
|
1198
1309
|
},
|
|
1199
|
-
|
|
1310
|
+
metaRow: {
|
|
1200
1311
|
display: "flex",
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1312
|
+
flexWrap: "wrap",
|
|
1313
|
+
columnGap: "14px",
|
|
1314
|
+
rowGap: "4px",
|
|
1315
|
+
marginTop: "6px"
|
|
1204
1316
|
},
|
|
1205
|
-
|
|
1317
|
+
metaItem: {
|
|
1206
1318
|
fontSize: "13px",
|
|
1207
|
-
color: "#
|
|
1319
|
+
color: "#374151",
|
|
1320
|
+
whiteSpace: "nowrap"
|
|
1321
|
+
},
|
|
1322
|
+
metaLabel: {
|
|
1323
|
+
color: "#6b7280",
|
|
1324
|
+
fontWeight: 500
|
|
1325
|
+
},
|
|
1326
|
+
metaValue: {
|
|
1327
|
+
color: "#111827"
|
|
1208
1328
|
},
|
|
1209
1329
|
actions: {
|
|
1210
1330
|
display: "flex",
|
|
1211
1331
|
gap: "8px",
|
|
1212
|
-
marginTop: "
|
|
1332
|
+
marginTop: "10px"
|
|
1213
1333
|
},
|
|
1214
1334
|
dicomButton: {
|
|
1335
|
+
display: "inline-flex",
|
|
1336
|
+
alignItems: "center",
|
|
1337
|
+
gap: "8px",
|
|
1215
1338
|
minHeight: "40px",
|
|
1216
1339
|
padding: "8px 16px",
|
|
1217
1340
|
fontSize: "14px",
|
|
@@ -1223,6 +1346,9 @@ var styles = {
|
|
|
1223
1346
|
cursor: "pointer"
|
|
1224
1347
|
},
|
|
1225
1348
|
settingsButton: {
|
|
1349
|
+
display: "inline-flex",
|
|
1350
|
+
alignItems: "center",
|
|
1351
|
+
gap: "8px",
|
|
1226
1352
|
minHeight: "40px",
|
|
1227
1353
|
padding: "8px 16px",
|
|
1228
1354
|
fontSize: "14px",
|
|
@@ -1439,6 +1565,8 @@ function MoreIcon({ size = 18, color = "currentColor" }) {
|
|
|
1439
1565
|
}
|
|
1440
1566
|
);
|
|
1441
1567
|
}
|
|
1568
|
+
var VIEWPORT_MARGIN = 8;
|
|
1569
|
+
var TRIGGER_GAP = 4;
|
|
1442
1570
|
function MessageActionsMenu({
|
|
1443
1571
|
message,
|
|
1444
1572
|
onReply,
|
|
@@ -1450,16 +1578,43 @@ function MessageActionsMenu({
|
|
|
1450
1578
|
className
|
|
1451
1579
|
}) {
|
|
1452
1580
|
const [isOpen, setIsOpen] = React4.useState(false);
|
|
1453
|
-
const
|
|
1581
|
+
const [coords, setCoords] = React4.useState(null);
|
|
1454
1582
|
const triggerRef = React4.useRef(null);
|
|
1583
|
+
const menuRef = React4.useRef(null);
|
|
1455
1584
|
const isPinned = !!message.isPinned;
|
|
1456
1585
|
const canCopy = message.type === "text" && !!message.body;
|
|
1586
|
+
React4.useLayoutEffect(() => {
|
|
1587
|
+
if (!isOpen) {
|
|
1588
|
+
setCoords(null);
|
|
1589
|
+
return;
|
|
1590
|
+
}
|
|
1591
|
+
const trigger = triggerRef.current;
|
|
1592
|
+
const menu2 = menuRef.current;
|
|
1593
|
+
if (!trigger || !menu2) return;
|
|
1594
|
+
const triggerRect = trigger.getBoundingClientRect();
|
|
1595
|
+
const menuRect = menu2.getBoundingClientRect();
|
|
1596
|
+
const vw = window.innerWidth;
|
|
1597
|
+
const vh = window.innerHeight;
|
|
1598
|
+
const spaceBelow = vh - triggerRect.bottom;
|
|
1599
|
+
const spaceAbove = triggerRect.top;
|
|
1600
|
+
const placeAbove = spaceBelow < menuRect.height + TRIGGER_GAP + VIEWPORT_MARGIN && spaceAbove > spaceBelow;
|
|
1601
|
+
const top = placeAbove ? triggerRect.top - menuRect.height - TRIGGER_GAP : triggerRect.bottom + TRIGGER_GAP;
|
|
1602
|
+
const preferredLeft = anchorRight ? triggerRect.right - menuRect.width : triggerRect.left;
|
|
1603
|
+
const left = Math.max(
|
|
1604
|
+
VIEWPORT_MARGIN,
|
|
1605
|
+
Math.min(preferredLeft, vw - menuRect.width - VIEWPORT_MARGIN)
|
|
1606
|
+
);
|
|
1607
|
+
const clampedTop = Math.max(
|
|
1608
|
+
VIEWPORT_MARGIN,
|
|
1609
|
+
Math.min(top, vh - menuRect.height - VIEWPORT_MARGIN)
|
|
1610
|
+
);
|
|
1611
|
+
setCoords({ top: clampedTop, left });
|
|
1612
|
+
}, [isOpen, anchorRight]);
|
|
1457
1613
|
React4.useEffect(() => {
|
|
1458
1614
|
if (!isOpen) return;
|
|
1615
|
+
const isInside = (node) => !!node && (triggerRef.current?.contains(node) === true || menuRef.current?.contains(node) === true);
|
|
1459
1616
|
const handleClick = (e) => {
|
|
1460
|
-
if (!
|
|
1461
|
-
setIsOpen(false);
|
|
1462
|
-
}
|
|
1617
|
+
if (!isInside(e.target)) setIsOpen(false);
|
|
1463
1618
|
};
|
|
1464
1619
|
const handleKey = (e) => {
|
|
1465
1620
|
if (e.key === "Escape") {
|
|
@@ -1467,18 +1622,100 @@ function MessageActionsMenu({
|
|
|
1467
1622
|
triggerRef.current?.focus();
|
|
1468
1623
|
}
|
|
1469
1624
|
};
|
|
1625
|
+
const handleScroll = (e) => {
|
|
1626
|
+
if (!isInside(e.target)) setIsOpen(false);
|
|
1627
|
+
};
|
|
1628
|
+
const handleResize = () => setIsOpen(false);
|
|
1470
1629
|
document.addEventListener("mousedown", handleClick);
|
|
1471
1630
|
document.addEventListener("keydown", handleKey);
|
|
1631
|
+
window.addEventListener("resize", handleResize);
|
|
1632
|
+
window.addEventListener("scroll", handleScroll, true);
|
|
1472
1633
|
return () => {
|
|
1473
1634
|
document.removeEventListener("mousedown", handleClick);
|
|
1474
1635
|
document.removeEventListener("keydown", handleKey);
|
|
1636
|
+
window.removeEventListener("resize", handleResize);
|
|
1637
|
+
window.removeEventListener("scroll", handleScroll, true);
|
|
1475
1638
|
};
|
|
1476
1639
|
}, [isOpen]);
|
|
1477
1640
|
const run = (fn) => {
|
|
1478
1641
|
setIsOpen(false);
|
|
1479
1642
|
fn();
|
|
1480
1643
|
};
|
|
1481
|
-
|
|
1644
|
+
const menu = isOpen ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1645
|
+
"div",
|
|
1646
|
+
{
|
|
1647
|
+
ref: menuRef,
|
|
1648
|
+
role: "menu",
|
|
1649
|
+
"aria-label": "Message actions",
|
|
1650
|
+
style: {
|
|
1651
|
+
...styles4.menu,
|
|
1652
|
+
// Render off-screen on first paint so we can measure before placing,
|
|
1653
|
+
// then snap to computed coords on the next layout pass.
|
|
1654
|
+
top: coords?.top ?? -9999,
|
|
1655
|
+
left: coords?.left ?? -9999,
|
|
1656
|
+
visibility: coords ? "visible" : "hidden"
|
|
1657
|
+
},
|
|
1658
|
+
children: [
|
|
1659
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1660
|
+
"button",
|
|
1661
|
+
{
|
|
1662
|
+
type: "button",
|
|
1663
|
+
role: "menuitem",
|
|
1664
|
+
onClick: () => run(() => onReply(message)),
|
|
1665
|
+
style: styles4.item,
|
|
1666
|
+
children: [
|
|
1667
|
+
/* @__PURE__ */ jsxRuntime.jsx(ReplyIcon, { size: 18, color: "#374151" }),
|
|
1668
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reply" })
|
|
1669
|
+
]
|
|
1670
|
+
}
|
|
1671
|
+
),
|
|
1672
|
+
isPinned ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1673
|
+
"button",
|
|
1674
|
+
{
|
|
1675
|
+
type: "button",
|
|
1676
|
+
role: "menuitem",
|
|
1677
|
+
onClick: () => run(() => onUnpin(message.id)),
|
|
1678
|
+
style: styles4.item,
|
|
1679
|
+
children: [
|
|
1680
|
+
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1681
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Unpin" })
|
|
1682
|
+
]
|
|
1683
|
+
}
|
|
1684
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1685
|
+
"button",
|
|
1686
|
+
{
|
|
1687
|
+
type: "button",
|
|
1688
|
+
role: "menuitem",
|
|
1689
|
+
onClick: () => run(() => onPin(message.id)),
|
|
1690
|
+
disabled: pinDisabled,
|
|
1691
|
+
style: {
|
|
1692
|
+
...styles4.item,
|
|
1693
|
+
...pinDisabled ? styles4.itemDisabled : {}
|
|
1694
|
+
},
|
|
1695
|
+
title: pinDisabled ? "Pin limit reached (max 3)" : void 0,
|
|
1696
|
+
children: [
|
|
1697
|
+
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1698
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: pinDisabled ? "Pin (limit reached)" : "Pin" })
|
|
1699
|
+
]
|
|
1700
|
+
}
|
|
1701
|
+
),
|
|
1702
|
+
canCopy && onCopy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1703
|
+
"button",
|
|
1704
|
+
{
|
|
1705
|
+
type: "button",
|
|
1706
|
+
role: "menuitem",
|
|
1707
|
+
onClick: () => run(() => onCopy(message.body)),
|
|
1708
|
+
style: styles4.item,
|
|
1709
|
+
children: [
|
|
1710
|
+
/* @__PURE__ */ jsxRuntime.jsx(CopyIcon, { size: 16, color: "#374151" }),
|
|
1711
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy text" })
|
|
1712
|
+
]
|
|
1713
|
+
}
|
|
1714
|
+
)
|
|
1715
|
+
]
|
|
1716
|
+
}
|
|
1717
|
+
) : null;
|
|
1718
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles4.wrapper, children: [
|
|
1482
1719
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1483
1720
|
"button",
|
|
1484
1721
|
{
|
|
@@ -1496,75 +1733,7 @@ function MessageActionsMenu({
|
|
|
1496
1733
|
children: /* @__PURE__ */ jsxRuntime.jsx(MoreIcon, { size: 18, color: "#4b5563" })
|
|
1497
1734
|
}
|
|
1498
1735
|
),
|
|
1499
|
-
|
|
1500
|
-
"div",
|
|
1501
|
-
{
|
|
1502
|
-
role: "menu",
|
|
1503
|
-
"aria-label": "Message actions",
|
|
1504
|
-
style: {
|
|
1505
|
-
...styles4.menu,
|
|
1506
|
-
...anchorRight ? styles4.menuRight : styles4.menuLeft
|
|
1507
|
-
},
|
|
1508
|
-
children: [
|
|
1509
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1510
|
-
"button",
|
|
1511
|
-
{
|
|
1512
|
-
type: "button",
|
|
1513
|
-
role: "menuitem",
|
|
1514
|
-
onClick: () => run(() => onReply(message)),
|
|
1515
|
-
style: styles4.item,
|
|
1516
|
-
children: [
|
|
1517
|
-
/* @__PURE__ */ jsxRuntime.jsx(ReplyIcon, { size: 18, color: "#374151" }),
|
|
1518
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Reply" })
|
|
1519
|
-
]
|
|
1520
|
-
}
|
|
1521
|
-
),
|
|
1522
|
-
isPinned ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1523
|
-
"button",
|
|
1524
|
-
{
|
|
1525
|
-
type: "button",
|
|
1526
|
-
role: "menuitem",
|
|
1527
|
-
onClick: () => run(() => onUnpin(message.id)),
|
|
1528
|
-
style: styles4.item,
|
|
1529
|
-
children: [
|
|
1530
|
-
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1531
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Unpin" })
|
|
1532
|
-
]
|
|
1533
|
-
}
|
|
1534
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1535
|
-
"button",
|
|
1536
|
-
{
|
|
1537
|
-
type: "button",
|
|
1538
|
-
role: "menuitem",
|
|
1539
|
-
onClick: () => run(() => onPin(message.id)),
|
|
1540
|
-
disabled: pinDisabled,
|
|
1541
|
-
style: {
|
|
1542
|
-
...styles4.item,
|
|
1543
|
-
...pinDisabled ? styles4.itemDisabled : {}
|
|
1544
|
-
},
|
|
1545
|
-
title: pinDisabled ? "Pin limit reached (max 3)" : void 0,
|
|
1546
|
-
children: [
|
|
1547
|
-
/* @__PURE__ */ jsxRuntime.jsx(PinIcon, { size: 16, color: "#374151" }),
|
|
1548
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: pinDisabled ? "Pin (limit reached)" : "Pin" })
|
|
1549
|
-
]
|
|
1550
|
-
}
|
|
1551
|
-
),
|
|
1552
|
-
canCopy && onCopy && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1553
|
-
"button",
|
|
1554
|
-
{
|
|
1555
|
-
type: "button",
|
|
1556
|
-
role: "menuitem",
|
|
1557
|
-
onClick: () => run(() => onCopy(message.body)),
|
|
1558
|
-
style: styles4.item,
|
|
1559
|
-
children: [
|
|
1560
|
-
/* @__PURE__ */ jsxRuntime.jsx(CopyIcon, { size: 16, color: "#374151" }),
|
|
1561
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy text" })
|
|
1562
|
-
]
|
|
1563
|
-
}
|
|
1564
|
-
)
|
|
1565
|
-
]
|
|
1566
|
-
}
|
|
1567
|
-
)
|
|
1736
|
+
menu && typeof document !== "undefined" ? reactDom.createPortal(menu, document.body) : null
|
|
1568
1737
|
] });
|
|
1569
1738
|
}
|
|
1570
1739
|
var styles4 = {
|
|
@@ -1585,22 +1754,15 @@ var styles4 = {
|
|
|
1585
1754
|
color: "#4b5563"
|
|
1586
1755
|
},
|
|
1587
1756
|
menu: {
|
|
1588
|
-
position: "
|
|
1589
|
-
top: "100%",
|
|
1590
|
-
marginTop: "4px",
|
|
1757
|
+
position: "fixed",
|
|
1591
1758
|
minWidth: "160px",
|
|
1592
1759
|
backgroundColor: "#ffffff",
|
|
1593
1760
|
border: "1px solid #e5e7eb",
|
|
1594
1761
|
borderRadius: "10px",
|
|
1595
1762
|
boxShadow: "0 6px 18px rgba(0, 0, 0, 0.12)",
|
|
1596
1763
|
padding: "4px",
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
menuLeft: {
|
|
1600
|
-
left: 0
|
|
1601
|
-
},
|
|
1602
|
-
menuRight: {
|
|
1603
|
-
right: 0
|
|
1764
|
+
// Above the floating popup (z-index 9999) but below any future modal.
|
|
1765
|
+
zIndex: 1e4
|
|
1604
1766
|
},
|
|
1605
1767
|
item: {
|
|
1606
1768
|
display: "flex",
|
|
@@ -2253,31 +2415,34 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
2253
2415
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.emptySubtitle, children: "Start the conversation \u2014 everyone on this case will see what you write." })
|
|
2254
2416
|
] }),
|
|
2255
2417
|
messages.length === 0 && isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.firstLoad, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 20 }) }),
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2263
|
-
|
|
2264
|
-
{
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2418
|
+
(() => {
|
|
2419
|
+
let lastValidBucket = null;
|
|
2420
|
+
return messages.map((message) => {
|
|
2421
|
+
const currentBucket = dayBucketKey(message.insertedAt);
|
|
2422
|
+
const showDivider = !!currentBucket && currentBucket !== lastValidBucket;
|
|
2423
|
+
if (currentBucket) lastValidBucket = currentBucket;
|
|
2424
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React4__default.default.Fragment, { children: [
|
|
2425
|
+
showDivider && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.dayDivider, role: "separator", "aria-label": "Date", children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles6.dayDividerPill, children: formatDayDivider(message.insertedAt) }) }),
|
|
2426
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-message-id": message.id, "data-natoe-message-bubble": true, style: styles6.bubbleSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2427
|
+
MessageBubble,
|
|
2428
|
+
{
|
|
2429
|
+
message,
|
|
2430
|
+
isOwn: message.senderId === currentUserId,
|
|
2431
|
+
participants,
|
|
2432
|
+
currentUserId,
|
|
2433
|
+
showSeenBy,
|
|
2434
|
+
onDeepLinkClick,
|
|
2435
|
+
onReply,
|
|
2436
|
+
onPin,
|
|
2437
|
+
onUnpin,
|
|
2438
|
+
onCopy,
|
|
2439
|
+
onRetry,
|
|
2440
|
+
pinDisabled
|
|
2441
|
+
}
|
|
2442
|
+
) })
|
|
2443
|
+
] }, message.id);
|
|
2444
|
+
});
|
|
2445
|
+
})(),
|
|
2281
2446
|
typingUsers.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.typingIndicator, children: [
|
|
2282
2447
|
typingUsers.map((t) => t.userName ?? "Someone").join(", "),
|
|
2283
2448
|
typingUsers.length === 1 ? " is " : " are ",
|
|
@@ -2357,7 +2522,11 @@ var styles6 = {
|
|
|
2357
2522
|
dayDivider: {
|
|
2358
2523
|
display: "flex",
|
|
2359
2524
|
justifyContent: "center",
|
|
2360
|
-
margin: "12px 0 8px"
|
|
2525
|
+
margin: "12px 0 8px",
|
|
2526
|
+
position: "sticky",
|
|
2527
|
+
top: "4px",
|
|
2528
|
+
zIndex: 1,
|
|
2529
|
+
pointerEvents: "none"
|
|
2361
2530
|
},
|
|
2362
2531
|
dayDividerPill: {
|
|
2363
2532
|
display: "inline-block",
|
|
@@ -2367,7 +2536,11 @@ var styles6 = {
|
|
|
2367
2536
|
color: "#334155",
|
|
2368
2537
|
backgroundColor: "#e2e8f0",
|
|
2369
2538
|
borderRadius: "12px",
|
|
2370
|
-
letterSpacing: "0.2px"
|
|
2539
|
+
letterSpacing: "0.2px",
|
|
2540
|
+
boxShadow: "0 1px 2px rgba(0, 0, 0, 0.04)"
|
|
2541
|
+
},
|
|
2542
|
+
bubbleSlot: {
|
|
2543
|
+
animation: "natoe-colab-message-in 180ms ease-out"
|
|
2371
2544
|
}
|
|
2372
2545
|
};
|
|
2373
2546
|
function ReplyPreview({ message, onCancel, className }) {
|
|
@@ -3419,11 +3592,52 @@ var styles12 = {
|
|
|
3419
3592
|
letterSpacing: "0.4px"
|
|
3420
3593
|
}
|
|
3421
3594
|
};
|
|
3595
|
+
|
|
3596
|
+
// src/core/styles.ts
|
|
3597
|
+
var FONT_STACK = '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif';
|
|
3598
|
+
var ROOT_CLASS = "natoe-colab-root";
|
|
3599
|
+
var GLOBAL_STYLE_ID = "natoe-colab-global-styles";
|
|
3600
|
+
var GLOBAL_CSS = `
|
|
3601
|
+
@keyframes natoe-colab-spin { to { transform: rotate(360deg); } }
|
|
3602
|
+
|
|
3603
|
+
@keyframes natoe-colab-message-in {
|
|
3604
|
+
from { opacity: 0; transform: translateY(4px); }
|
|
3605
|
+
to { opacity: 1; transform: translateY(0); }
|
|
3606
|
+
}
|
|
3607
|
+
|
|
3608
|
+
/* High-contrast adjustments \u2014 older users on OS-level high-contrast mode
|
|
3609
|
+
get heavier borders and stronger text without losing the package look. */
|
|
3610
|
+
@media (prefers-contrast: more) {
|
|
3611
|
+
.${ROOT_CLASS} {
|
|
3612
|
+
color: #000000;
|
|
3613
|
+
}
|
|
3614
|
+
.${ROOT_CLASS} button {
|
|
3615
|
+
outline: 1px solid currentColor;
|
|
3616
|
+
}
|
|
3617
|
+
}
|
|
3618
|
+
|
|
3619
|
+
/* Honour reduced-motion preferences by killing entry animations. */
|
|
3620
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3621
|
+
.${ROOT_CLASS} [data-natoe-message-bubble] {
|
|
3622
|
+
animation: none !important;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
`;
|
|
3626
|
+
function ensureGlobalStyles() {
|
|
3627
|
+
if (typeof document === "undefined") return;
|
|
3628
|
+
if (document.getElementById(GLOBAL_STYLE_ID)) return;
|
|
3629
|
+
const style = document.createElement("style");
|
|
3630
|
+
style.id = GLOBAL_STYLE_ID;
|
|
3631
|
+
style.textContent = GLOBAL_CSS;
|
|
3632
|
+
document.head.appendChild(style);
|
|
3633
|
+
}
|
|
3634
|
+
ensureGlobalStyles();
|
|
3422
3635
|
function CollabPanel({
|
|
3423
3636
|
orderId,
|
|
3424
3637
|
patientData,
|
|
3425
3638
|
participantIds,
|
|
3426
3639
|
showSeenBy = true,
|
|
3640
|
+
onBack,
|
|
3427
3641
|
className,
|
|
3428
3642
|
style
|
|
3429
3643
|
}) {
|
|
@@ -3497,13 +3711,13 @@ function CollabPanel({
|
|
|
3497
3711
|
};
|
|
3498
3712
|
const pinDisabled = pinnedMessages.length >= MAX_PINNED_MESSAGES;
|
|
3499
3713
|
if (error) {
|
|
3500
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyles.errorState, children: [
|
|
3714
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: [ROOT_CLASS, className].filter(Boolean).join(" "), style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyles.errorState, children: [
|
|
3501
3715
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: panelStyles.errorTitle, children: "Unable to load conversation" }),
|
|
3502
3716
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: panelStyles.errorMessage, children: error })
|
|
3503
3717
|
] }) });
|
|
3504
3718
|
}
|
|
3505
3719
|
if (isLoading && !conversation) {
|
|
3506
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: panelStyles.loadingState, children: "Loading conversation..." }) });
|
|
3720
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: [ROOT_CLASS, className].filter(Boolean).join(" "), style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: panelStyles.loadingState, children: "Loading conversation..." }) });
|
|
3507
3721
|
}
|
|
3508
3722
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...panelStyles.container, ...style }, children: [
|
|
3509
3723
|
showSettings && conversation ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3531,7 +3745,8 @@ function CollabPanel({
|
|
|
3531
3745
|
patientData,
|
|
3532
3746
|
participants,
|
|
3533
3747
|
onOpenDicom: handleOpenDicom,
|
|
3534
|
-
onOpenSettings: () => setShowSettings(true)
|
|
3748
|
+
onOpenSettings: () => setShowSettings(true),
|
|
3749
|
+
onBack
|
|
3535
3750
|
}
|
|
3536
3751
|
),
|
|
3537
3752
|
pinnedMessages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3589,7 +3804,7 @@ var panelStyles = {
|
|
|
3589
3804
|
borderRadius: "8px",
|
|
3590
3805
|
overflow: "hidden",
|
|
3591
3806
|
border: "1px solid #e5e7eb",
|
|
3592
|
-
fontFamily:
|
|
3807
|
+
fontFamily: FONT_STACK
|
|
3593
3808
|
},
|
|
3594
3809
|
loadingState: {
|
|
3595
3810
|
display: "flex",
|
|
@@ -3648,6 +3863,7 @@ function ExpandIcon({ size = 18, color = "currentColor" }) {
|
|
|
3648
3863
|
}
|
|
3649
3864
|
);
|
|
3650
3865
|
}
|
|
3866
|
+
ensureGlobalStyles();
|
|
3651
3867
|
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
3652
3868
|
function CollabPopup({
|
|
3653
3869
|
orderId,
|
|
@@ -3655,6 +3871,7 @@ function CollabPopup({
|
|
|
3655
3871
|
participantIds,
|
|
3656
3872
|
isOpen,
|
|
3657
3873
|
onClose,
|
|
3874
|
+
onBack,
|
|
3658
3875
|
initialPosition,
|
|
3659
3876
|
width = 380,
|
|
3660
3877
|
height = 520,
|
|
@@ -3748,7 +3965,7 @@ function CollabPopup({
|
|
|
3748
3965
|
"div",
|
|
3749
3966
|
{
|
|
3750
3967
|
ref: containerRef,
|
|
3751
|
-
className,
|
|
3968
|
+
className: [ROOT_CLASS, className].filter(Boolean).join(" "),
|
|
3752
3969
|
role: "dialog",
|
|
3753
3970
|
"aria-modal": "true",
|
|
3754
3971
|
"aria-labelledby": titleId,
|
|
@@ -3764,7 +3981,18 @@ function CollabPopup({
|
|
|
3764
3981
|
onMouseDown: handleMouseDown,
|
|
3765
3982
|
children: [
|
|
3766
3983
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-drag-handle": true, style: styles13.titleBar, children: [
|
|
3767
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3984
|
+
onBack && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3985
|
+
"button",
|
|
3986
|
+
{
|
|
3987
|
+
onClick: onBack,
|
|
3988
|
+
style: styles13.titleButton,
|
|
3989
|
+
"aria-label": "Go back",
|
|
3990
|
+
title: "Back",
|
|
3991
|
+
type: "button",
|
|
3992
|
+
children: "\u2190"
|
|
3993
|
+
}
|
|
3994
|
+
),
|
|
3995
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: titleId, style: { ...styles13.titleText, flex: 1 }, children: buildChannelName(patientData) }),
|
|
3768
3996
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles13.titleActions, children: [
|
|
3769
3997
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3770
3998
|
"button",
|
|
@@ -3806,7 +4034,8 @@ var styles13 = {
|
|
|
3806
4034
|
flexDirection: "column",
|
|
3807
4035
|
backgroundColor: "#ffffff",
|
|
3808
4036
|
border: "1px solid #e5e7eb",
|
|
3809
|
-
transition: "height 0.2s ease"
|
|
4037
|
+
transition: "height 0.2s ease",
|
|
4038
|
+
fontFamily: FONT_STACK
|
|
3810
4039
|
},
|
|
3811
4040
|
titleBar: {
|
|
3812
4041
|
display: "flex",
|
|
@@ -4051,8 +4280,8 @@ function useInlineCollab({
|
|
|
4051
4280
|
await dispatchSend({
|
|
4052
4281
|
body: "Voice message",
|
|
4053
4282
|
type: "audio",
|
|
4054
|
-
|
|
4055
|
-
|
|
4283
|
+
media_url: url,
|
|
4284
|
+
media_duration: duration
|
|
4056
4285
|
});
|
|
4057
4286
|
} catch (err) {
|
|
4058
4287
|
setError(err instanceof Error ? err.message : "Failed to send voice message");
|
|
@@ -4078,6 +4307,7 @@ function useInlineCollab({
|
|
|
4078
4307
|
containerRef
|
|
4079
4308
|
};
|
|
4080
4309
|
}
|
|
4310
|
+
ensureGlobalStyles();
|
|
4081
4311
|
function CollabInline({
|
|
4082
4312
|
orderId,
|
|
4083
4313
|
patientData,
|
|
@@ -4100,9 +4330,9 @@ function CollabInline({
|
|
|
4100
4330
|
containerRef
|
|
4101
4331
|
} = useInlineCollab({ orderId, patientData, participantIds, messageLimit });
|
|
4102
4332
|
if (isLoading && !hasConversation) {
|
|
4103
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...styles14.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.loadingState, children: "Loading..." }) });
|
|
4333
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: [ROOT_CLASS, className].filter(Boolean).join(" "), style: { ...styles14.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.loadingState, children: "Loading..." }) });
|
|
4104
4334
|
}
|
|
4105
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className, style: { ...styles14.container, ...style }, children: [
|
|
4335
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className: [ROOT_CLASS, className].filter(Boolean).join(" "), style: { ...styles14.container, ...style }, children: [
|
|
4106
4336
|
hasConversation && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.preview, children: messages.slice(-messageLimit).map((message) => /* @__PURE__ */ jsxRuntime.jsx(InlineMessageRow, { message }, message.id)) }),
|
|
4107
4337
|
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.error, children: error }),
|
|
4108
4338
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4318,7 +4548,7 @@ var styles14 = {
|
|
|
4318
4548
|
backgroundColor: "#ffffff",
|
|
4319
4549
|
border: "1px solid #e5e7eb",
|
|
4320
4550
|
borderRadius: "8px",
|
|
4321
|
-
fontFamily:
|
|
4551
|
+
fontFamily: FONT_STACK
|
|
4322
4552
|
},
|
|
4323
4553
|
loadingState: {
|
|
4324
4554
|
padding: "8px",
|
|
@@ -4948,6 +5178,8 @@ var styles16 = {
|
|
|
4948
5178
|
textAlign: "center"
|
|
4949
5179
|
}
|
|
4950
5180
|
};
|
|
5181
|
+
ensureGlobalStyles();
|
|
5182
|
+
var COMPACT_BREAKPOINT = 720;
|
|
4951
5183
|
function CollabInbox({
|
|
4952
5184
|
initialConversationId,
|
|
4953
5185
|
onSelectConversation,
|
|
@@ -4957,34 +5189,55 @@ function CollabInbox({
|
|
|
4957
5189
|
}) {
|
|
4958
5190
|
const { conversations, isLoading, error } = useConversationList();
|
|
4959
5191
|
const [selectedId, setSelectedId] = React4.useState(initialConversationId ?? null);
|
|
5192
|
+
const [isCompact, setIsCompact] = React4.useState(
|
|
5193
|
+
() => typeof window === "undefined" ? false : window.innerWidth < COMPACT_BREAKPOINT
|
|
5194
|
+
);
|
|
5195
|
+
React4.useEffect(() => {
|
|
5196
|
+
if (typeof window === "undefined") return;
|
|
5197
|
+
const mq = window.matchMedia(`(max-width: ${COMPACT_BREAKPOINT - 1}px)`);
|
|
5198
|
+
const sync = () => setIsCompact(mq.matches);
|
|
5199
|
+
sync();
|
|
5200
|
+
mq.addEventListener("change", sync);
|
|
5201
|
+
return () => mq.removeEventListener("change", sync);
|
|
5202
|
+
}, []);
|
|
4960
5203
|
const selected = conversations.find((c) => c.id === selectedId) || null;
|
|
4961
5204
|
const handleSelect = (item) => {
|
|
4962
5205
|
setSelectedId(item.id);
|
|
4963
5206
|
onSelectConversation?.(item);
|
|
4964
5207
|
};
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
4987
|
-
|
|
5208
|
+
const showDetail = !isCompact || isCompact && !!selected;
|
|
5209
|
+
const showList = !isCompact || isCompact && !selected;
|
|
5210
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
5211
|
+
"div",
|
|
5212
|
+
{
|
|
5213
|
+
className: [ROOT_CLASS, className].filter(Boolean).join(" "),
|
|
5214
|
+
style: { ...styles17.container, ...style },
|
|
5215
|
+
children: [
|
|
5216
|
+
showList && /* @__PURE__ */ jsxRuntime.jsx("div", { style: isCompact ? styles17.sidebarCompact : styles17.sidebar, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5217
|
+
ConversationList,
|
|
5218
|
+
{
|
|
5219
|
+
conversations,
|
|
5220
|
+
selectedId,
|
|
5221
|
+
isLoading,
|
|
5222
|
+
error,
|
|
5223
|
+
onSelect: handleSelect,
|
|
5224
|
+
title
|
|
5225
|
+
}
|
|
5226
|
+
) }),
|
|
5227
|
+
showDetail && /* @__PURE__ */ jsxRuntime.jsx("div", { style: isCompact ? styles17.mainCompact : styles17.main, children: selected ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
5228
|
+
CollabPanel,
|
|
5229
|
+
{
|
|
5230
|
+
orderId: selected.orderId,
|
|
5231
|
+
patientData: buildPatientData(selected),
|
|
5232
|
+
showSeenBy: true,
|
|
5233
|
+
style: styles17.panel,
|
|
5234
|
+
onBack: isCompact ? () => setSelectedId(null) : void 0
|
|
5235
|
+
},
|
|
5236
|
+
selected.id
|
|
5237
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { hasAny: conversations.length > 0 }) })
|
|
5238
|
+
]
|
|
5239
|
+
}
|
|
5240
|
+
);
|
|
4988
5241
|
}
|
|
4989
5242
|
function buildPatientData(item) {
|
|
4990
5243
|
if (item.patientSnapshot) return item.patientSnapshot;
|
|
@@ -5006,7 +5259,7 @@ var styles17 = {
|
|
|
5006
5259
|
height: "100%",
|
|
5007
5260
|
width: "100%",
|
|
5008
5261
|
backgroundColor: "#ffffff",
|
|
5009
|
-
fontFamily:
|
|
5262
|
+
fontFamily: FONT_STACK
|
|
5010
5263
|
},
|
|
5011
5264
|
sidebar: {
|
|
5012
5265
|
width: "320px",
|
|
@@ -5015,6 +5268,12 @@ var styles17 = {
|
|
|
5015
5268
|
display: "flex",
|
|
5016
5269
|
flexDirection: "column"
|
|
5017
5270
|
},
|
|
5271
|
+
sidebarCompact: {
|
|
5272
|
+
width: "100%",
|
|
5273
|
+
flex: 1,
|
|
5274
|
+
display: "flex",
|
|
5275
|
+
flexDirection: "column"
|
|
5276
|
+
},
|
|
5018
5277
|
main: {
|
|
5019
5278
|
flex: 1,
|
|
5020
5279
|
display: "flex",
|
|
@@ -5023,6 +5282,13 @@ var styles17 = {
|
|
|
5023
5282
|
padding: "12px",
|
|
5024
5283
|
backgroundColor: "#f3f4f6"
|
|
5025
5284
|
},
|
|
5285
|
+
mainCompact: {
|
|
5286
|
+
flex: 1,
|
|
5287
|
+
display: "flex",
|
|
5288
|
+
flexDirection: "column",
|
|
5289
|
+
minWidth: 0,
|
|
5290
|
+
backgroundColor: "#f3f4f6"
|
|
5291
|
+
},
|
|
5026
5292
|
panel: {
|
|
5027
5293
|
height: "100%",
|
|
5028
5294
|
width: "100%"
|