@droppii-org/chat-sdk 0.4.11 → 0.4.13

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,4CAynB9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationDetailInput.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationDetailInput.tsx"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAkB/D,MAAM,WAAW,4BAA4B;IAC3C,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,CAAC,EAAE,gBAAgB,EAAE,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,QAAA,MAAM,uBAAuB,GAAI,4EAM9B,4BAA4B,4CA8qB9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -4,8 +4,10 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { useBoolean } from "ahooks";
6
6
  import clsx from "clsx";
7
+ import { Button, message as toastMessage } from "antd";
7
8
  import { Icon } from "../../components/icon";
8
9
  import { useSendMessage } from "../../hooks/message/useSendMessage";
10
+ import { useJoinPublicGroup } from "../../hooks/group/useJoinPublicGroup";
9
11
  import useAuthStore from "../../store/auth";
10
12
  import useConversationStore from "../../store/conversation";
11
13
  import useMessageDraftStore from "../../store/messageDraft";
@@ -36,6 +38,38 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
36
38
  const conversationId = selectedConversationId || (conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationID) || "";
37
39
  const isConversationReady = !!conversationData && (!!conversationData.userID || !!conversationData.groupID);
38
40
  const isViewOnlyMember = useConversationStore((state) => state.isViewOnlyMember);
41
+ const setIsViewOnlyMember = useConversationStore((state) => state.setIsViewOnlyMember);
42
+ const getCurrentMemberInGroupByReq = useConversationStore((state) => state.getCurrentMemberInGroupByReq);
43
+ const getSelfGroupPermissionByReq = useConversationStore((state) => state.getSelfGroupPermissionByReq);
44
+ const { mutate: joinPublicGroup, isPending: isJoiningPublicGroup } = useJoinPublicGroup();
45
+ const handleJoinPublicGroup = useCallback(() => {
46
+ const groupID = conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID;
47
+ if (!groupID)
48
+ return;
49
+ joinPublicGroup({ groupID }, {
50
+ onSuccess: async () => {
51
+ toastMessage.success(tCommon("join_group_success"));
52
+ // updateCurrentConversation's revalidation only runs on a
53
+ // conversationID change — this is the same conversation the user
54
+ // was already viewing, so refresh membership/permissions directly
55
+ // instead, and flip isViewOnlyMember off immediately rather than
56
+ // waiting on a WS event that may not fire right away.
57
+ setIsViewOnlyMember(false);
58
+ await Promise.allSettled([
59
+ getCurrentMemberInGroupByReq(groupID),
60
+ getSelfGroupPermissionByReq(groupID),
61
+ ]);
62
+ },
63
+ onError: () => toastMessage.error(tCommon("join_group_failed")),
64
+ });
65
+ }, [
66
+ conversationData,
67
+ getCurrentMemberInGroupByReq,
68
+ getSelfGroupPermissionByReq,
69
+ joinPublicGroup,
70
+ setIsViewOnlyMember,
71
+ tCommon,
72
+ ]);
39
73
  const sendMessageOptions = useMemo(() => ({
40
74
  scrollEvent: "CONVERSATION_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM",
41
75
  }), []);
@@ -408,7 +442,7 @@ const ConversationDetailInput = ({ placeholder, onSendMessage, onInputChange, mo
408
442
  void handleSend();
409
443
  };
410
444
  if (isViewOnlyMember) {
411
- return (_jsx("div", { "data-testid": "conversation-detail-input-view-only", className: "flex w-full shrink-0 items-center justify-center bg-chat-bubble-neutral/[0.05] px-4 py-3 text-center text-sm text-gray-500", children: t("thread_detail.view_only_notice") }));
445
+ return (_jsxs("div", { "data-testid": "conversation-detail-input-view-only", className: "flex w-full shrink-0 items-center justify-between gap-3 bg-chat-bubble-neutral/[0.05] px-4 py-3", children: [_jsx("span", { className: "text-sm text-gray-500", children: t("thread_detail.view_only_notice") }), _jsx(Button, { type: "primary", size: "small", loading: isJoiningPublicGroup, onClick: handleJoinPublicGroup, children: tCommon("join_group") })] }));
412
446
  }
413
447
  return (_jsxs("div", { ref: containerRef, "data-testid": "conversation-detail-input", "data-cp-name": "ConversationDetailInput", className: "flex w-full shrink-0 flex-col bg-chat-bubble-neutral/[0.05]", children: [_jsx("input", { ref: mediaInputRef, type: "file", accept: "image/jpeg,image/png,image/jpg,video/*", multiple: true, className: "hidden", onChange: handleMediaInputChange }), _jsx("input", { ref: documentInputRef, type: "file", accept: ".pdf,.doc,.docx", multiple: true, className: "hidden", onChange: handleDocumentInputChange }), _jsx(ReplyPreviewBar, {}), listUploadFiles.length > 0 && (_jsx(FilePreviewList, { files: listUploadFiles, onRemove: (file) => handleRemoveFile(file.uid), onVideoReady: () => setIsVideoLoading(false) })), showLinkPreview && previewUrl && (_jsx(LinkInputPreview, { url: previewUrl, onRemove: () => setPreviewDismissed(true) })), _jsxs("div", { className: "flex items-end gap-3 px-3 py-2", children: [_jsx("div", { className: "flex shrink-0 items-center", children: _jsx("button", { type: "button", onClick: handleToggleMoreOption, "aria-label": t("thread_detail.more_option.toggle"), "aria-expanded": isMoreOptionOpen, "data-testid": "conversation-detail-more-option-toggle", className: "flex py-3 items-center justify-center rounded-full", children: isMoreOptionOpen ? (_jsx(Icon, { icon: "close-circle-b", size: 24, className: "text-primary-400" })) : (_jsx(Icon, { icon: "plus-circle-o", size: 24, className: "text-gray-900" })) }) }), _jsx("div", { className: clsx("flex min-w-0 flex-1 overflow-hidden rounded-xl border bg-white transition-shadow", isFocused
414
448
  ? "border-primary-200 shadow-primary-focus"
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAGL,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AAStB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoB/C,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAc/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,4CA0UpB,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/footer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAGL,wBAAwB,EAEzB,MAAM,cAAc,CAAC;AAUtB,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAoB/C,UAAU,kBAAkB;IAC1B,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AASD,eAAO,MAAM,oBAAoB,mDAc/B,CAAC;AAEH,eAAO,MAAM,uBAAuB,gCAAyC,CAAC;AAE9E,QAAA,MAAM,qBAAqB,GAAI,4CAG5B,kBAAkB,4CAgYpB,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -10,7 +10,8 @@ import EnterHandler from "./EnterHandler";
10
10
  import ActionBar from "./ActionBar";
11
11
  import { AccountType, } from "../../../types/chat";
12
12
  import { useSendMessage } from "../../../hooks/message/useSendMessage";
13
- import { Modal, Popover } from "antd";
13
+ import { useJoinPublicGroup } from "../../../hooks/group/useJoinPublicGroup";
14
+ import { Button, Modal, Popover, message as toastMessage } from "antd";
14
15
  import FilePreview from "./FilePreview";
15
16
  import LinkInputPreview from "./LinkInputPreview";
16
17
  import ComposerTextSyncPlugin from "./ComposerTextSyncPlugin";
@@ -72,6 +73,38 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
72
73
  const quotedMessage = useConversationStore((state) => state.quotedMessage);
73
74
  const conversationData = useConversationStore((state) => state.conversationData);
74
75
  const isViewOnlyMember = useConversationStore((state) => state.isViewOnlyMember);
76
+ const setIsViewOnlyMember = useConversationStore((state) => state.setIsViewOnlyMember);
77
+ const getCurrentMemberInGroupByReq = useConversationStore((state) => state.getCurrentMemberInGroupByReq);
78
+ const getSelfGroupPermissionByReq = useConversationStore((state) => state.getSelfGroupPermissionByReq);
79
+ const { mutate: joinPublicGroup, isPending: isJoiningPublicGroup } = useJoinPublicGroup();
80
+ const handleJoinPublicGroup = useCallback(() => {
81
+ const groupID = conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID;
82
+ if (!groupID)
83
+ return;
84
+ joinPublicGroup({ groupID }, {
85
+ onSuccess: async () => {
86
+ toastMessage.success(t("join_group_success"));
87
+ // updateCurrentConversation's revalidation only runs on a
88
+ // conversationID change — this is the same conversation the user
89
+ // was already viewing, so refresh membership/permissions directly
90
+ // instead, and flip isViewOnlyMember off immediately rather than
91
+ // waiting on a WS event that may not fire right away.
92
+ setIsViewOnlyMember(false);
93
+ await Promise.allSettled([
94
+ getCurrentMemberInGroupByReq(groupID),
95
+ getSelfGroupPermissionByReq(groupID),
96
+ ]);
97
+ },
98
+ onError: () => toastMessage.error(t("join_group_failed")),
99
+ });
100
+ }, [
101
+ conversationData,
102
+ getCurrentMemberInGroupByReq,
103
+ getSelfGroupPermissionByReq,
104
+ joinPublicGroup,
105
+ setIsViewOnlyMember,
106
+ t,
107
+ ]);
75
108
  // Internal notes are a CX-support concept (team-only remarks not sent to
76
109
  // the customer) — meaningless inside a real member-managed group, where
77
110
  // everyone in the thread already is the "team".
@@ -216,7 +249,7 @@ const MessageFooterProvider = ({ currentSession, openCreateCannedModal, }) => {
216
249
  closeCanned();
217
250
  };
218
251
  if (isViewOnlyMember) {
219
- return (_jsx("div", { "data-testid": "message-footer-view-only", className: "flex w-full items-center justify-center border-t border-gray-25 bg-white px-4 py-3 text-center text-sm text-gray-500", children: tConversationInbox("thread_detail.view_only_notice") }));
252
+ return (_jsxs("div", { "data-testid": "message-footer-view-only", className: "flex w-full items-center justify-between gap-3 border-t border-gray-25 bg-white px-4 py-3", children: [_jsx("span", { className: "text-sm text-gray-500", children: tConversationInbox("thread_detail.view_only_notice") }), _jsx(Button, { type: "primary", size: "small", loading: isJoiningPublicGroup, onClick: handleJoinPublicGroup, children: t("join_group") })] }));
220
253
  }
221
254
  return (_jsxs(MessageFooterContext.Provider, { value: {
222
255
  onSendMessage,
@@ -1 +1 @@
1
- {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC;AA6CD,QAAA,MAAM,aAAa,GAAI,uIAYpB,kBAAkB,4CAiEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,OAAO,EAAE,SAAS,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+EAA+E;IAC/E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,8EAA8E;IAC9E,kBAAkB,CAAC,EAAE,MAAM,IAAI,CAAC;CACjC;AA6CD,QAAA,MAAM,aAAa,GAAI,uIAYpB,kBAAkB,4CAsEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -22,9 +22,9 @@ const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip =
22
22
  : isMine
23
23
  ? "bg-chat-bubble-mine/10"
24
24
  : "bg-chat-bubble-neutral/10"));
25
- return (_jsxs("div", { className: "relative flex min-w-0 max-w-full items-end", "data-testid": "message-bubble", "data-cp-name": "MessageBubble", onClick: () => {
26
- if (timeLabel)
27
- onToggleTimeReveal === null || onToggleTimeReveal === void 0 ? void 0 : onToggleTimeReveal();
28
- }, children: [!isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), _jsx("div", { className: bubbleClass, id: id, children: _jsxs("div", { className: clsx("flex flex-col gap-1", !isTransparent && "px-1"), children: [showSenderName && senderName && (_jsx("span", { className: "text-[12px] font-medium leading-[160%] tracking-[0.12px] text-gray-400", children: senderName })), _jsx("div", { className: "flex flex-col gap-2", children: content })] }) }), isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), showTimeLabel && (_jsx("span", { "data-testid": "message-time-label", className: clsx("absolute -bottom-2 flex h-[19px] w-[30px] items-center justify-center rounded-full bg-white text-[10px] text-gray-400 shadow-sm", isMine ? "right-1" : "left-1"), children: timeLabel }))] }));
25
+ return (_jsxs("div", { className: "flex min-w-0 max-w-full flex-col gap-1", children: [showSenderName && senderName && (_jsx("span", { "data-testid": "message-sender-name", className: "px-1 text-[12px] font-medium leading-[160%] tracking-[0.12px] text-gray-400", children: senderName })), _jsxs("div", { className: "relative flex min-w-0 max-w-full items-end", "data-testid": "message-bubble", "data-cp-name": "MessageBubble", onClick: () => {
26
+ if (timeLabel)
27
+ onToggleTimeReveal === null || onToggleTimeReveal === void 0 ? void 0 : onToggleTimeReveal();
28
+ }, children: [!isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), _jsx("div", { className: bubbleClass, id: id, children: _jsx("div", { className: clsx("flex flex-col gap-2", !isTransparent && "px-1"), children: content }) }), isMine && showTail && (_jsx(MessageBubbleTail, { isMine: isMine, isInternal: isInternal })), showTimeLabel && (_jsx("span", { "data-testid": "message-time-label", className: clsx("absolute -bottom-2 flex h-[19px] w-[30px] items-center justify-center rounded-full bg-white text-[10px] text-gray-400 shadow-sm", isMine ? "right-1" : "left-1"), children: timeLabel }))] })] }));
29
29
  };
30
30
  export default MessageBubble;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AAyCtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AA2BD,QAAA,MAAM,WAAW,GAAI,uOAelB,gBAAgB,mDA4UlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/index.tsx"],"names":[],"mappings":"AAGA,OAAO,EACL,WAAW,IAAI,eAAe,EAG/B,MAAM,8BAA8B,CAAC;AAyCtC,UAAU,gBAAgB;IACxB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,eAAe,EAAE,CAAC;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,uBAAuB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAClD,eAAe,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAChD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,YAAY,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IAClD,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,2EAA2E;IAC3E,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,uEAAuE;IACvE,kBAAkB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAkCD,QAAA,MAAM,WAAW,GAAI,uOAelB,gBAAgB,mDA+UlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -25,9 +25,14 @@ import { isGroupNotificationMessageType, isSessionEventMessage, isSystemLogMessa
25
25
  import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, isPinnableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
26
26
  const MESSAGE_AVATAR_SIZE = 24;
27
27
  const DIVIDER_GAP_MINUTES = 30;
28
+ const DIVIDER_GAP_MS = DIVIDER_GAP_MINUTES * 60 * 1000;
28
29
  const GROUPING_GAP_MINUTES = 5;
29
30
  const GROUPING_GAP_MS = GROUPING_GAP_MINUTES * 60 * 1000;
30
31
  const isOrderMessage = (message) => { var _a; return ((_a = message === null || message === void 0 ? void 0 : message.customElem) === null || _a === void 0 ? void 0 : _a.extension) === CustomMessageType.Order; };
32
+ // Shared by showTimeBreak (day divider) and prevSameUser/nextSameUser (group
33
+ // break) so both features agree on the same calendar-day boundary — a group
34
+ // must never span a divider, regardless of how small the time gap is.
35
+ const isSameCalendarDay = (sendTimeA, sendTimeB) => dayjs(sendTimeA).isSame(sendTimeB, "day");
31
36
  const MessageAvatar = ({ avatarUrl, senderNickname, }) => {
32
37
  var _a;
33
38
  return (_jsx(Avatar, { size: MESSAGE_AVATAR_SIZE, src: avatarUrl, className: "shrink-0 self-end", "data-cp-name": "MessageAvatar", children: ((_a = senderNickname === null || senderNickname === void 0 ? void 0 : senderNickname.charAt) === null || _a === void 0 ? void 0 : _a.call(senderNickname, 0)) || "A" }));
@@ -154,6 +159,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
154
159
  !!previousMessage &&
155
160
  !isOrderMessage(previousMessage) &&
156
161
  previousMessage.sendID === (message === null || message === void 0 ? void 0 : message.sendID) &&
162
+ isSameCalendarDay(message.sendTime, previousMessage.sendTime) &&
157
163
  Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "millisecond")) <=
158
164
  GROUPING_GAP_MS;
159
165
  const nextSameUser = !isOrder &&
@@ -161,12 +167,12 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
161
167
  !!nextMessage &&
162
168
  !isOrderMessage(nextMessage) &&
163
169
  nextMessage.sendID === (message === null || message === void 0 ? void 0 : message.sendID) &&
170
+ isSameCalendarDay(nextMessage.sendTime, message.sendTime) &&
164
171
  Math.abs(dayjs(nextMessage.sendTime).diff(message.sendTime, "millisecond")) <=
165
172
  GROUPING_GAP_MS;
166
173
  const showTimeBreak = !previousMessage ||
167
- !dayjs(message.sendTime).isSame(previousMessage.sendTime, "days") ||
168
- Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "minute")) >
169
- DIVIDER_GAP_MINUTES;
174
+ !isSameCalendarDay(message.sendTime, previousMessage.sendTime) ||
175
+ Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "millisecond")) > DIVIDER_GAP_MS;
170
176
  const showPeerInfo = isGroupChat || showSenderInfo;
171
177
  const showAvatar = showPeerInfo && !isMine && !nextSameUser;
172
178
  const showSenderName = showPeerInfo && !isMine && !prevSameUser;
@@ -1 +1 @@
1
- {"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAStB,eAAO,MAAM,WAAW,0CAOtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,gFAM1B,iBAAiB,4CAwGnB,CAAC"}
1
+ {"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAStB,eAAO,MAAM,WAAW,0CAOtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,gFAM1B,iBAAiB,4CA0GnB,CAAC"}
@@ -73,6 +73,8 @@ export const ChatProvider = ({ children, config, renderCustomMessage, onNavigate
73
73
  wsAddress: config.wsAddr,
74
74
  applicationType: config.applicationType,
75
75
  isCrm: config.isCrm,
76
+ onTokenRefresh: config.onTokenRefresh,
77
+ onAuthError: config.onAuthError,
76
78
  });
77
79
  setUser({
78
80
  userID: config.userID,
@@ -72,7 +72,7 @@
72
72
  "profile_hint": "Nhấn để xem thông tin",
73
73
  "options_title": "Tuỳ chọn",
74
74
  "input_placeholder": "Nhập tin nhắn...",
75
- "view_only_notice": "Bạn không còn thành viên của nhóm này. Bạn chỉ có thể xem lại nội dung trò chuyện.",
75
+ "view_only_notice": "Bạn cần tham gia nhóm để gửi tin nhắn",
76
76
  "resolve_failed": "Không thể mở cuộc trò chuyện",
77
77
  "more_option": {
78
78
  "toggle": "Tùy chọn khác",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droppii-org/chat-sdk",
3
- "version": "0.4.11",
3
+ "version": "0.4.13",
4
4
  "description": "Droppii React Chat SDK",
5
5
  "repository": {
6
6
  "type": "git",