@natoe/colab 0.1.3 → 0.1.5
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 +24 -6
- package/dist/index.d.ts +24 -6
- package/dist/index.js +687 -245
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +688 -246
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -834,6 +834,7 @@ function useConversation({
|
|
|
834
834
|
body,
|
|
835
835
|
type: "text",
|
|
836
836
|
insertedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
837
|
+
status: "sending",
|
|
837
838
|
...replyTo ? {
|
|
838
839
|
replyToId: replyTo.id,
|
|
839
840
|
replyToSnapshot: {
|
|
@@ -849,7 +850,9 @@ function useConversation({
|
|
|
849
850
|
try {
|
|
850
851
|
await socket.sendMessage(conv.id, payload);
|
|
851
852
|
} catch (err) {
|
|
852
|
-
setMessages(
|
|
853
|
+
setMessages(
|
|
854
|
+
(prev) => prev.map((m) => m.id === optimistic.id ? { ...m, status: "failed" } : m)
|
|
855
|
+
);
|
|
853
856
|
config.onError?.({
|
|
854
857
|
code: "SEND_FAILED",
|
|
855
858
|
message: "Failed to send message",
|
|
@@ -859,6 +862,34 @@ function useConversation({
|
|
|
859
862
|
},
|
|
860
863
|
[ensureConversation, socket, replyTo, config]
|
|
861
864
|
);
|
|
865
|
+
const retryMessage = React4.useCallback(
|
|
866
|
+
async (messageId) => {
|
|
867
|
+
if (!conversation) return;
|
|
868
|
+
const target = messages.find((m) => m.id === messageId);
|
|
869
|
+
if (!target || target.status !== "failed" || target.type !== "text") return;
|
|
870
|
+
setMessages(
|
|
871
|
+
(prev) => prev.map((m) => m.id === messageId ? { ...m, status: "sending" } : m)
|
|
872
|
+
);
|
|
873
|
+
const payload = {
|
|
874
|
+
body: target.body,
|
|
875
|
+
type: "text",
|
|
876
|
+
...target.replyToId ? { replyToId: target.replyToId } : {}
|
|
877
|
+
};
|
|
878
|
+
try {
|
|
879
|
+
await socket.sendMessage(conversation.id, payload);
|
|
880
|
+
} catch (err) {
|
|
881
|
+
setMessages(
|
|
882
|
+
(prev) => prev.map((m) => m.id === messageId ? { ...m, status: "failed" } : m)
|
|
883
|
+
);
|
|
884
|
+
config.onError?.({
|
|
885
|
+
code: "SEND_FAILED",
|
|
886
|
+
message: "Failed to send message",
|
|
887
|
+
details: err
|
|
888
|
+
});
|
|
889
|
+
}
|
|
890
|
+
},
|
|
891
|
+
[conversation, messages, socket, config]
|
|
892
|
+
);
|
|
862
893
|
const sendAudioMessage = React4.useCallback(
|
|
863
894
|
async (audioBlob, duration) => {
|
|
864
895
|
if (!config.onUploadFile) return;
|
|
@@ -951,6 +982,7 @@ function useConversation({
|
|
|
951
982
|
message: "Failed to pin message",
|
|
952
983
|
details: err
|
|
953
984
|
});
|
|
985
|
+
throw err;
|
|
954
986
|
}
|
|
955
987
|
},
|
|
956
988
|
[conversation, pinMessageApi, config]
|
|
@@ -966,6 +998,7 @@ function useConversation({
|
|
|
966
998
|
message: "Failed to unpin message",
|
|
967
999
|
details: err
|
|
968
1000
|
});
|
|
1001
|
+
throw err;
|
|
969
1002
|
}
|
|
970
1003
|
},
|
|
971
1004
|
[conversation, unpinMessageApi, config]
|
|
@@ -983,6 +1016,7 @@ function useConversation({
|
|
|
983
1016
|
replyTo,
|
|
984
1017
|
setReplyTo,
|
|
985
1018
|
sendMessage,
|
|
1019
|
+
retryMessage,
|
|
986
1020
|
sendAudioMessage,
|
|
987
1021
|
sendFileMessage,
|
|
988
1022
|
sendDeepLink,
|
|
@@ -1345,91 +1379,247 @@ var styles3 = {
|
|
|
1345
1379
|
textDecoration: "underline"
|
|
1346
1380
|
}
|
|
1347
1381
|
};
|
|
1382
|
+
function ReplyIcon({ size = 18, color = "currentColor" }) {
|
|
1383
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1384
|
+
"svg",
|
|
1385
|
+
{
|
|
1386
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1387
|
+
width: size,
|
|
1388
|
+
height: size,
|
|
1389
|
+
viewBox: "0 0 24 24",
|
|
1390
|
+
fill: color,
|
|
1391
|
+
"aria-hidden": "true",
|
|
1392
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 9V5l-7 7 7 7v-4.1c5 0 8.5 1.6 11 5.1-1-5-4-10-11-11z" })
|
|
1393
|
+
}
|
|
1394
|
+
);
|
|
1395
|
+
}
|
|
1396
|
+
function PinIcon({ size = 14, color = "currentColor" }) {
|
|
1397
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1398
|
+
"svg",
|
|
1399
|
+
{
|
|
1400
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1401
|
+
width: size,
|
|
1402
|
+
height: size,
|
|
1403
|
+
viewBox: "0 0 24 24",
|
|
1404
|
+
fill: color,
|
|
1405
|
+
"aria-hidden": "true",
|
|
1406
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 9V4l1 0c.55 0 1-.45 1-1s-.45-1-1-1H7c-.55 0-1 .45-1 1s.45 1 1 1l1 0v5c0 1.66-1.34 3-3 3v2h5.97v7l1 1 1-1v-7H19v-2c-1.66 0-3-1.34-3-3z" })
|
|
1407
|
+
}
|
|
1408
|
+
);
|
|
1409
|
+
}
|
|
1410
|
+
function CopyIcon({ size = 18, color = "currentColor" }) {
|
|
1411
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1412
|
+
"svg",
|
|
1413
|
+
{
|
|
1414
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1415
|
+
width: size,
|
|
1416
|
+
height: size,
|
|
1417
|
+
viewBox: "0 0 24 24",
|
|
1418
|
+
fill: color,
|
|
1419
|
+
"aria-hidden": "true",
|
|
1420
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z" })
|
|
1421
|
+
}
|
|
1422
|
+
);
|
|
1423
|
+
}
|
|
1424
|
+
function MoreIcon({ size = 18, color = "currentColor" }) {
|
|
1425
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1426
|
+
"svg",
|
|
1427
|
+
{
|
|
1428
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1429
|
+
width: size,
|
|
1430
|
+
height: size,
|
|
1431
|
+
viewBox: "0 0 24 24",
|
|
1432
|
+
fill: color,
|
|
1433
|
+
"aria-hidden": "true",
|
|
1434
|
+
children: [
|
|
1435
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "5", r: "2" }),
|
|
1436
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "2" }),
|
|
1437
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "19", r: "2" })
|
|
1438
|
+
]
|
|
1439
|
+
}
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1348
1442
|
function MessageActionsMenu({
|
|
1349
1443
|
message,
|
|
1350
1444
|
onReply,
|
|
1351
1445
|
onPin,
|
|
1352
1446
|
onUnpin,
|
|
1353
1447
|
onCopy,
|
|
1354
|
-
visible,
|
|
1355
1448
|
pinDisabled = false,
|
|
1449
|
+
anchorRight = false,
|
|
1356
1450
|
className
|
|
1357
1451
|
}) {
|
|
1358
|
-
|
|
1452
|
+
const [isOpen, setIsOpen] = React4.useState(false);
|
|
1453
|
+
const wrapperRef = React4.useRef(null);
|
|
1454
|
+
const triggerRef = React4.useRef(null);
|
|
1359
1455
|
const isPinned = !!message.isPinned;
|
|
1360
1456
|
const canCopy = message.type === "text" && !!message.body;
|
|
1361
|
-
|
|
1362
|
-
if (!
|
|
1363
|
-
|
|
1457
|
+
React4.useEffect(() => {
|
|
1458
|
+
if (!isOpen) return;
|
|
1459
|
+
const handleClick = (e) => {
|
|
1460
|
+
if (!wrapperRef.current?.contains(e.target)) {
|
|
1461
|
+
setIsOpen(false);
|
|
1462
|
+
}
|
|
1463
|
+
};
|
|
1464
|
+
const handleKey = (e) => {
|
|
1465
|
+
if (e.key === "Escape") {
|
|
1466
|
+
setIsOpen(false);
|
|
1467
|
+
triggerRef.current?.focus();
|
|
1468
|
+
}
|
|
1469
|
+
};
|
|
1470
|
+
document.addEventListener("mousedown", handleClick);
|
|
1471
|
+
document.addEventListener("keydown", handleKey);
|
|
1472
|
+
return () => {
|
|
1473
|
+
document.removeEventListener("mousedown", handleClick);
|
|
1474
|
+
document.removeEventListener("keydown", handleKey);
|
|
1475
|
+
};
|
|
1476
|
+
}, [isOpen]);
|
|
1477
|
+
const run = (fn) => {
|
|
1478
|
+
setIsOpen(false);
|
|
1479
|
+
fn();
|
|
1364
1480
|
};
|
|
1365
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles4.
|
|
1481
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: wrapperRef, className, style: styles4.wrapper, children: [
|
|
1366
1482
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1367
1483
|
"button",
|
|
1368
1484
|
{
|
|
1369
|
-
|
|
1370
|
-
style: styles4.button,
|
|
1371
|
-
title: "Reply",
|
|
1485
|
+
ref: triggerRef,
|
|
1372
1486
|
type: "button",
|
|
1373
|
-
|
|
1487
|
+
onClick: (e) => {
|
|
1488
|
+
e.stopPropagation();
|
|
1489
|
+
setIsOpen((v) => !v);
|
|
1490
|
+
},
|
|
1491
|
+
"aria-label": "Message actions",
|
|
1492
|
+
"aria-haspopup": "menu",
|
|
1493
|
+
"aria-expanded": isOpen ? "true" : "false",
|
|
1494
|
+
title: "Message actions",
|
|
1495
|
+
style: styles4.trigger,
|
|
1496
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(MoreIcon, { size: 18, color: "#4b5563" })
|
|
1374
1497
|
}
|
|
1375
1498
|
),
|
|
1376
|
-
|
|
1377
|
-
"
|
|
1378
|
-
{
|
|
1379
|
-
onClick: () => onUnpin(message.id),
|
|
1380
|
-
style: styles4.button,
|
|
1381
|
-
title: "Unpin",
|
|
1382
|
-
type: "button",
|
|
1383
|
-
children: "\u{1F4CC}"
|
|
1384
|
-
}
|
|
1385
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1386
|
-
"button",
|
|
1499
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1500
|
+
"div",
|
|
1387
1501
|
{
|
|
1388
|
-
|
|
1502
|
+
role: "menu",
|
|
1503
|
+
"aria-label": "Message actions",
|
|
1389
1504
|
style: {
|
|
1390
|
-
...styles4.
|
|
1391
|
-
|
|
1392
|
-
cursor: pinDisabled ? "not-allowed" : "pointer"
|
|
1505
|
+
...styles4.menu,
|
|
1506
|
+
...anchorRight ? styles4.menuRight : styles4.menuLeft
|
|
1393
1507
|
},
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
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
|
+
]
|
|
1408
1566
|
}
|
|
1409
1567
|
)
|
|
1410
1568
|
] });
|
|
1411
1569
|
}
|
|
1412
1570
|
var styles4 = {
|
|
1413
|
-
|
|
1571
|
+
wrapper: {
|
|
1572
|
+
position: "relative",
|
|
1573
|
+
display: "inline-block"
|
|
1574
|
+
},
|
|
1575
|
+
trigger: {
|
|
1576
|
+
width: "36px",
|
|
1577
|
+
height: "36px",
|
|
1414
1578
|
display: "flex",
|
|
1415
|
-
|
|
1416
|
-
|
|
1579
|
+
alignItems: "center",
|
|
1580
|
+
justifyContent: "center",
|
|
1581
|
+
backgroundColor: "transparent",
|
|
1582
|
+
border: "none",
|
|
1583
|
+
borderRadius: "50%",
|
|
1584
|
+
cursor: "pointer",
|
|
1585
|
+
color: "#4b5563"
|
|
1586
|
+
},
|
|
1587
|
+
menu: {
|
|
1588
|
+
position: "absolute",
|
|
1589
|
+
top: "100%",
|
|
1590
|
+
marginTop: "4px",
|
|
1591
|
+
minWidth: "160px",
|
|
1417
1592
|
backgroundColor: "#ffffff",
|
|
1418
1593
|
border: "1px solid #e5e7eb",
|
|
1419
|
-
borderRadius: "
|
|
1420
|
-
boxShadow: "0
|
|
1594
|
+
borderRadius: "10px",
|
|
1595
|
+
boxShadow: "0 6px 18px rgba(0, 0, 0, 0.12)",
|
|
1596
|
+
padding: "4px",
|
|
1597
|
+
zIndex: 20
|
|
1421
1598
|
},
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1599
|
+
menuLeft: {
|
|
1600
|
+
left: 0
|
|
1601
|
+
},
|
|
1602
|
+
menuRight: {
|
|
1603
|
+
right: 0
|
|
1604
|
+
},
|
|
1605
|
+
item: {
|
|
1425
1606
|
display: "flex",
|
|
1426
1607
|
alignItems: "center",
|
|
1427
|
-
|
|
1428
|
-
|
|
1608
|
+
gap: "10px",
|
|
1609
|
+
width: "100%",
|
|
1610
|
+
minHeight: "40px",
|
|
1611
|
+
padding: "8px 12px",
|
|
1612
|
+
fontSize: "14px",
|
|
1613
|
+
color: "#111827",
|
|
1429
1614
|
backgroundColor: "transparent",
|
|
1430
1615
|
border: "none",
|
|
1431
|
-
borderRadius: "
|
|
1432
|
-
cursor: "pointer"
|
|
1616
|
+
borderRadius: "6px",
|
|
1617
|
+
cursor: "pointer",
|
|
1618
|
+
textAlign: "left"
|
|
1619
|
+
},
|
|
1620
|
+
itemDisabled: {
|
|
1621
|
+
color: "#9ca3af",
|
|
1622
|
+
cursor: "not-allowed"
|
|
1433
1623
|
}
|
|
1434
1624
|
};
|
|
1435
1625
|
function FileIcon({ size = 18, color = "currentColor" }) {
|
|
@@ -1446,7 +1636,7 @@ function FileIcon({ size = 18, color = "currentColor" }) {
|
|
|
1446
1636
|
}
|
|
1447
1637
|
);
|
|
1448
1638
|
}
|
|
1449
|
-
function
|
|
1639
|
+
function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
1450
1640
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1451
1641
|
"svg",
|
|
1452
1642
|
{
|
|
@@ -1456,10 +1646,38 @@ function PinIcon({ size = 14, color = "currentColor" }) {
|
|
|
1456
1646
|
viewBox: "0 0 24 24",
|
|
1457
1647
|
fill: color,
|
|
1458
1648
|
"aria-hidden": "true",
|
|
1459
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "
|
|
1649
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
|
|
1460
1650
|
}
|
|
1461
1651
|
);
|
|
1462
1652
|
}
|
|
1653
|
+
function Spinner({ size = 16, color = "#6b7280", thickness = 2 }) {
|
|
1654
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1655
|
+
"span",
|
|
1656
|
+
{
|
|
1657
|
+
role: "status",
|
|
1658
|
+
"aria-label": "Loading",
|
|
1659
|
+
style: {
|
|
1660
|
+
display: "inline-block",
|
|
1661
|
+
width: size,
|
|
1662
|
+
height: size,
|
|
1663
|
+
border: `${thickness}px solid ${color}33`,
|
|
1664
|
+
borderTopColor: color,
|
|
1665
|
+
borderRadius: "50%",
|
|
1666
|
+
animation: "natoe-colab-spin 800ms linear infinite",
|
|
1667
|
+
verticalAlign: "middle"
|
|
1668
|
+
}
|
|
1669
|
+
}
|
|
1670
|
+
);
|
|
1671
|
+
}
|
|
1672
|
+
if (typeof document !== "undefined") {
|
|
1673
|
+
const existing = document.getElementById("natoe-colab-spin-keyframes");
|
|
1674
|
+
if (!existing) {
|
|
1675
|
+
const style = document.createElement("style");
|
|
1676
|
+
style.id = "natoe-colab-spin-keyframes";
|
|
1677
|
+
style.textContent = `@keyframes natoe-colab-spin { to { transform: rotate(360deg); } }`;
|
|
1678
|
+
document.head.appendChild(style);
|
|
1679
|
+
}
|
|
1680
|
+
}
|
|
1463
1681
|
var ROLE_LABELS = {
|
|
1464
1682
|
radiologist: "Radiologist",
|
|
1465
1683
|
lab: "Imaging Center",
|
|
@@ -1478,15 +1696,30 @@ function MessageBubble({
|
|
|
1478
1696
|
onUnpin,
|
|
1479
1697
|
onCopy,
|
|
1480
1698
|
onReplyJumpTo,
|
|
1699
|
+
onRetry,
|
|
1481
1700
|
pinDisabled = false,
|
|
1482
1701
|
className
|
|
1483
1702
|
}) {
|
|
1484
|
-
const [isHovered, setIsHovered] = React4.useState(false);
|
|
1485
1703
|
if (message.type === "system") {
|
|
1486
1704
|
return /* @__PURE__ */ jsxRuntime.jsx(SystemBubble, { message });
|
|
1487
1705
|
}
|
|
1488
1706
|
const hasActions = !!(onReply || onPin || onUnpin || onCopy);
|
|
1489
|
-
|
|
1707
|
+
const actionsSlot = hasActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.actionsSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1708
|
+
MessageActionsMenu,
|
|
1709
|
+
{
|
|
1710
|
+
message,
|
|
1711
|
+
onReply: onReply ?? (() => {
|
|
1712
|
+
}),
|
|
1713
|
+
onPin: onPin ?? (() => {
|
|
1714
|
+
}),
|
|
1715
|
+
onUnpin: onUnpin ?? (() => {
|
|
1716
|
+
}),
|
|
1717
|
+
onCopy,
|
|
1718
|
+
pinDisabled,
|
|
1719
|
+
anchorRight: !isOwn
|
|
1720
|
+
}
|
|
1721
|
+
) }) : null;
|
|
1722
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1490
1723
|
"div",
|
|
1491
1724
|
{
|
|
1492
1725
|
className,
|
|
@@ -1494,10 +1727,9 @@ function MessageBubble({
|
|
|
1494
1727
|
...styles5.wrapper,
|
|
1495
1728
|
justifyContent: isOwn ? "flex-end" : "flex-start"
|
|
1496
1729
|
},
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1730
|
+
children: [
|
|
1731
|
+
isOwn && actionsSlot,
|
|
1732
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.bubbleWrapper, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1501
1733
|
"div",
|
|
1502
1734
|
{
|
|
1503
1735
|
style: {
|
|
@@ -1527,7 +1759,25 @@ function MessageBubble({
|
|
|
1527
1759
|
message.type === "file" && /* @__PURE__ */ jsxRuntime.jsx(FileContent, { mediaUrl: message.mediaUrl, fileName: message.fileName }),
|
|
1528
1760
|
message.type === "deep_link" && /* @__PURE__ */ jsxRuntime.jsx(DeepLinkContent, { body: message.body, metadata: message.metadata, onDeepLinkClick }),
|
|
1529
1761
|
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.timestamp, children: formatTime(message.insertedAt) }),
|
|
1530
|
-
|
|
1762
|
+
isOwn && message.status === "sending" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.statusRow, children: [
|
|
1763
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 12, color: "rgba(255,255,255,0.85)" }),
|
|
1764
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.statusText, children: "Sending\u2026" })
|
|
1765
|
+
] }),
|
|
1766
|
+
isOwn && message.status === "failed" && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles5.statusRow, children: [
|
|
1767
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 12, color: "#fecaca" }),
|
|
1768
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles5.statusText, children: "Not sent" }),
|
|
1769
|
+
onRetry && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1770
|
+
"button",
|
|
1771
|
+
{
|
|
1772
|
+
type: "button",
|
|
1773
|
+
onClick: () => onRetry(message.id),
|
|
1774
|
+
style: styles5.retryButton,
|
|
1775
|
+
"aria-label": "Retry sending message",
|
|
1776
|
+
children: "Retry"
|
|
1777
|
+
}
|
|
1778
|
+
)
|
|
1779
|
+
] }),
|
|
1780
|
+
showSeenBy && isOwn && !message.status && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1531
1781
|
SeenByIndicator,
|
|
1532
1782
|
{
|
|
1533
1783
|
readBy: message.readBy ?? [],
|
|
@@ -1538,33 +1788,9 @@ function MessageBubble({
|
|
|
1538
1788
|
)
|
|
1539
1789
|
]
|
|
1540
1790
|
}
|
|
1541
|
-
),
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
{
|
|
1545
|
-
style: {
|
|
1546
|
-
...styles5.actionsWrapper,
|
|
1547
|
-
[isOwn ? "right" : "left"]: "100%",
|
|
1548
|
-
[isOwn ? "marginRight" : "marginLeft"]: "6px"
|
|
1549
|
-
},
|
|
1550
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1551
|
-
MessageActionsMenu,
|
|
1552
|
-
{
|
|
1553
|
-
message,
|
|
1554
|
-
onReply: onReply ?? (() => {
|
|
1555
|
-
}),
|
|
1556
|
-
onPin: onPin ?? (() => {
|
|
1557
|
-
}),
|
|
1558
|
-
onUnpin: onUnpin ?? (() => {
|
|
1559
|
-
}),
|
|
1560
|
-
onCopy,
|
|
1561
|
-
visible: isHovered,
|
|
1562
|
-
pinDisabled
|
|
1563
|
-
}
|
|
1564
|
-
)
|
|
1565
|
-
}
|
|
1566
|
-
)
|
|
1567
|
-
] })
|
|
1791
|
+
) }),
|
|
1792
|
+
!isOwn && actionsSlot
|
|
1793
|
+
]
|
|
1568
1794
|
}
|
|
1569
1795
|
);
|
|
1570
1796
|
}
|
|
@@ -1661,6 +1887,8 @@ function escapeRegex2(string) {
|
|
|
1661
1887
|
var styles5 = {
|
|
1662
1888
|
wrapper: {
|
|
1663
1889
|
display: "flex",
|
|
1890
|
+
alignItems: "flex-end",
|
|
1891
|
+
gap: "4px",
|
|
1664
1892
|
marginBottom: "8px",
|
|
1665
1893
|
paddingLeft: "16px",
|
|
1666
1894
|
paddingRight: "16px"
|
|
@@ -1669,6 +1897,10 @@ var styles5 = {
|
|
|
1669
1897
|
position: "relative",
|
|
1670
1898
|
maxWidth: "75%"
|
|
1671
1899
|
},
|
|
1900
|
+
actionsSlot: {
|
|
1901
|
+
flexShrink: 0,
|
|
1902
|
+
alignSelf: "flex-end"
|
|
1903
|
+
},
|
|
1672
1904
|
bubble: {
|
|
1673
1905
|
padding: "10px 14px",
|
|
1674
1906
|
borderRadius: "12px",
|
|
@@ -1722,11 +1954,27 @@ var styles5 = {
|
|
|
1722
1954
|
marginTop: "4px",
|
|
1723
1955
|
textAlign: "right"
|
|
1724
1956
|
},
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1957
|
+
statusRow: {
|
|
1958
|
+
display: "flex",
|
|
1959
|
+
alignItems: "center",
|
|
1960
|
+
gap: "6px",
|
|
1961
|
+
marginTop: "4px",
|
|
1962
|
+
fontSize: "12px",
|
|
1963
|
+
justifyContent: "flex-end",
|
|
1964
|
+
color: "rgba(255, 255, 255, 0.9)"
|
|
1965
|
+
},
|
|
1966
|
+
statusText: {
|
|
1967
|
+
opacity: 0.9
|
|
1968
|
+
},
|
|
1969
|
+
retryButton: {
|
|
1970
|
+
background: "transparent",
|
|
1971
|
+
border: "none",
|
|
1972
|
+
color: "#ffffff",
|
|
1973
|
+
fontWeight: 600,
|
|
1974
|
+
fontSize: "12px",
|
|
1975
|
+
textDecoration: "underline",
|
|
1976
|
+
cursor: "pointer",
|
|
1977
|
+
padding: "0 2px"
|
|
1730
1978
|
},
|
|
1731
1979
|
audioContainer: {
|
|
1732
1980
|
display: "flex",
|
|
@@ -1800,6 +2048,44 @@ var styles5 = {
|
|
|
1800
2048
|
color: "#9ca3af"
|
|
1801
2049
|
}
|
|
1802
2050
|
};
|
|
2051
|
+
function ChatIllustration({ size = 96 }) {
|
|
2052
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2053
|
+
"svg",
|
|
2054
|
+
{
|
|
2055
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2056
|
+
width: size,
|
|
2057
|
+
height: size,
|
|
2058
|
+
viewBox: "0 0 120 120",
|
|
2059
|
+
fill: "none",
|
|
2060
|
+
"aria-hidden": "true",
|
|
2061
|
+
children: [
|
|
2062
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "60", cy: "60", r: "56", fill: "#eff6ff" }),
|
|
2063
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2064
|
+
"path",
|
|
2065
|
+
{
|
|
2066
|
+
d: "M28 44a10 10 0 0 1 10-10h28a10 10 0 0 1 10 10v18a10 10 0 0 1-10 10H46l-10 8v-8h2a10 10 0 0 1-10-10V44Z",
|
|
2067
|
+
fill: "#ffffff",
|
|
2068
|
+
stroke: "#2563eb",
|
|
2069
|
+
strokeWidth: "2.5"
|
|
2070
|
+
}
|
|
2071
|
+
),
|
|
2072
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2073
|
+
"path",
|
|
2074
|
+
{
|
|
2075
|
+
d: "M52 60a8 8 0 0 1 8-8h26a8 8 0 0 1 8 8v14a8 8 0 0 1-8 8H72l8 8v-8h6a8 8 0 0 0 0-30Z",
|
|
2076
|
+
fill: "#dbeafe",
|
|
2077
|
+
stroke: "#2563eb",
|
|
2078
|
+
strokeWidth: "2.5"
|
|
2079
|
+
}
|
|
2080
|
+
),
|
|
2081
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "48", cy: "53", r: "2.5", fill: "#2563eb" }),
|
|
2082
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "58", cy: "53", r: "2.5", fill: "#2563eb" }),
|
|
2083
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "68", cy: "68", r: "2.5", fill: "#2563eb" }),
|
|
2084
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "78", cy: "68", r: "2.5", fill: "#2563eb" })
|
|
2085
|
+
]
|
|
2086
|
+
}
|
|
2087
|
+
);
|
|
2088
|
+
}
|
|
1803
2089
|
|
|
1804
2090
|
// src/core/dateLabels.ts
|
|
1805
2091
|
var SHORT_MONTHS = [
|
|
@@ -1891,6 +2177,7 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
1891
2177
|
onPin,
|
|
1892
2178
|
onUnpin,
|
|
1893
2179
|
onCopy,
|
|
2180
|
+
onRetry,
|
|
1894
2181
|
pinDisabled,
|
|
1895
2182
|
className
|
|
1896
2183
|
}, ref) {
|
|
@@ -1955,12 +2242,17 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
1955
2242
|
style: styles6.container,
|
|
1956
2243
|
onScroll: handleScroll,
|
|
1957
2244
|
children: [
|
|
1958
|
-
isLoading && /* @__PURE__ */ jsxRuntime.
|
|
2245
|
+
isLoading && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.loadingMore, children: [
|
|
2246
|
+
/* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 14 }),
|
|
2247
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Loading earlier messages\u2026" })
|
|
2248
|
+
] }),
|
|
1959
2249
|
hasMore && !isLoading && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onLoadMore, style: styles6.loadMoreButton, type: "button", children: "Load earlier messages" }),
|
|
1960
2250
|
messages.length === 0 && !isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles6.empty, children: [
|
|
2251
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChatIllustration, { size: 104 }),
|
|
1961
2252
|
/* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.emptyTitle, children: "No messages yet" }),
|
|
1962
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.emptySubtitle, children: "Start the conversation
|
|
2253
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: styles6.emptySubtitle, children: "Start the conversation \u2014 everyone on this case will see what you write." })
|
|
1963
2254
|
] }),
|
|
2255
|
+
messages.length === 0 && isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.firstLoad, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 20 }) }),
|
|
1964
2256
|
messages.map((message, index) => {
|
|
1965
2257
|
const currentBucket = dayBucketKey(message.insertedAt);
|
|
1966
2258
|
const prevBucket = index === 0 ? null : dayBucketKey(messages[index - 1].insertedAt);
|
|
@@ -1980,6 +2272,7 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
1980
2272
|
onPin,
|
|
1981
2273
|
onUnpin,
|
|
1982
2274
|
onCopy,
|
|
2275
|
+
onRetry,
|
|
1983
2276
|
pinDisabled
|
|
1984
2277
|
}
|
|
1985
2278
|
) })
|
|
@@ -2008,11 +2301,20 @@ var styles6 = {
|
|
|
2008
2301
|
paddingBottom: "8px"
|
|
2009
2302
|
},
|
|
2010
2303
|
loadingMore: {
|
|
2011
|
-
|
|
2304
|
+
display: "flex",
|
|
2305
|
+
alignItems: "center",
|
|
2306
|
+
justifyContent: "center",
|
|
2307
|
+
gap: "8px",
|
|
2012
2308
|
padding: "12px",
|
|
2013
2309
|
fontSize: "14px",
|
|
2014
2310
|
color: "#6b7280"
|
|
2015
2311
|
},
|
|
2312
|
+
firstLoad: {
|
|
2313
|
+
display: "flex",
|
|
2314
|
+
alignItems: "center",
|
|
2315
|
+
justifyContent: "center",
|
|
2316
|
+
padding: "48px 16px"
|
|
2317
|
+
},
|
|
2016
2318
|
loadMoreButton: {
|
|
2017
2319
|
display: "block",
|
|
2018
2320
|
margin: "0 auto 12px",
|
|
@@ -2037,11 +2339,14 @@ var styles6 = {
|
|
|
2037
2339
|
fontSize: "16px",
|
|
2038
2340
|
fontWeight: 600,
|
|
2039
2341
|
color: "#374151",
|
|
2040
|
-
margin: "
|
|
2342
|
+
margin: "14px 0 4px"
|
|
2041
2343
|
},
|
|
2042
2344
|
emptySubtitle: {
|
|
2043
2345
|
fontSize: "14px",
|
|
2044
|
-
margin: 0
|
|
2346
|
+
margin: 0,
|
|
2347
|
+
maxWidth: "280px",
|
|
2348
|
+
lineHeight: 1.45,
|
|
2349
|
+
textAlign: "center"
|
|
2045
2350
|
},
|
|
2046
2351
|
typingIndicator: {
|
|
2047
2352
|
padding: "4px 16px 8px",
|
|
@@ -2320,7 +2625,18 @@ function MessageInput({
|
|
|
2320
2625
|
type: "file",
|
|
2321
2626
|
onChange: handleFileSelect,
|
|
2322
2627
|
style: { display: "none" },
|
|
2323
|
-
accept: [
|
|
2628
|
+
accept: [
|
|
2629
|
+
...SUPPORTED_IMAGE_TYPES,
|
|
2630
|
+
"application/pdf",
|
|
2631
|
+
".doc",
|
|
2632
|
+
".docx",
|
|
2633
|
+
".xls",
|
|
2634
|
+
".xlsx",
|
|
2635
|
+
".csv",
|
|
2636
|
+
".txt",
|
|
2637
|
+
".heic",
|
|
2638
|
+
".heif"
|
|
2639
|
+
].join(",")
|
|
2324
2640
|
}
|
|
2325
2641
|
),
|
|
2326
2642
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3045,6 +3361,64 @@ var styles11 = {
|
|
|
3045
3361
|
flexShrink: 0
|
|
3046
3362
|
}
|
|
3047
3363
|
};
|
|
3364
|
+
function Toast({ toast, onDismiss, durationMs = 4e3 }) {
|
|
3365
|
+
React4.useEffect(() => {
|
|
3366
|
+
if (!toast) return;
|
|
3367
|
+
const timer = setTimeout(onDismiss, durationMs);
|
|
3368
|
+
return () => clearTimeout(timer);
|
|
3369
|
+
}, [toast, onDismiss, durationMs]);
|
|
3370
|
+
if (!toast) return null;
|
|
3371
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles12.container, role: "status", "aria-live": "polite", children: [
|
|
3372
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles12.message, children: toast.message }),
|
|
3373
|
+
toast.actionLabel && toast.onAction && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3374
|
+
"button",
|
|
3375
|
+
{
|
|
3376
|
+
type: "button",
|
|
3377
|
+
onClick: () => {
|
|
3378
|
+
toast.onAction?.();
|
|
3379
|
+
onDismiss();
|
|
3380
|
+
},
|
|
3381
|
+
style: styles12.action,
|
|
3382
|
+
children: toast.actionLabel
|
|
3383
|
+
}
|
|
3384
|
+
)
|
|
3385
|
+
] });
|
|
3386
|
+
}
|
|
3387
|
+
var styles12 = {
|
|
3388
|
+
container: {
|
|
3389
|
+
position: "absolute",
|
|
3390
|
+
bottom: "76px",
|
|
3391
|
+
left: "50%",
|
|
3392
|
+
transform: "translateX(-50%)",
|
|
3393
|
+
display: "flex",
|
|
3394
|
+
alignItems: "center",
|
|
3395
|
+
gap: "12px",
|
|
3396
|
+
padding: "10px 14px",
|
|
3397
|
+
backgroundColor: "#1e293b",
|
|
3398
|
+
color: "#ffffff",
|
|
3399
|
+
borderRadius: "8px",
|
|
3400
|
+
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.18)",
|
|
3401
|
+
fontSize: "14px",
|
|
3402
|
+
maxWidth: "90%",
|
|
3403
|
+
zIndex: 20
|
|
3404
|
+
},
|
|
3405
|
+
message: {
|
|
3406
|
+
whiteSpace: "nowrap",
|
|
3407
|
+
overflow: "hidden",
|
|
3408
|
+
textOverflow: "ellipsis"
|
|
3409
|
+
},
|
|
3410
|
+
action: {
|
|
3411
|
+
background: "transparent",
|
|
3412
|
+
border: "none",
|
|
3413
|
+
color: "#93c5fd",
|
|
3414
|
+
fontWeight: 600,
|
|
3415
|
+
fontSize: "14px",
|
|
3416
|
+
cursor: "pointer",
|
|
3417
|
+
padding: "4px 6px",
|
|
3418
|
+
textTransform: "uppercase",
|
|
3419
|
+
letterSpacing: "0.4px"
|
|
3420
|
+
}
|
|
3421
|
+
};
|
|
3048
3422
|
function CollabPanel({
|
|
3049
3423
|
orderId,
|
|
3050
3424
|
patientData,
|
|
@@ -3055,6 +3429,7 @@ function CollabPanel({
|
|
|
3055
3429
|
}) {
|
|
3056
3430
|
const { config } = useCollab();
|
|
3057
3431
|
const [showSettings, setShowSettings] = React4.useState(false);
|
|
3432
|
+
const [toast, setToast] = React4.useState(null);
|
|
3058
3433
|
const messageListRef = React4.useRef(null);
|
|
3059
3434
|
const {
|
|
3060
3435
|
conversation,
|
|
@@ -3068,6 +3443,7 @@ function CollabPanel({
|
|
|
3068
3443
|
replyTo,
|
|
3069
3444
|
setReplyTo,
|
|
3070
3445
|
sendMessage,
|
|
3446
|
+
retryMessage,
|
|
3071
3447
|
sendAudioMessage,
|
|
3072
3448
|
sendFileMessage,
|
|
3073
3449
|
sendTyping,
|
|
@@ -3092,10 +3468,33 @@ function CollabPanel({
|
|
|
3092
3468
|
try {
|
|
3093
3469
|
if (navigator.clipboard) {
|
|
3094
3470
|
await navigator.clipboard.writeText(text);
|
|
3471
|
+
setToast({ message: "Copied to clipboard" });
|
|
3095
3472
|
}
|
|
3096
3473
|
} catch {
|
|
3097
3474
|
}
|
|
3098
3475
|
};
|
|
3476
|
+
const handlePin = async (messageId) => {
|
|
3477
|
+
try {
|
|
3478
|
+
await pinMessage(messageId);
|
|
3479
|
+
setToast({
|
|
3480
|
+
message: "Pinned",
|
|
3481
|
+
actionLabel: "Undo",
|
|
3482
|
+
onAction: () => {
|
|
3483
|
+
void unpinMessage(messageId);
|
|
3484
|
+
}
|
|
3485
|
+
});
|
|
3486
|
+
} catch {
|
|
3487
|
+
setToast({ message: "Could not pin message" });
|
|
3488
|
+
}
|
|
3489
|
+
};
|
|
3490
|
+
const handleUnpin = async (messageId) => {
|
|
3491
|
+
try {
|
|
3492
|
+
await unpinMessage(messageId);
|
|
3493
|
+
setToast({ message: "Unpinned" });
|
|
3494
|
+
} catch {
|
|
3495
|
+
setToast({ message: "Could not unpin message" });
|
|
3496
|
+
}
|
|
3497
|
+
};
|
|
3099
3498
|
const pinDisabled = pinnedMessages.length >= MAX_PINNED_MESSAGES;
|
|
3100
3499
|
if (error) {
|
|
3101
3500
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { style: panelStyles.errorState, children: [
|
|
@@ -3106,78 +3505,83 @@ function CollabPanel({
|
|
|
3106
3505
|
if (isLoading && !conversation) {
|
|
3107
3506
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...panelStyles.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: panelStyles.loadingState, children: "Loading conversation..." }) });
|
|
3108
3507
|
}
|
|
3109
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
conversationId: conversation.id,
|
|
3113
|
-
channelName: conversation.name,
|
|
3114
|
-
channelPicture: conversation.picture,
|
|
3115
|
-
participants,
|
|
3116
|
-
currentUserId: config.userId,
|
|
3117
|
-
isAdmin: channelSettings.isAdmin,
|
|
3118
|
-
isUpdating: channelSettings.isUpdating,
|
|
3119
|
-
error: channelSettings.error,
|
|
3120
|
-
onUpdateChannel: channelSettings.updateChannel,
|
|
3121
|
-
onInviteUser: channelSettings.inviteUser,
|
|
3122
|
-
onRemoveUser: channelSettings.removeUser,
|
|
3123
|
-
onLeaveChannel: channelSettings.leaveChannel,
|
|
3124
|
-
onDeleteChannel: channelSettings.deleteChannel,
|
|
3125
|
-
onClose: () => setShowSettings(false)
|
|
3126
|
-
}
|
|
3127
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3128
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3129
|
-
PatientHeader,
|
|
3508
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...panelStyles.container, ...style }, children: [
|
|
3509
|
+
showSettings && conversation ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3510
|
+
ChannelSettings,
|
|
3130
3511
|
{
|
|
3131
|
-
|
|
3512
|
+
conversationId: conversation.id,
|
|
3513
|
+
channelName: conversation.name,
|
|
3514
|
+
channelPicture: conversation.picture,
|
|
3132
3515
|
participants,
|
|
3133
|
-
onOpenDicom: handleOpenDicom,
|
|
3134
|
-
onOpenSettings: () => setShowSettings(true)
|
|
3135
|
-
}
|
|
3136
|
-
),
|
|
3137
|
-
pinnedMessages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3138
|
-
PinnedMessagesBar,
|
|
3139
|
-
{
|
|
3140
|
-
pinnedMessages,
|
|
3141
|
-
onJumpTo: handleJumpToMessage,
|
|
3142
|
-
onUnpin: unpinMessage
|
|
3143
|
-
}
|
|
3144
|
-
),
|
|
3145
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3146
|
-
MessageList,
|
|
3147
|
-
{
|
|
3148
|
-
ref: messageListRef,
|
|
3149
|
-
messages,
|
|
3150
3516
|
currentUserId: config.userId,
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
onPin: pinMessage,
|
|
3161
|
-
onUnpin: unpinMessage,
|
|
3162
|
-
onCopy: handleCopy,
|
|
3163
|
-
pinDisabled
|
|
3517
|
+
isAdmin: channelSettings.isAdmin,
|
|
3518
|
+
isUpdating: channelSettings.isUpdating,
|
|
3519
|
+
error: channelSettings.error,
|
|
3520
|
+
onUpdateChannel: channelSettings.updateChannel,
|
|
3521
|
+
onInviteUser: channelSettings.inviteUser,
|
|
3522
|
+
onRemoveUser: channelSettings.removeUser,
|
|
3523
|
+
onLeaveChannel: channelSettings.leaveChannel,
|
|
3524
|
+
onDeleteChannel: channelSettings.deleteChannel,
|
|
3525
|
+
onClose: () => setShowSettings(false)
|
|
3164
3526
|
}
|
|
3165
|
-
),
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3527
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3528
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3529
|
+
PatientHeader,
|
|
3530
|
+
{
|
|
3531
|
+
patientData,
|
|
3532
|
+
participants,
|
|
3533
|
+
onOpenDicom: handleOpenDicom,
|
|
3534
|
+
onOpenSettings: () => setShowSettings(true)
|
|
3535
|
+
}
|
|
3536
|
+
),
|
|
3537
|
+
pinnedMessages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3538
|
+
PinnedMessagesBar,
|
|
3539
|
+
{
|
|
3540
|
+
pinnedMessages,
|
|
3541
|
+
onJumpTo: handleJumpToMessage,
|
|
3542
|
+
onUnpin: handleUnpin
|
|
3543
|
+
}
|
|
3544
|
+
),
|
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3546
|
+
MessageList,
|
|
3547
|
+
{
|
|
3548
|
+
ref: messageListRef,
|
|
3549
|
+
messages,
|
|
3550
|
+
currentUserId: config.userId,
|
|
3551
|
+
participants,
|
|
3552
|
+
showSeenBy,
|
|
3553
|
+
typingUsers,
|
|
3554
|
+
hasMore,
|
|
3555
|
+
isLoading,
|
|
3556
|
+
onLoadMore: loadMoreMessages,
|
|
3557
|
+
onDeepLinkClick: handleDeepLink,
|
|
3558
|
+
onMessageVisible: markAsRead,
|
|
3559
|
+
onReply: setReplyTo,
|
|
3560
|
+
onPin: handlePin,
|
|
3561
|
+
onUnpin: handleUnpin,
|
|
3562
|
+
onCopy: handleCopy,
|
|
3563
|
+
onRetry: retryMessage,
|
|
3564
|
+
pinDisabled
|
|
3565
|
+
}
|
|
3566
|
+
),
|
|
3567
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3568
|
+
MessageInput,
|
|
3569
|
+
{
|
|
3570
|
+
onSendText: sendMessage,
|
|
3571
|
+
onSendAudio: sendAudioMessage,
|
|
3572
|
+
onSendFile: sendFileMessage,
|
|
3573
|
+
onTyping: sendTyping,
|
|
3574
|
+
replyTo,
|
|
3575
|
+
onCancelReply: () => setReplyTo(null)
|
|
3576
|
+
}
|
|
3577
|
+
)
|
|
3578
|
+
] }),
|
|
3579
|
+
/* @__PURE__ */ jsxRuntime.jsx(Toast, { toast, onDismiss: () => setToast(null) })
|
|
3580
|
+
] });
|
|
3178
3581
|
}
|
|
3179
3582
|
var panelStyles = {
|
|
3180
3583
|
container: {
|
|
3584
|
+
position: "relative",
|
|
3181
3585
|
display: "flex",
|
|
3182
3586
|
flexDirection: "column",
|
|
3183
3587
|
height: "100%",
|
|
@@ -3244,6 +3648,7 @@ function ExpandIcon({ size = 18, color = "currentColor" }) {
|
|
|
3244
3648
|
}
|
|
3245
3649
|
);
|
|
3246
3650
|
}
|
|
3651
|
+
var FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
|
|
3247
3652
|
function CollabPopup({
|
|
3248
3653
|
orderId,
|
|
3249
3654
|
patientData,
|
|
@@ -3265,6 +3670,8 @@ function CollabPopup({
|
|
|
3265
3670
|
const [isMinimized, setIsMinimized] = React4.useState(false);
|
|
3266
3671
|
const dragOffset = React4.useRef({ x: 0, y: 0 });
|
|
3267
3672
|
const containerRef = React4.useRef(null);
|
|
3673
|
+
const previouslyFocused = React4.useRef(null);
|
|
3674
|
+
const titleId = React4.useId();
|
|
3268
3675
|
const handleMouseDown = React4.useCallback(
|
|
3269
3676
|
(e) => {
|
|
3270
3677
|
if (!e.target.closest("[data-drag-handle]")) return;
|
|
@@ -3279,13 +3686,44 @@ function CollabPopup({
|
|
|
3279
3686
|
);
|
|
3280
3687
|
React4.useEffect(() => {
|
|
3281
3688
|
if (!isOpen) return;
|
|
3689
|
+
previouslyFocused.current = document.activeElement;
|
|
3690
|
+
const focusFirst = () => {
|
|
3691
|
+
const root = containerRef.current;
|
|
3692
|
+
if (!root) return;
|
|
3693
|
+
const first = root.querySelector(FOCUSABLE_SELECTOR);
|
|
3694
|
+
(first ?? root).focus();
|
|
3695
|
+
};
|
|
3696
|
+
const raf = requestAnimationFrame(focusFirst);
|
|
3282
3697
|
const handleKey = (e) => {
|
|
3283
3698
|
if (e.key === "Escape") {
|
|
3284
3699
|
onClose();
|
|
3700
|
+
return;
|
|
3701
|
+
}
|
|
3702
|
+
if (e.key !== "Tab") return;
|
|
3703
|
+
const root = containerRef.current;
|
|
3704
|
+
if (!root) return;
|
|
3705
|
+
const focusables = Array.from(root.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
3706
|
+
if (focusables.length === 0) {
|
|
3707
|
+
e.preventDefault();
|
|
3708
|
+
return;
|
|
3709
|
+
}
|
|
3710
|
+
const first = focusables[0];
|
|
3711
|
+
const last = focusables[focusables.length - 1];
|
|
3712
|
+
const active = document.activeElement;
|
|
3713
|
+
if (e.shiftKey && active === first) {
|
|
3714
|
+
e.preventDefault();
|
|
3715
|
+
last.focus();
|
|
3716
|
+
} else if (!e.shiftKey && active === last) {
|
|
3717
|
+
e.preventDefault();
|
|
3718
|
+
first.focus();
|
|
3285
3719
|
}
|
|
3286
3720
|
};
|
|
3287
3721
|
window.addEventListener("keydown", handleKey);
|
|
3288
|
-
return () =>
|
|
3722
|
+
return () => {
|
|
3723
|
+
cancelAnimationFrame(raf);
|
|
3724
|
+
window.removeEventListener("keydown", handleKey);
|
|
3725
|
+
previouslyFocused.current?.focus?.();
|
|
3726
|
+
};
|
|
3289
3727
|
}, [isOpen, onClose]);
|
|
3290
3728
|
React4.useEffect(() => {
|
|
3291
3729
|
if (!isDragging) return;
|
|
@@ -3311,8 +3749,12 @@ function CollabPopup({
|
|
|
3311
3749
|
{
|
|
3312
3750
|
ref: containerRef,
|
|
3313
3751
|
className,
|
|
3752
|
+
role: "dialog",
|
|
3753
|
+
"aria-modal": "true",
|
|
3754
|
+
"aria-labelledby": titleId,
|
|
3755
|
+
tabIndex: -1,
|
|
3314
3756
|
style: {
|
|
3315
|
-
...
|
|
3757
|
+
...styles13.container,
|
|
3316
3758
|
left: position.x,
|
|
3317
3759
|
top: position.y,
|
|
3318
3760
|
width,
|
|
@@ -3321,14 +3763,14 @@ function CollabPopup({
|
|
|
3321
3763
|
},
|
|
3322
3764
|
onMouseDown: handleMouseDown,
|
|
3323
3765
|
children: [
|
|
3324
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-drag-handle": true, style:
|
|
3325
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
3326
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
3766
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { "data-drag-handle": true, style: styles13.titleBar, children: [
|
|
3767
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { id: titleId, style: styles13.titleText, children: buildChannelName(patientData) }),
|
|
3768
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles13.titleActions, children: [
|
|
3327
3769
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3328
3770
|
"button",
|
|
3329
3771
|
{
|
|
3330
3772
|
onClick: () => setIsMinimized(!isMinimized),
|
|
3331
|
-
style:
|
|
3773
|
+
style: styles13.titleButton,
|
|
3332
3774
|
"aria-label": isMinimized ? "Expand chat" : "Minimize chat",
|
|
3333
3775
|
title: isMinimized ? "Expand" : "Minimize",
|
|
3334
3776
|
type: "button",
|
|
@@ -3339,7 +3781,7 @@ function CollabPopup({
|
|
|
3339
3781
|
"button",
|
|
3340
3782
|
{
|
|
3341
3783
|
onClick: onClose,
|
|
3342
|
-
style:
|
|
3784
|
+
style: styles13.titleButton,
|
|
3343
3785
|
"aria-label": "Close chat",
|
|
3344
3786
|
title: "Close",
|
|
3345
3787
|
type: "button",
|
|
@@ -3348,12 +3790,12 @@ function CollabPopup({
|
|
|
3348
3790
|
)
|
|
3349
3791
|
] })
|
|
3350
3792
|
] }),
|
|
3351
|
-
!isMinimized && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
3793
|
+
!isMinimized && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles13.panelWrapper, children: /* @__PURE__ */ jsxRuntime.jsx(CollabPanel, { orderId, patientData, participantIds }) })
|
|
3352
3794
|
]
|
|
3353
3795
|
}
|
|
3354
3796
|
);
|
|
3355
3797
|
}
|
|
3356
|
-
var
|
|
3798
|
+
var styles13 = {
|
|
3357
3799
|
container: {
|
|
3358
3800
|
position: "fixed",
|
|
3359
3801
|
zIndex: 9999,
|
|
@@ -3658,11 +4100,11 @@ function CollabInline({
|
|
|
3658
4100
|
containerRef
|
|
3659
4101
|
} = useInlineCollab({ orderId, patientData, participantIds, messageLimit });
|
|
3660
4102
|
if (isLoading && !hasConversation) {
|
|
3661
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...
|
|
4103
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className, style: { ...styles14.container, ...style }, children: /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.loadingState, children: "Loading..." }) });
|
|
3662
4104
|
}
|
|
3663
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className, style: { ...
|
|
3664
|
-
hasConversation && messages.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
3665
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4105
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: containerRef, className, style: { ...styles14.container, ...style }, children: [
|
|
4106
|
+
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
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.error, children: error }),
|
|
3666
4108
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3667
4109
|
InlineInputBar,
|
|
3668
4110
|
{
|
|
@@ -3679,12 +4121,12 @@ function CollabInline({
|
|
|
3679
4121
|
}
|
|
3680
4122
|
function InlineMessageRow({ message }) {
|
|
3681
4123
|
if (message.type === "system") {
|
|
3682
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4124
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles14.systemRow, children: /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles14.systemText, children: message.body }) });
|
|
3683
4125
|
}
|
|
3684
4126
|
if (message.type === "audio" && message.mediaUrl) {
|
|
3685
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4127
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles14.messageRow, children: [
|
|
3686
4128
|
/* @__PURE__ */ jsxRuntime.jsx(RoleDot, { role: message.senderRole }),
|
|
3687
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style:
|
|
4129
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles14.senderName, children: [
|
|
3688
4130
|
message.senderName,
|
|
3689
4131
|
":"
|
|
3690
4132
|
] }),
|
|
@@ -3692,13 +4134,13 @@ function InlineMessageRow({ message }) {
|
|
|
3692
4134
|
] });
|
|
3693
4135
|
}
|
|
3694
4136
|
const preview = renderMessagePreview(message);
|
|
3695
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4137
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles14.messageRow, children: [
|
|
3696
4138
|
/* @__PURE__ */ jsxRuntime.jsx(RoleDot, { role: message.senderRole }),
|
|
3697
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style:
|
|
4139
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles14.senderName, children: [
|
|
3698
4140
|
message.senderName,
|
|
3699
4141
|
":"
|
|
3700
4142
|
] }),
|
|
3701
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4143
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles14.messageText, children: preview })
|
|
3702
4144
|
] });
|
|
3703
4145
|
}
|
|
3704
4146
|
function RoleDot({ role }) {
|
|
@@ -3708,7 +4150,7 @@ function RoleDot({ role }) {
|
|
|
3708
4150
|
physician: "#059669",
|
|
3709
4151
|
admin: "#dc2626"
|
|
3710
4152
|
};
|
|
3711
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
4153
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.roleDot, backgroundColor: colors[role] } });
|
|
3712
4154
|
}
|
|
3713
4155
|
function InlineAudioPlayer({ url, duration }) {
|
|
3714
4156
|
const audioRef = React4.useRef(null);
|
|
@@ -3752,27 +4194,27 @@ function InlineAudioPlayer({ url, duration }) {
|
|
|
3752
4194
|
const total = duration ?? 0;
|
|
3753
4195
|
const remaining = Math.max(0, total - Math.floor(currentTime));
|
|
3754
4196
|
const displayTime = isPlaying ? remaining : total;
|
|
3755
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { style:
|
|
4197
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles14.audioPlayer, children: [
|
|
3756
4198
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3757
4199
|
"button",
|
|
3758
4200
|
{
|
|
3759
4201
|
onClick: toggle,
|
|
3760
|
-
style:
|
|
4202
|
+
style: styles14.audioButton,
|
|
3761
4203
|
title: isPlaying ? "Pause" : "Play",
|
|
3762
4204
|
type: "button",
|
|
3763
4205
|
children: isPlaying ? "\u23F8" : "\u25B6"
|
|
3764
4206
|
}
|
|
3765
4207
|
),
|
|
3766
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { style:
|
|
3767
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3768
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3769
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3770
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3771
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3772
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
3773
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...
|
|
4208
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { style: styles14.audioWaveform, children: [
|
|
4209
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "40%" } }),
|
|
4210
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "80%" } }),
|
|
4211
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "60%" } }),
|
|
4212
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "90%" } }),
|
|
4213
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "50%" } }),
|
|
4214
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "70%" } }),
|
|
4215
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { ...styles14.waveBar, height: "40%" } })
|
|
3774
4216
|
] }),
|
|
3775
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4217
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: styles14.audioDuration, children: formatDuration2(displayTime) }),
|
|
3776
4218
|
/* @__PURE__ */ jsxRuntime.jsx("audio", { ref: audioRef, src: url, preload: "metadata" })
|
|
3777
4219
|
] });
|
|
3778
4220
|
}
|
|
@@ -3828,7 +4270,7 @@ function InlineInputBar({
|
|
|
3828
4270
|
},
|
|
3829
4271
|
[handleSend]
|
|
3830
4272
|
);
|
|
3831
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4273
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles14.inputBar, children: [
|
|
3832
4274
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3833
4275
|
"input",
|
|
3834
4276
|
{
|
|
@@ -3839,17 +4281,17 @@ function InlineInputBar({
|
|
|
3839
4281
|
onKeyDown: handleKeyDown,
|
|
3840
4282
|
placeholder,
|
|
3841
4283
|
disabled: isSending,
|
|
3842
|
-
style:
|
|
4284
|
+
style: styles14.input
|
|
3843
4285
|
}
|
|
3844
4286
|
),
|
|
3845
|
-
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
3846
|
-
isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4287
|
+
unreadCount > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles14.unreadBadge, title: `${unreadCount} unread`, children: unreadCount > 99 ? "99+" : unreadCount }),
|
|
4288
|
+
isLive && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles14.liveDot, title: "Live updates active" }),
|
|
3847
4289
|
text.trim() && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3848
4290
|
"button",
|
|
3849
4291
|
{
|
|
3850
4292
|
onClick: handleSend,
|
|
3851
4293
|
disabled: isSending,
|
|
3852
|
-
style:
|
|
4294
|
+
style: styles14.sendButton,
|
|
3853
4295
|
title: "Send message",
|
|
3854
4296
|
type: "button",
|
|
3855
4297
|
children: "\u27A4"
|
|
@@ -3859,7 +4301,7 @@ function InlineInputBar({
|
|
|
3859
4301
|
"button",
|
|
3860
4302
|
{
|
|
3861
4303
|
onClick: onExpand,
|
|
3862
|
-
style:
|
|
4304
|
+
style: styles14.expandButton,
|
|
3863
4305
|
title: "Expand to full chat",
|
|
3864
4306
|
type: "button",
|
|
3865
4307
|
children: "\u26F6"
|
|
@@ -3867,7 +4309,7 @@ function InlineInputBar({
|
|
|
3867
4309
|
)
|
|
3868
4310
|
] });
|
|
3869
4311
|
}
|
|
3870
|
-
var
|
|
4312
|
+
var styles14 = {
|
|
3871
4313
|
container: {
|
|
3872
4314
|
display: "flex",
|
|
3873
4315
|
flexDirection: "column",
|
|
@@ -4134,24 +4576,24 @@ function ConversationListItem({
|
|
|
4134
4576
|
className,
|
|
4135
4577
|
onClick,
|
|
4136
4578
|
style: {
|
|
4137
|
-
...
|
|
4138
|
-
...isSelected ?
|
|
4139
|
-
...hasUnread ?
|
|
4579
|
+
...styles15.container,
|
|
4580
|
+
...isSelected ? styles15.selected : {},
|
|
4581
|
+
...hasUnread ? styles15.unread : {}
|
|
4140
4582
|
},
|
|
4141
4583
|
type: "button",
|
|
4142
4584
|
children: [
|
|
4143
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4144
|
-
item.picture ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.picture, alt: "", style:
|
|
4145
|
-
hasUnread && /* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4585
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles15.avatarWrapper, children: [
|
|
4586
|
+
item.picture ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: item.picture, alt: "", style: styles15.avatar }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles15.avatarFallback, children: (displayName).charAt(0).toUpperCase() }),
|
|
4587
|
+
hasUnread && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles15.unreadDot })
|
|
4146
4588
|
] }),
|
|
4147
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4148
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4589
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles15.content, children: [
|
|
4590
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles15.topRow, children: [
|
|
4149
4591
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4150
4592
|
"span",
|
|
4151
4593
|
{
|
|
4152
4594
|
style: {
|
|
4153
|
-
...
|
|
4154
|
-
...hasUnread ?
|
|
4595
|
+
...styles15.name,
|
|
4596
|
+
...hasUnread ? styles15.nameUnread : {}
|
|
4155
4597
|
},
|
|
4156
4598
|
children: displayName
|
|
4157
4599
|
}
|
|
@@ -4160,25 +4602,25 @@ function ConversationListItem({
|
|
|
4160
4602
|
"span",
|
|
4161
4603
|
{
|
|
4162
4604
|
style: {
|
|
4163
|
-
...
|
|
4164
|
-
...hasUnread ?
|
|
4605
|
+
...styles15.time,
|
|
4606
|
+
...hasUnread ? styles15.timeUnread : {}
|
|
4165
4607
|
},
|
|
4166
4608
|
children: formatInboxTimestamp(item.lastActivityAt)
|
|
4167
4609
|
}
|
|
4168
4610
|
)
|
|
4169
4611
|
] }),
|
|
4170
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4612
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles15.bottomRow, children: [
|
|
4171
4613
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4172
4614
|
"span",
|
|
4173
4615
|
{
|
|
4174
4616
|
style: {
|
|
4175
|
-
...
|
|
4176
|
-
...hasUnread ?
|
|
4617
|
+
...styles15.preview,
|
|
4618
|
+
...hasUnread ? styles15.previewUnread : {}
|
|
4177
4619
|
},
|
|
4178
4620
|
children: renderLastMessagePreview(item.lastMessage)
|
|
4179
4621
|
}
|
|
4180
4622
|
),
|
|
4181
|
-
hasUnread && /* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4623
|
+
hasUnread && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles15.badge, children: item.unreadCount > 99 ? "99+" : item.unreadCount })
|
|
4182
4624
|
] })
|
|
4183
4625
|
] })
|
|
4184
4626
|
]
|
|
@@ -4206,7 +4648,7 @@ function renderLastMessagePreview(message) {
|
|
|
4206
4648
|
}
|
|
4207
4649
|
}
|
|
4208
4650
|
}
|
|
4209
|
-
var
|
|
4651
|
+
var styles15 = {
|
|
4210
4652
|
container: {
|
|
4211
4653
|
display: "flex",
|
|
4212
4654
|
alignItems: "center",
|
|
@@ -4353,30 +4795,30 @@ function ConversationList({
|
|
|
4353
4795
|
return result;
|
|
4354
4796
|
}, [conversations, query, showUnreadOnly]);
|
|
4355
4797
|
const totalUnread = conversations.reduce((sum, c) => sum + c.unreadCount, 0);
|
|
4356
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style:
|
|
4357
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4358
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4359
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { style:
|
|
4360
|
-
totalUnread > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style:
|
|
4798
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: styles16.container, children: [
|
|
4799
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles16.header, children: [
|
|
4800
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles16.titleRow, children: [
|
|
4801
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { style: styles16.title, children: title }),
|
|
4802
|
+
totalUnread > 0 && /* @__PURE__ */ jsxRuntime.jsx("span", { style: styles16.totalBadge, children: totalUnread })
|
|
4361
4803
|
] }),
|
|
4362
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4804
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles16.searchRow, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4363
4805
|
"input",
|
|
4364
4806
|
{
|
|
4365
4807
|
type: "text",
|
|
4366
4808
|
value: query,
|
|
4367
4809
|
onChange: (e) => setQuery(e.target.value),
|
|
4368
4810
|
placeholder: "Search patients or channels...",
|
|
4369
|
-
style:
|
|
4811
|
+
style: styles16.searchInput
|
|
4370
4812
|
}
|
|
4371
4813
|
) }),
|
|
4372
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4814
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles16.filterRow, children: [
|
|
4373
4815
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4374
4816
|
"button",
|
|
4375
4817
|
{
|
|
4376
4818
|
onClick: () => setShowUnreadOnly(false),
|
|
4377
4819
|
style: {
|
|
4378
|
-
...
|
|
4379
|
-
...!showUnreadOnly ?
|
|
4820
|
+
...styles16.filterButton,
|
|
4821
|
+
...!showUnreadOnly ? styles16.filterButtonActive : {}
|
|
4380
4822
|
},
|
|
4381
4823
|
type: "button",
|
|
4382
4824
|
children: "All"
|
|
@@ -4387,8 +4829,8 @@ function ConversationList({
|
|
|
4387
4829
|
{
|
|
4388
4830
|
onClick: () => setShowUnreadOnly(true),
|
|
4389
4831
|
style: {
|
|
4390
|
-
...
|
|
4391
|
-
...showUnreadOnly ?
|
|
4832
|
+
...styles16.filterButton,
|
|
4833
|
+
...showUnreadOnly ? styles16.filterButtonActive : {}
|
|
4392
4834
|
},
|
|
4393
4835
|
type: "button",
|
|
4394
4836
|
children: [
|
|
@@ -4399,10 +4841,10 @@ function ConversationList({
|
|
|
4399
4841
|
)
|
|
4400
4842
|
] })
|
|
4401
4843
|
] }),
|
|
4402
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4403
|
-
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4404
|
-
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4405
|
-
!isLoading && !error && filtered.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4844
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles16.list, children: [
|
|
4845
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles16.state, children: "Loading conversations..." }),
|
|
4846
|
+
error && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles16.errorState, children: error }),
|
|
4847
|
+
!isLoading && !error && filtered.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles16.state, children: query ? "No matching conversations" : "No conversations yet" }),
|
|
4406
4848
|
filtered.map((item) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
4407
4849
|
ConversationListItem,
|
|
4408
4850
|
{
|
|
@@ -4415,7 +4857,7 @@ function ConversationList({
|
|
|
4415
4857
|
] })
|
|
4416
4858
|
] });
|
|
4417
4859
|
}
|
|
4418
|
-
var
|
|
4860
|
+
var styles16 = {
|
|
4419
4861
|
container: {
|
|
4420
4862
|
display: "flex",
|
|
4421
4863
|
flexDirection: "column",
|
|
@@ -4520,8 +4962,8 @@ function CollabInbox({
|
|
|
4520
4962
|
setSelectedId(item.id);
|
|
4521
4963
|
onSelectConversation?.(item);
|
|
4522
4964
|
};
|
|
4523
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...
|
|
4524
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4965
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className, style: { ...styles17.container, ...style }, children: [
|
|
4966
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles17.sidebar, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4525
4967
|
ConversationList,
|
|
4526
4968
|
{
|
|
4527
4969
|
conversations,
|
|
@@ -4532,13 +4974,13 @@ function CollabInbox({
|
|
|
4532
4974
|
title
|
|
4533
4975
|
}
|
|
4534
4976
|
) }),
|
|
4535
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4977
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles17.main, children: selected ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
4536
4978
|
CollabPanel,
|
|
4537
4979
|
{
|
|
4538
4980
|
orderId: selected.orderId,
|
|
4539
4981
|
patientData: buildPatientData(selected),
|
|
4540
4982
|
showSeenBy: true,
|
|
4541
|
-
style:
|
|
4983
|
+
style: styles17.panel
|
|
4542
4984
|
},
|
|
4543
4985
|
selected.id
|
|
4544
4986
|
) : /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { hasAny: conversations.length > 0 }) })
|
|
@@ -4552,13 +4994,13 @@ function buildPatientData(item) {
|
|
|
4552
4994
|
};
|
|
4553
4995
|
}
|
|
4554
4996
|
function EmptyState({ hasAny }) {
|
|
4555
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style:
|
|
4556
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { style:
|
|
4557
|
-
/* @__PURE__ */ jsxRuntime.jsx("h3", { style:
|
|
4558
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { style:
|
|
4997
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { style: styles17.empty, children: [
|
|
4998
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: styles17.emptyIcon, children: "\u{1F4AC}" }),
|
|
4999
|
+
/* @__PURE__ */ jsxRuntime.jsx("h3", { style: styles17.emptyTitle, children: hasAny ? "Select a conversation" : "No conversations yet" }),
|
|
5000
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { style: styles17.emptySubtitle, children: hasAny ? "Pick a patient from the list to start collaborating" : "Conversations appear here once you start messaging about a case" })
|
|
4559
5001
|
] });
|
|
4560
5002
|
}
|
|
4561
|
-
var
|
|
5003
|
+
var styles17 = {
|
|
4562
5004
|
container: {
|
|
4563
5005
|
display: "flex",
|
|
4564
5006
|
height: "100%",
|