@natoe/colab 0.1.24 → 0.1.27
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 +31 -2
- package/dist/index.d.ts +31 -2
- package/dist/index.js +88 -17
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -17
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -88,6 +88,19 @@ interface CollabConfig {
|
|
|
88
88
|
onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
|
|
89
89
|
onDeepLink?: (path: string) => void;
|
|
90
90
|
onError?: (error: CollabError) => void;
|
|
91
|
+
/**
|
|
92
|
+
* Report a message. The host captures any reason UI and calls its backend.
|
|
93
|
+
* The "Report" message action renders only when this callback is provided.
|
|
94
|
+
*/
|
|
95
|
+
onReportMessage?: (message: Message) => void | Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Block a user. The "Block" action renders only when this callback is set.
|
|
98
|
+
*/
|
|
99
|
+
onBlockUser?: (userId: string, userName: string) => void | Promise<void>;
|
|
100
|
+
/** Unblock a previously blocked user. */
|
|
101
|
+
onUnblockUser?: (userId: string) => void | Promise<void>;
|
|
102
|
+
/** IDs of users the current user has blocked — their messages are hidden. */
|
|
103
|
+
blockedUserIds?: string[];
|
|
91
104
|
}
|
|
92
105
|
type UserRole = 'lab' | 'radiologist' | 'physician' | 'admin';
|
|
93
106
|
interface PatientData {
|
|
@@ -932,6 +945,12 @@ interface MessageListProps {
|
|
|
932
945
|
onPin?: (messageId: string) => void;
|
|
933
946
|
onUnpin?: (messageId: string) => void;
|
|
934
947
|
onCopy?: (text: string) => void;
|
|
948
|
+
/** Report a message (moderation). Shown only for others' messages. */
|
|
949
|
+
onReport?: (message: Message) => void;
|
|
950
|
+
/** Block a message's sender (moderation). Shown only for others' messages. */
|
|
951
|
+
onBlock?: (message: Message) => void;
|
|
952
|
+
/** Sender IDs to hide locally (blocked users). */
|
|
953
|
+
blockedUserIds?: string[];
|
|
935
954
|
/** Retry a failed message (own bubbles only) */
|
|
936
955
|
onRetry?: (messageId: string) => void;
|
|
937
956
|
pinDisabled?: boolean;
|
|
@@ -953,6 +972,10 @@ interface MessageBubbleProps {
|
|
|
953
972
|
onPin?: (messageId: string) => void;
|
|
954
973
|
onUnpin?: (messageId: string) => void;
|
|
955
974
|
onCopy?: (text: string) => void;
|
|
975
|
+
/** Report this message (moderation). Only shown for others' messages. */
|
|
976
|
+
onReport?: (message: Message) => void;
|
|
977
|
+
/** Block this message's sender (moderation). Only shown for others' messages. */
|
|
978
|
+
onBlock?: (message: Message) => void;
|
|
956
979
|
onReplyJumpTo?: (messageId: string) => void;
|
|
957
980
|
/** Re-send a previously-failed message (own bubbles only) */
|
|
958
981
|
onRetry?: (messageId: string) => void;
|
|
@@ -960,7 +983,7 @@ interface MessageBubbleProps {
|
|
|
960
983
|
pinDisabled?: boolean;
|
|
961
984
|
className?: string;
|
|
962
985
|
}
|
|
963
|
-
declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
|
|
986
|
+
declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReport, onBlock, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
|
|
964
987
|
|
|
965
988
|
interface MessageInputProps {
|
|
966
989
|
onSendText: (body: string) => Promise<void>;
|
|
@@ -984,6 +1007,12 @@ interface MessageActionsMenuProps {
|
|
|
984
1007
|
onPin: (messageId: string) => void;
|
|
985
1008
|
onUnpin: (messageId: string) => void;
|
|
986
1009
|
onCopy?: (text: string) => void;
|
|
1010
|
+
/** Report this message (moderation). Rendered only when `canModerate`. */
|
|
1011
|
+
onReport?: (message: Message) => void;
|
|
1012
|
+
/** Block this message's sender (moderation). Rendered only when `canModerate`. */
|
|
1013
|
+
onBlock?: (message: Message) => void;
|
|
1014
|
+
/** Enable moderation actions (Report / Block) — true for others' messages. */
|
|
1015
|
+
canModerate?: boolean;
|
|
987
1016
|
/** Whether we've hit the pin limit — if true, pin is disabled */
|
|
988
1017
|
pinDisabled?: boolean;
|
|
989
1018
|
/** Anchor the popover to the right edge of the trigger (use for messages on the left side of the panel) */
|
|
@@ -998,7 +1027,7 @@ interface MessageActionsMenuProps {
|
|
|
998
1027
|
*
|
|
999
1028
|
* Closes on outside-click, Escape, window resize, or scroll outside the menu.
|
|
1000
1029
|
*/
|
|
1001
|
-
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
1030
|
+
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, onReport, onBlock, canModerate, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
1002
1031
|
|
|
1003
1032
|
interface ReplyPreviewProps {
|
|
1004
1033
|
/** The message being replied to */
|
package/dist/index.d.ts
CHANGED
|
@@ -88,6 +88,19 @@ interface CollabConfig {
|
|
|
88
88
|
onUploadFile?: (file: File | Blob, fileName?: string) => Promise<string>;
|
|
89
89
|
onDeepLink?: (path: string) => void;
|
|
90
90
|
onError?: (error: CollabError) => void;
|
|
91
|
+
/**
|
|
92
|
+
* Report a message. The host captures any reason UI and calls its backend.
|
|
93
|
+
* The "Report" message action renders only when this callback is provided.
|
|
94
|
+
*/
|
|
95
|
+
onReportMessage?: (message: Message) => void | Promise<void>;
|
|
96
|
+
/**
|
|
97
|
+
* Block a user. The "Block" action renders only when this callback is set.
|
|
98
|
+
*/
|
|
99
|
+
onBlockUser?: (userId: string, userName: string) => void | Promise<void>;
|
|
100
|
+
/** Unblock a previously blocked user. */
|
|
101
|
+
onUnblockUser?: (userId: string) => void | Promise<void>;
|
|
102
|
+
/** IDs of users the current user has blocked — their messages are hidden. */
|
|
103
|
+
blockedUserIds?: string[];
|
|
91
104
|
}
|
|
92
105
|
type UserRole = 'lab' | 'radiologist' | 'physician' | 'admin';
|
|
93
106
|
interface PatientData {
|
|
@@ -932,6 +945,12 @@ interface MessageListProps {
|
|
|
932
945
|
onPin?: (messageId: string) => void;
|
|
933
946
|
onUnpin?: (messageId: string) => void;
|
|
934
947
|
onCopy?: (text: string) => void;
|
|
948
|
+
/** Report a message (moderation). Shown only for others' messages. */
|
|
949
|
+
onReport?: (message: Message) => void;
|
|
950
|
+
/** Block a message's sender (moderation). Shown only for others' messages. */
|
|
951
|
+
onBlock?: (message: Message) => void;
|
|
952
|
+
/** Sender IDs to hide locally (blocked users). */
|
|
953
|
+
blockedUserIds?: string[];
|
|
935
954
|
/** Retry a failed message (own bubbles only) */
|
|
936
955
|
onRetry?: (messageId: string) => void;
|
|
937
956
|
pinDisabled?: boolean;
|
|
@@ -953,6 +972,10 @@ interface MessageBubbleProps {
|
|
|
953
972
|
onPin?: (messageId: string) => void;
|
|
954
973
|
onUnpin?: (messageId: string) => void;
|
|
955
974
|
onCopy?: (text: string) => void;
|
|
975
|
+
/** Report this message (moderation). Only shown for others' messages. */
|
|
976
|
+
onReport?: (message: Message) => void;
|
|
977
|
+
/** Block this message's sender (moderation). Only shown for others' messages. */
|
|
978
|
+
onBlock?: (message: Message) => void;
|
|
956
979
|
onReplyJumpTo?: (messageId: string) => void;
|
|
957
980
|
/** Re-send a previously-failed message (own bubbles only) */
|
|
958
981
|
onRetry?: (messageId: string) => void;
|
|
@@ -960,7 +983,7 @@ interface MessageBubbleProps {
|
|
|
960
983
|
pinDisabled?: boolean;
|
|
961
984
|
className?: string;
|
|
962
985
|
}
|
|
963
|
-
declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
|
|
986
|
+
declare function MessageBubble({ message, isOwn, participants, currentUserId, showSeenBy, onDeepLinkClick, onReply, onPin, onUnpin, onCopy, onReport, onBlock, onReplyJumpTo, onRetry, pinDisabled, className, }: MessageBubbleProps): react_jsx_runtime.JSX.Element;
|
|
964
987
|
|
|
965
988
|
interface MessageInputProps {
|
|
966
989
|
onSendText: (body: string) => Promise<void>;
|
|
@@ -984,6 +1007,12 @@ interface MessageActionsMenuProps {
|
|
|
984
1007
|
onPin: (messageId: string) => void;
|
|
985
1008
|
onUnpin: (messageId: string) => void;
|
|
986
1009
|
onCopy?: (text: string) => void;
|
|
1010
|
+
/** Report this message (moderation). Rendered only when `canModerate`. */
|
|
1011
|
+
onReport?: (message: Message) => void;
|
|
1012
|
+
/** Block this message's sender (moderation). Rendered only when `canModerate`. */
|
|
1013
|
+
onBlock?: (message: Message) => void;
|
|
1014
|
+
/** Enable moderation actions (Report / Block) — true for others' messages. */
|
|
1015
|
+
canModerate?: boolean;
|
|
987
1016
|
/** Whether we've hit the pin limit — if true, pin is disabled */
|
|
988
1017
|
pinDisabled?: boolean;
|
|
989
1018
|
/** Anchor the popover to the right edge of the trigger (use for messages on the left side of the panel) */
|
|
@@ -998,7 +1027,7 @@ interface MessageActionsMenuProps {
|
|
|
998
1027
|
*
|
|
999
1028
|
* Closes on outside-click, Escape, window resize, or scroll outside the menu.
|
|
1000
1029
|
*/
|
|
1001
|
-
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
1030
|
+
declare function MessageActionsMenu({ message, onReply, onPin, onUnpin, onCopy, onReport, onBlock, canModerate, pinDisabled, anchorRight, className, }: MessageActionsMenuProps): react_jsx_runtime.JSX.Element;
|
|
1002
1031
|
|
|
1003
1032
|
interface ReplyPreviewProps {
|
|
1004
1033
|
/** The message being replied to */
|
package/dist/index.js
CHANGED
|
@@ -1948,6 +1948,20 @@ function MoreIcon({ size = 18, color = "currentColor" }) {
|
|
|
1948
1948
|
}
|
|
1949
1949
|
);
|
|
1950
1950
|
}
|
|
1951
|
+
function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
1952
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1953
|
+
"svg",
|
|
1954
|
+
{
|
|
1955
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
1956
|
+
width: size,
|
|
1957
|
+
height: size,
|
|
1958
|
+
viewBox: "0 0 24 24",
|
|
1959
|
+
fill: color,
|
|
1960
|
+
"aria-hidden": "true",
|
|
1961
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
|
|
1962
|
+
}
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1951
1965
|
var VIEWPORT_MARGIN = 8;
|
|
1952
1966
|
var TRIGGER_GAP = 4;
|
|
1953
1967
|
function MessageActionsMenu({
|
|
@@ -1956,6 +1970,9 @@ function MessageActionsMenu({
|
|
|
1956
1970
|
onPin,
|
|
1957
1971
|
onUnpin,
|
|
1958
1972
|
onCopy,
|
|
1973
|
+
onReport,
|
|
1974
|
+
onBlock,
|
|
1975
|
+
canModerate = false,
|
|
1959
1976
|
pinDisabled = false,
|
|
1960
1977
|
anchorRight = false,
|
|
1961
1978
|
className
|
|
@@ -2094,6 +2111,36 @@ function MessageActionsMenu({
|
|
|
2094
2111
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Copy text" })
|
|
2095
2112
|
]
|
|
2096
2113
|
}
|
|
2114
|
+
),
|
|
2115
|
+
canModerate && (onReport || onBlock) && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles4.divider }),
|
|
2116
|
+
canModerate && onReport && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2117
|
+
"button",
|
|
2118
|
+
{
|
|
2119
|
+
type: "button",
|
|
2120
|
+
role: "menuitem",
|
|
2121
|
+
onClick: () => run(() => onReport(message)),
|
|
2122
|
+
style: styles4.item,
|
|
2123
|
+
children: [
|
|
2124
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16, color: COLOR.neutral700 }),
|
|
2125
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Report message" })
|
|
2126
|
+
]
|
|
2127
|
+
}
|
|
2128
|
+
),
|
|
2129
|
+
canModerate && onBlock && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2130
|
+
"button",
|
|
2131
|
+
{
|
|
2132
|
+
type: "button",
|
|
2133
|
+
role: "menuitem",
|
|
2134
|
+
onClick: () => run(() => onBlock(message)),
|
|
2135
|
+
style: { ...styles4.item, ...styles4.itemDanger },
|
|
2136
|
+
children: [
|
|
2137
|
+
/* @__PURE__ */ jsxRuntime.jsx(AlertIcon, { size: 16, color: "#c0392b" }),
|
|
2138
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
|
|
2139
|
+
"Block ",
|
|
2140
|
+
message.senderName
|
|
2141
|
+
] })
|
|
2142
|
+
]
|
|
2143
|
+
}
|
|
2097
2144
|
)
|
|
2098
2145
|
]
|
|
2099
2146
|
}
|
|
@@ -2172,6 +2219,14 @@ var styles4 = {
|
|
|
2172
2219
|
itemDisabled: {
|
|
2173
2220
|
color: COLOR.neutral400,
|
|
2174
2221
|
cursor: "not-allowed"
|
|
2222
|
+
},
|
|
2223
|
+
itemDanger: {
|
|
2224
|
+
color: "#c0392b"
|
|
2225
|
+
},
|
|
2226
|
+
divider: {
|
|
2227
|
+
height: "1px",
|
|
2228
|
+
backgroundColor: COLOR.neutral200,
|
|
2229
|
+
margin: "4px 0"
|
|
2175
2230
|
}
|
|
2176
2231
|
};
|
|
2177
2232
|
function FileIcon({ size = 18, color = "currentColor" }) {
|
|
@@ -2188,20 +2243,6 @@ function FileIcon({ size = 18, color = "currentColor" }) {
|
|
|
2188
2243
|
}
|
|
2189
2244
|
);
|
|
2190
2245
|
}
|
|
2191
|
-
function AlertIcon({ size = 14, color = "currentColor" }) {
|
|
2192
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2193
|
-
"svg",
|
|
2194
|
-
{
|
|
2195
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
2196
|
-
width: size,
|
|
2197
|
-
height: size,
|
|
2198
|
-
viewBox: "0 0 24 24",
|
|
2199
|
-
fill: color,
|
|
2200
|
-
"aria-hidden": "true",
|
|
2201
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z" })
|
|
2202
|
-
}
|
|
2203
|
-
);
|
|
2204
|
-
}
|
|
2205
2246
|
function RoleAvatarIcon({
|
|
2206
2247
|
role,
|
|
2207
2248
|
size = 18,
|
|
@@ -2303,6 +2344,8 @@ function MessageBubble({
|
|
|
2303
2344
|
onPin,
|
|
2304
2345
|
onUnpin,
|
|
2305
2346
|
onCopy,
|
|
2347
|
+
onReport,
|
|
2348
|
+
onBlock,
|
|
2306
2349
|
onReplyJumpTo,
|
|
2307
2350
|
onRetry,
|
|
2308
2351
|
pinDisabled = false,
|
|
@@ -2311,7 +2354,8 @@ function MessageBubble({
|
|
|
2311
2354
|
if (message.type === "system") {
|
|
2312
2355
|
return /* @__PURE__ */ jsxRuntime.jsx(SystemBubble, { message });
|
|
2313
2356
|
}
|
|
2314
|
-
const
|
|
2357
|
+
const canModerate = !isOwn && !!(onReport || onBlock);
|
|
2358
|
+
const hasActions = !!(onReply || onPin || onUnpin || onCopy) || canModerate;
|
|
2315
2359
|
const actionsSlot = hasActions ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles5.actionsSlot, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2316
2360
|
MessageActionsMenu,
|
|
2317
2361
|
{
|
|
@@ -2323,6 +2367,9 @@ function MessageBubble({
|
|
|
2323
2367
|
onUnpin: onUnpin ?? (() => {
|
|
2324
2368
|
}),
|
|
2325
2369
|
onCopy,
|
|
2370
|
+
onReport,
|
|
2371
|
+
onBlock,
|
|
2372
|
+
canModerate,
|
|
2326
2373
|
pinDisabled,
|
|
2327
2374
|
anchorRight: !isOwn
|
|
2328
2375
|
}
|
|
@@ -2859,6 +2906,9 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
2859
2906
|
onPin,
|
|
2860
2907
|
onUnpin,
|
|
2861
2908
|
onCopy,
|
|
2909
|
+
onReport,
|
|
2910
|
+
onBlock,
|
|
2911
|
+
blockedUserIds,
|
|
2862
2912
|
onRetry,
|
|
2863
2913
|
pinDisabled,
|
|
2864
2914
|
className
|
|
@@ -2962,7 +3012,7 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
2962
3012
|
messages.length === 0 && isLoading && /* @__PURE__ */ jsxRuntime.jsx("div", { style: styles6.firstLoad, children: /* @__PURE__ */ jsxRuntime.jsx(Spinner, { size: 20 }) }),
|
|
2963
3013
|
(() => {
|
|
2964
3014
|
let lastValidBucket = null;
|
|
2965
|
-
return messages.map((message) => {
|
|
3015
|
+
return messages.filter((m) => !blockedUserIds?.includes(m.senderId)).map((message) => {
|
|
2966
3016
|
const currentBucket = dayBucketKey(message.insertedAt);
|
|
2967
3017
|
const showDivider = !!currentBucket && currentBucket !== lastValidBucket;
|
|
2968
3018
|
if (currentBucket) lastValidBucket = currentBucket;
|
|
@@ -2985,6 +3035,8 @@ var MessageList = React4.forwardRef(function MessageList2({
|
|
|
2985
3035
|
onPin,
|
|
2986
3036
|
onUnpin,
|
|
2987
3037
|
onCopy,
|
|
3038
|
+
onReport,
|
|
3039
|
+
onBlock,
|
|
2988
3040
|
onRetry,
|
|
2989
3041
|
pinDisabled
|
|
2990
3042
|
}
|
|
@@ -4604,6 +4656,9 @@ function CollabPanel({
|
|
|
4604
4656
|
onPin: handlePin,
|
|
4605
4657
|
onUnpin: handleUnpin,
|
|
4606
4658
|
onCopy: handleCopy,
|
|
4659
|
+
onReport: config.onReportMessage ? (m) => config.onReportMessage(m) : void 0,
|
|
4660
|
+
onBlock: config.onBlockUser ? (m) => config.onBlockUser(m.senderId, m.senderName) : void 0,
|
|
4661
|
+
blockedUserIds: config.blockedUserIds,
|
|
4607
4662
|
onRetry: retryMessage,
|
|
4608
4663
|
pinDisabled
|
|
4609
4664
|
}
|
|
@@ -5022,6 +5077,8 @@ function useInlineCollab({
|
|
|
5022
5077
|
const elementRef = React4.useRef(null);
|
|
5023
5078
|
const observerRef = React4.useRef(null);
|
|
5024
5079
|
const subscribedConversationIdRef = React4.useRef(null);
|
|
5080
|
+
const latestMessageIdRef = React4.useRef(null);
|
|
5081
|
+
const lastMarkedReadIdRef = React4.useRef(null);
|
|
5025
5082
|
const channelSubscriptionRef = React4.useRef(null);
|
|
5026
5083
|
const trimToLimit = React4.useCallback(
|
|
5027
5084
|
(msgs) => msgs.length > messageLimit ? msgs.slice(msgs.length - messageLimit) : msgs,
|
|
@@ -5031,6 +5088,18 @@ function useInlineCollab({
|
|
|
5031
5088
|
() => buildChannelName(patientData),
|
|
5032
5089
|
[patientData]
|
|
5033
5090
|
);
|
|
5091
|
+
React4.useEffect(() => {
|
|
5092
|
+
latestMessageIdRef.current = messages[messages.length - 1]?.id ?? null;
|
|
5093
|
+
}, [messages]);
|
|
5094
|
+
const markLatestRead = React4.useCallback(
|
|
5095
|
+
(conversationId) => {
|
|
5096
|
+
const messageId = latestMessageIdRef.current;
|
|
5097
|
+
if (!messageId || lastMarkedReadIdRef.current === messageId) return;
|
|
5098
|
+
lastMarkedReadIdRef.current = messageId;
|
|
5099
|
+
socket.markAsRead(conversationId, messageId);
|
|
5100
|
+
},
|
|
5101
|
+
[socket]
|
|
5102
|
+
);
|
|
5034
5103
|
React4.useEffect(() => {
|
|
5035
5104
|
let cancelled = false;
|
|
5036
5105
|
const load = async () => {
|
|
@@ -5164,6 +5233,7 @@ function useInlineCollab({
|
|
|
5164
5233
|
try {
|
|
5165
5234
|
await socket.sendMessage(preview.conversationId, payload);
|
|
5166
5235
|
setUnreadCount(0);
|
|
5236
|
+
markLatestRead(preview.conversationId);
|
|
5167
5237
|
} catch (err) {
|
|
5168
5238
|
setError(err instanceof Error ? err.message : "Failed to send message");
|
|
5169
5239
|
config.onError?.({
|
|
@@ -5182,7 +5252,8 @@ function useInlineCollab({
|
|
|
5182
5252
|
invalidatePreview,
|
|
5183
5253
|
subscribe,
|
|
5184
5254
|
socket,
|
|
5185
|
-
config
|
|
5255
|
+
config,
|
|
5256
|
+
markLatestRead
|
|
5186
5257
|
]
|
|
5187
5258
|
);
|
|
5188
5259
|
const sendMessage = React4.useCallback(
|