@droppii-org/chat-sdk 0.3.6 → 0.3.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. package/dist/components/common/ConfirmModal.d.ts +18 -0
  2. package/dist/components/common/ConfirmModal.d.ts.map +1 -0
  3. package/dist/components/common/ConfirmModal.js +15 -0
  4. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  5. package/dist/components/conversation/DeskConversationList.js +20 -14
  6. package/dist/components/message/GroupMembersDrawer.d.ts.map +1 -1
  7. package/dist/components/message/GroupMembersDrawer.js +5 -4
  8. package/dist/components/message/MessageList.d.ts.map +1 -1
  9. package/dist/components/message/MessageList.js +17 -3
  10. package/dist/components/message/item/MessageBubble.d.ts +3 -2
  11. package/dist/components/message/item/MessageBubble.d.ts.map +1 -1
  12. package/dist/components/message/item/MessageBubble.js +8 -2
  13. package/dist/components/message/item/index.d.ts.map +1 -1
  14. package/dist/components/message/item/index.js +21 -6
  15. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  16. package/dist/components/thread/GroupThreadInfo.js +43 -14
  17. package/dist/components/thread/SingleThreadInfo.d.ts.map +1 -1
  18. package/dist/components/thread/SingleThreadInfo.js +3 -2
  19. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  20. package/dist/hooks/global/useGlobalEvent.js +32 -3
  21. package/dist/hooks/session/useConversationSessionState.d.ts.map +1 -1
  22. package/dist/hooks/session/useConversationSessionState.js +1 -0
  23. package/dist/layout/index.d.ts.map +1 -1
  24. package/dist/layout/index.js +5 -0
  25. package/dist/locales/vi/common.json +11 -8
  26. package/dist/store/conversation.d.ts.map +1 -1
  27. package/dist/store/conversation.js +16 -4
  28. package/dist/styles/global.css +1 -1
  29. package/dist/utils/common.d.ts +1 -0
  30. package/dist/utils/common.d.ts.map +1 -1
  31. package/dist/utils/common.js +18 -0
  32. package/dist/utils/fileValidation.d.ts.map +1 -1
  33. package/dist/utils/fileValidation.js +1 -1
  34. package/package.json +1 -1
@@ -0,0 +1,18 @@
1
+ import type { ReactNode } from "react";
2
+ export interface ConfirmModalProps {
3
+ open: boolean;
4
+ title: ReactNode;
5
+ okText: ReactNode;
6
+ cancelText: ReactNode;
7
+ onOk: () => void;
8
+ onCancel: () => void;
9
+ okType?: "danger" | "primary";
10
+ confirmLoading?: boolean;
11
+ okButtonProps?: {
12
+ disabled?: boolean;
13
+ };
14
+ children: ReactNode;
15
+ }
16
+ declare const ConfirmModal: ({ open, title, okText, cancelText, onOk, onCancel, okType, confirmLoading, okButtonProps, children, }: ConfirmModalProps) => import("react/jsx-runtime").JSX.Element;
17
+ export default ConfirmModal;
18
+ //# sourceMappingURL=ConfirmModal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/common/ConfirmModal.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,SAAS,CAAC;IACjB,MAAM,EAAE,SAAS,CAAC;IAClB,UAAU,EAAE,SAAS,CAAC;IACtB,IAAI,EAAE,MAAM,IAAI,CAAC;IACjB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC9B,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,aAAa,CAAC,EAAE;QAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IACvC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,QAAA,MAAM,YAAY,GAAI,uGAWnB,iBAAiB,4CAiCnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -0,0 +1,15 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { Modal } from "antd";
4
+ const ConfirmModal = ({ open, title, okText, cancelText, onOk, onCancel, okType = "primary", confirmLoading, okButtonProps, children, }) => {
5
+ return (_jsx(Modal, { centered: true, open: open, onOk: onOk, onCancel: onCancel, okText: okText, cancelText: cancelText, confirmLoading: confirmLoading, okButtonProps: Object.assign(Object.assign({}, okButtonProps), { className: okType === "danger"
6
+ ? "!h-10 !rounded-lg !border-danger-400 !bg-danger-400 !text-white hover:!border-danger-300 hover:!bg-danger-300"
7
+ : "!h-10 !rounded-lg !border-primary-400 !bg-primary-400 !text-white hover:!border-primary-300 hover:!bg-primary-300" }), cancelButtonProps: {
8
+ className: "!h-10 !rounded-lg !border-gray-25 !bg-gray-25 !text-gray-900",
9
+ }, styles: {
10
+ header: { textAlign: "center", marginBottom: 0 },
11
+ footer: { marginTop: 16 },
12
+ body: { paddingTop: 4 },
13
+ }, classNames: { footer: "border-t border-gray-25 pt-4" }, title: _jsx("span", { className: "text-[18px] font-bold text-gray-900", children: title }), getContainer: false, forceRender: true, children: children }));
14
+ };
15
+ export default ConfirmModal;
@@ -1 +1 @@
1
- {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+CAgSzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA4BA,QAAA,MAAM,oBAAoB,+CAySzB,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -68,20 +68,26 @@ const DeskConversationList = () => {
68
68
  }, [showSearch]);
69
69
  useEffect(() => {
70
70
  const threadId = searchParams.get("threadId");
71
- if (threadId) {
72
- setSelectedConversationId(threadId);
73
- const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
74
- if (selectedConversation) {
75
- setConversationData(selectedConversation);
76
- }
77
- else {
78
- DChatSDK.getMultipleConversation([threadId]).then((res) => {
79
- if (res.data.length > 0) {
80
- setConversationData(res.data[0]);
81
- updateConversationList(res.data, "filter");
82
- }
83
- });
84
- }
71
+ if (!threadId) {
72
+ useConversationStore.getState().clearSelectedConversation();
73
+ return;
74
+ }
75
+ setSelectedConversationId(threadId);
76
+ const selectedConversation = conversationList.find((conv) => conv.conversationID === threadId);
77
+ if (selectedConversation) {
78
+ setConversationData(selectedConversation);
79
+ }
80
+ else {
81
+ DChatSDK.getMultipleConversation([threadId]).then((res) => {
82
+ // threadId can go stale between the fetch starting and resolving
83
+ // (e.g. the user was removed from that group mid-flight) — only
84
+ // apply the result if the URL still points at this conversation.
85
+ if (res.data.length > 0 &&
86
+ searchParams.get("threadId") === threadId) {
87
+ setConversationData(res.data[0]);
88
+ updateConversationList(res.data, "filter");
89
+ }
90
+ });
85
91
  }
86
92
  }, [searchParams, conversationList]);
87
93
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AASA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0CD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CAwjBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"GroupMembersDrawer.d.ts","sourceRoot":"","sources":["../../../src/components/message/GroupMembersDrawer.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAiB/C,UAAU,uBAAuB;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AA0CD,QAAA,MAAM,kBAAkB,GAAI,wDAKzB,uBAAuB,4CA4iBzB,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { GroupMemberRole } from "@droppii-org/wasm-client-sdk";
3
- import { Avatar, Button, Drawer, Dropdown, Empty, Input, message, Modal, Spin } from "antd";
3
+ import { Avatar, Button, Drawer, Dropdown, Empty, Input, message, Spin } from "antd";
4
+ import ConfirmModal from "../../components/common/ConfirmModal";
4
5
  import { useEffect, useMemo, useState } from "react";
5
6
  import { useDebounce } from "ahooks";
6
7
  import { useTranslation } from "react-i18next";
@@ -360,11 +361,11 @@ const GroupMembersDrawer = ({ groupID, conversationId, currentSession, disabled
360
361
  userID: adminPermissionMember.userID,
361
362
  permissions: adminPermissionMember.permissions,
362
363
  }
363
- : undefined, onMemberPermissionsSaved: patchMemberPermissions })), _jsx(Modal, { centered: true, open: showLeaveConfirm, onOk: handleConfirmLeave, onCancel: () => setShowLeaveConfirm(false), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, forceRender: true, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "remove", onOk: handleConfirmRemoveMember, onCancel: () => setConfirmMemberAction(null), title: t("remove_member_confirm_title"), okText: t("remove_from_group"), cancelText: t("cancel"), okType: "danger", getContainer: false, forceRender: true, children: _jsx("p", { children: t("remove_member_confirm_message", {
364
+ : undefined, onMemberPermissionsSaved: patchMemberPermissions })), _jsx(ConfirmModal, { open: showLeaveConfirm, onOk: handleConfirmLeave, onCancel: () => setShowLeaveConfirm(false), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "remove", onOk: handleConfirmRemoveMember, onCancel: () => setConfirmMemberAction(null), title: t("remove_member_confirm_title"), okText: t("remove_from_group"), cancelText: t("cancel"), okType: "danger", children: _jsx("p", { children: t("remove_member_confirm_message", {
364
365
  name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
365
- }) }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "transfer-owner", onOk: handleConfirmTransferOwner, onCancel: () => setConfirmMemberAction(null), title: t("transfer_owner_confirm_title"), okText: t("transfer_owner"), cancelText: t("cancel"), okType: "danger", getContainer: false, forceRender: true, children: _jsx("p", { children: t("transfer_owner_confirm_message", {
366
+ }) }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "transfer-owner", onOk: handleConfirmTransferOwner, onCancel: () => setConfirmMemberAction(null), title: t("transfer_owner_confirm_title"), okText: t("transfer_owner"), cancelText: t("cancel"), okType: "danger", children: _jsx("p", { children: t("transfer_owner_confirm_message", {
366
367
  name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
367
- }) }) }), _jsx(Modal, { centered: true, open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "assign-admin", onOk: handleConfirmAssignAdmin, onCancel: () => setConfirmMemberAction(null), title: t("assign_admin_confirm_title"), okText: t("agree"), cancelText: t("cancel"), getContainer: false, forceRender: true, children: _jsx("p", { children: t("assign_admin_confirm_message", {
368
+ }) }) }), _jsx(ConfirmModal, { open: (confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.type) === "assign-admin", onOk: handleConfirmAssignAdmin, onCancel: () => setConfirmMemberAction(null), title: t("assign_admin_confirm_title"), okText: t("agree"), cancelText: t("cancel"), children: _jsx("p", { children: t("assign_admin_confirm_message", {
368
369
  name: confirmMemberAction === null || confirmMemberAction === void 0 ? void 0 : confirmMemberAction.member.nickname,
369
370
  }) }) })] }));
370
371
  };
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AA8BA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAmR3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAgCA,UAAU,gBAAgB;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAgS3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -1,10 +1,11 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useMessage } from "../../hooks/message/useMessage";
4
- import { Button, Empty, Modal, Spin, message as toastMessage } from "antd";
4
+ import { Button, Empty, Spin, message as toastMessage } from "antd";
5
5
  import { useCallback, useEffect, useState } from "react";
6
6
  import dayjs from "dayjs";
7
7
  import isToday from "dayjs/plugin/isToday";
8
+ import { GroupMemberRole, GroupStatus } from "@droppii-org/wasm-client-sdk";
8
9
  import emitter from "../../utils/events";
9
10
  import MessageItem from "./item";
10
11
  import MessageInfiniteScroll from "./MessageInfiniteScroll";
@@ -24,6 +25,7 @@ import { useGroupPermission } from "../../hooks/group/useGroupPermission";
24
25
  import { isGroupSession } from "../../utils/imCommon";
25
26
  import { ConnectStatus, SessionStatus } from "../../types/chat";
26
27
  import PinLimitModal from "../../components/conversation-detail/PinLimitModal";
28
+ import ConfirmModal from "../../components/common/ConfirmModal";
27
29
  dayjs.extend(isToday);
28
30
  const MessageList = (props) => {
29
31
  const { t } = useTranslation();
@@ -32,7 +34,19 @@ const MessageList = (props) => {
32
34
  const conversationData = useConversationStore((state) => state.conversationData);
33
35
  const permissions = useGroupPermission(conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID);
34
36
  const isGroupChat = isGroupSession(conversationData === null || conversationData === void 0 ? void 0 : conversationData.conversationType);
35
- const canSendMessage = !isGroupChat || permissions.sendMessage;
37
+ const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
38
+ const currentMemberInGroup = useConversationStore((state) => state.currentMemberInGroup);
39
+ // Group/member data refetches async on conversation switch and can briefly
40
+ // hold the previous conversation's groupID or a not-yet-loaded roleLevel.
41
+ const isGroupStateFresh = !isGroupChat ||
42
+ ((currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupID) === (conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) &&
43
+ (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.groupID) === (conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID) &&
44
+ (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) !== undefined);
45
+ // Group-wide mute (GroupThreadInfo.tsx) restricts Normal members only.
46
+ const isRestrictedByGroupMute = isGroupChat &&
47
+ (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.status) === GroupStatus.Muted &&
48
+ (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Normal;
49
+ const canSendMessage = !isGroupChat || (permissions.sendMessage && !isRestrictedByGroupMute);
36
50
  const canPinMessage = !isGroupChat || permissions.pinMessage;
37
51
  const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
38
52
  const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
@@ -136,6 +150,6 @@ const MessageList = (props) => {
136
150
  if (!conversationData) {
137
151
  return (_jsx("div", { className: "flex flex-1 items-center justify-center h-full", children: connectStatus !== ConnectStatus.Connected ? (_jsx(Spin, {})) : (_jsx(Empty, { description: t("no_conversation_data") })) }));
138
152
  }
139
- return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t("send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(Modal, { centered: true, open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, getContainer: false, forceRender: true, children: _jsx("p", { children: t("revoke_message_confirm_message") }) }), _jsx(PinLimitModal, { open: pinLimitModalOpen, max: pinnedTotalCount, onClose: () => setPinLimitModalOpen(false) })] }));
153
+ return (_jsxs("div", { className: "flex flex-col flex-1 relative h-full min-w-0 bg-white", style: { overflowX: "hidden" }, children: [_jsx(MessageHeader, { onClose: onClose, currentSession: latestConversationSession, isJoined: isJoined, onOpenThreadInfo: onOpenThreadInfo }), _jsx(MessageInfiniteScroll, { scrollRef: scrollRef, scrollableTargetId: "scrollableMessagesDiv", loadState: loadState, moreOldLoading: moreOldLoading, onLoadMoreOld: loadMoreOldMessage, onScroll: handleInfiniteScroll, children: loadState.messageList.map((message, _, array) => (_jsx(MessageItem, { message: message, allMessages: array, contextMenuOpen: openMenuId === message.clientMsgID, onContextMenuOpenChange: (open) => setOpenMenuId(open ? message.clientMsgID : null), onRevokeMessage: handleOpenRevoke, onQuoteMessage: setQuotedMessage, onPressQuoteMessage: onPressQuoteMessage, onPinMessage: canPinMessage ? handlePinMessage : undefined, onUnpinMessage: canPinMessage ? handleUnpinMessage : undefined }, message.clientMsgID))) }), moreNewLoading && (_jsx("div", { className: "flex items-center justify-center py-2", children: _jsx(Spin, {}) })), isCheckingMembership || !isGroupStateFresh ? (_jsx("div", { className: "border-t bg-white py-4 flex items-center justify-center", children: _jsx(Spin, {}) })) : (latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.status) === SessionStatus.UNASSIGNED ? (_jsx(UnassignedSessionFooter, { sessionId: latestConversationSession.id, teamId: latestConversationSession.teamId })) : shouldRestrictToLastSession ? (_jsxs("div", { className: "border-t bg-white py-4 flex flex-col items-center gap-2", children: [_jsx("p", { className: "text-sm text-gray-500", children: t("join_group_required") }), _jsx(Button, { type: "primary", onClick: joinGroup, loading: isJoining, children: t("join_group") })] })) : !canSendMessage ? (_jsx("div", { className: "border-t bg-[#f5f5f5] py-3 flex items-center justify-center", children: _jsx("p", { className: "text-sm text-gray-500", children: t(isRestrictedByGroupMute ? "send_message_disabled_group_mute" : "send_message_disabled") }) })) : (_jsx(MessageFooter, { currentSession: latestConversationSession, openCreateCannedModal: openCreateCannedModal })), _jsx(ConfirmModal, { open: showConfirmRevoke, onOk: onRevokeMessage, onCancel: handleCloseRevoke, title: t("revoke_message_confirm_title"), okText: t("revoke"), cancelText: t("cancel"), okType: "danger", confirmLoading: isRevoking, children: _jsx("p", { children: t("revoke_message_confirm_message") }) }), _jsx(PinLimitModal, { open: pinLimitModalOpen, max: pinnedTotalCount, onClose: () => setPinLimitModalOpen(false) })] }));
140
154
  };
141
155
  export default MessageList;
@@ -1,4 +1,4 @@
1
- import type { ReactNode } from "react";
1
+ import { type ReactNode } from "react";
2
2
  export interface MessageBubbleProps {
3
3
  isMine: boolean;
4
4
  content: ReactNode;
@@ -8,7 +8,8 @@ export interface MessageBubbleProps {
8
8
  isInternal?: boolean;
9
9
  id?: string;
10
10
  isTransparent?: boolean;
11
+ timeLabel?: string;
11
12
  }
12
- declare const MessageBubble: ({ isMine, content, senderName, showSenderName, showTip, isInternal, id, isTransparent, }: MessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
13
+ declare const MessageBubble: ({ isMine, content, senderName, showSenderName, showTip, isInternal, id, isTransparent, timeLabel, }: MessageBubbleProps) => import("react/jsx-runtime").JSX.Element;
13
14
  export default MessageBubble;
14
15
  //# sourceMappingURL=MessageBubble.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,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;CACzB;AA4CD,QAAA,MAAM,aAAa,GAAI,0FASpB,kBAAkB,4CA6CpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"MessageBubble.d.ts","sourceRoot":"","sources":["../../../../src/components/message/item/MessageBubble.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjD,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;CACpB;AA4CD,QAAA,MAAM,aAAa,GAAI,qGAUpB,kBAAkB,4CAiEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -1,6 +1,7 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import clsx from "clsx";
4
+ import { useState } from "react";
4
5
  const INCOMING_TAIL_PATH = "M1.3798 18H4V0C3.51762 4.5 3.34269 10.5 0.966518 14C-0.568384 16.2608 -0.159364 18 1.3798 18Z";
5
6
  const OUTGOING_TAIL_PATH = "M2.6202 18H0V0C0.482375 4.5 0.657308 10.5 3.03348 14C4.56838 16.2608 4.15936 18 2.6202 18Z";
6
7
  const MessageBubbleTail = ({ isMine, isInternal, }) => (_jsx("div", { className: clsx("flex shrink-0 items-center justify-center", isInternal
@@ -8,8 +9,10 @@ const MessageBubbleTail = ({ isMine, isInternal, }) => (_jsx("div", { className:
8
9
  : isMine
9
10
  ? "text-chat-bubble-mine"
10
11
  : "text-chat-bubble-neutral"), children: _jsx("div", { className: "flex-none", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", width: "4", height: "18", viewBox: "0 0 4 18", fill: "none", "aria-hidden": true, children: _jsx("path", { d: isMine ? OUTGOING_TAIL_PATH : INCOMING_TAIL_PATH, fill: "currentColor", fillOpacity: "0.1" }) }) }) }));
11
- const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, isInternal = false, id, isTransparent = false, }) => {
12
+ const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip = true, isInternal = false, id, isTransparent = false, timeLabel, }) => {
12
13
  const showTail = showTip && !isTransparent;
14
+ const [timeRevealed, setTimeRevealed] = useState(false);
15
+ const showTimeLabel = Boolean(timeLabel) && (showTip || timeRevealed);
13
16
  const bubbleClass = clsx("relative max-w-full", isTransparent
14
17
  ? "bg-transparent p-0"
15
18
  : clsx("p-2", showTip
@@ -21,6 +24,9 @@ const MessageBubble = ({ isMine, content, senderName, showSenderName, showTip =
21
24
  : isMine
22
25
  ? "bg-chat-bubble-mine/10"
23
26
  : "bg-chat-bubble-neutral/10"));
24
- return (_jsxs("div", { className: "relative flex items-end", "data-testid": "message-bubble", 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 }))] }));
27
+ return (_jsxs("div", { className: "relative flex items-end", "data-testid": "message-bubble", onClick: () => {
28
+ if (!showTip && timeLabel)
29
+ setTimeRevealed((prev) => !prev);
30
+ }, 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
31
  };
26
32
  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;AAkCtC,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;CAC3B;AAoBD,QAAA,MAAM,WAAW,GAAI,qMAalB,gBAAgB,mDA8RlB,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;AAmCtC,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;CAC3B;AAyBD,QAAA,MAAM,WAAW,GAAI,qMAalB,gBAAgB,mDA6SlB,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -8,7 +8,8 @@ import MessageBubble from "./MessageBubble";
8
8
  import { renderBubbleContent } from "./renderMessageContent";
9
9
  import { getVisibleNeighbor, isMessageHiddenForViewer, } from "../../../hooks/message/useMessage";
10
10
  import { MSG_ITEM_CONTENT_PREFIX, MSG_ITEM_PREFIX } from "../../../constants";
11
- import { formatTimestamp } from "../../../utils/common";
11
+ import { formatDividerTimestamp } from "../../../utils/common";
12
+ import { CustomMessageType } from "../../../types/customMessage";
12
13
  import useAuthStore from "../../../store/auth";
13
14
  import useConversationStore from "../../../store/conversation";
14
15
  import { useMemo, useRef } from "react";
@@ -22,6 +23,9 @@ import GroupNotificationMessageItem from "./GroupNotificationMessage";
22
23
  import { isGroupNotificationMessageType, isSystemLogMessageType } from "../../../utils/messageLog";
23
24
  import { buildMessageToolboxMenuItems, getCopyableMessageText, isCopyableMessageType, isPinnableMessageType, MessageToolboxActionKey, MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, useMessageToolboxVisibility, } from "../../../components/message/toolbox";
24
25
  const MESSAGE_AVATAR_SIZE = 24;
26
+ const DIVIDER_GAP_MINUTES = 30;
27
+ const GROUPING_GAP_MINUTES = 5;
28
+ 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; };
25
29
  const MessageAvatar = ({ avatarUrl, senderNickname, }) => {
26
30
  var _a;
27
31
  return (_jsx(Avatar, { size: MESSAGE_AVATAR_SIZE, src: avatarUrl, className: "shrink-0 self-end", children: ((_a = senderNickname === null || senderNickname === void 0 ? void 0 : senderNickname.charAt) === null || _a === void 0 ? void 0 : _a.call(senderNickname, 0)) || "A" }));
@@ -127,10 +131,21 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
127
131
  message.clientMsgID;
128
132
  const previousMessage = getVisibleNeighbor(allMessages, message, "prev");
129
133
  const nextMessage = getVisibleNeighbor(allMessages, message, "next");
130
- const prevSameUser = (previousMessage === null || previousMessage === void 0 ? void 0 : previousMessage.sendID) === (message === null || message === void 0 ? void 0 : message.sendID);
131
- const nextSameUser = (nextMessage === null || nextMessage === void 0 ? void 0 : nextMessage.sendID) === (message === null || message === void 0 ? void 0 : message.sendID);
134
+ const isOrder = isOrderMessage(message);
135
+ const prevSameUser = !isOrder &&
136
+ !isOrderMessage(previousMessage) &&
137
+ (previousMessage === null || previousMessage === void 0 ? void 0 : previousMessage.sendID) === (message === null || message === void 0 ? void 0 : message.sendID) &&
138
+ Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "minute")) <=
139
+ GROUPING_GAP_MINUTES;
140
+ const nextSameUser = !isOrder &&
141
+ !isOrderMessage(nextMessage) &&
142
+ (nextMessage === null || nextMessage === void 0 ? void 0 : nextMessage.sendID) === (message === null || message === void 0 ? void 0 : message.sendID) &&
143
+ Math.abs(dayjs(nextMessage.sendTime).diff(message.sendTime, "minute")) <=
144
+ GROUPING_GAP_MINUTES;
132
145
  const showTimeBreak = !previousMessage ||
133
- !dayjs(message.sendTime).isSame(previousMessage.sendTime, "days");
146
+ !dayjs(message.sendTime).isSame(previousMessage.sendTime, "days") ||
147
+ Math.abs(dayjs(message.sendTime).diff(previousMessage.sendTime, "minute")) >
148
+ DIVIDER_GAP_MINUTES;
134
149
  const showPeerInfo = isGroupChat || showSenderInfo;
135
150
  const showAvatar = showPeerInfo && !isMine && !nextSameUser;
136
151
  const showSenderName = showPeerInfo && !isMine && !prevSameUser;
@@ -142,7 +157,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
142
157
  className: "flex flex-col gap-2 py-1 px-3 sm:px-4 min-w-0",
143
158
  id: `${MSG_ITEM_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`,
144
159
  };
145
- const timeBreakNode = showTimeBreak ? (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "rounded-full bg-neutral-100 px-2 py-1 text-center text-xs text-gray-600", children: formatTimestamp(message.sendTime, { hasTime: true }) }) })) : null;
160
+ const timeBreakNode = showTimeBreak ? (_jsx("div", { className: "flex justify-center", children: _jsx("span", { className: "rounded-full bg-neutral-100 px-2 py-1 text-center text-xs text-gray-600", children: formatDividerTimestamp(message.sendTime) }) })) : null;
146
161
  if (isSystemLogMessage) {
147
162
  return (_createElement("div", Object.assign({}, messageContainerProps, { key: message === null || message === void 0 ? void 0 : message.clientMsgID }),
148
163
  timeBreakNode,
@@ -153,7 +168,7 @@ const MessageItem = ({ message, allMessages, isGroupChat = false, forceHideTip =
153
168
  timeBreakNode,
154
169
  _jsx(GroupNotificationMessageItem, { message: message })));
155
170
  }
156
- const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: renderBubbleContent(message, onPressQuoteMessage), isTransparent: isStickerMessage }));
171
+ const bubbleNode = (_jsx(MessageBubble, { isMine: isMine, isInternal: isInternalMessage, senderName: message === null || message === void 0 ? void 0 : message.senderNickname, showSenderName: showSenderName, showTip: showTip, id: `${MSG_ITEM_CONTENT_PREFIX}${message === null || message === void 0 ? void 0 : message.clientMsgID}`, content: renderBubbleContent(message, onPressQuoteMessage), isTransparent: isStickerMessage, timeLabel: dayjs.tz(message.sendTime).format("HH:mm") }));
157
172
  const showPinnedBadge = Boolean(message === null || message === void 0 ? void 0 : message.isPinned);
158
173
  const pinnedBadgeNode = showPinnedBadge ? (_jsx("span", { "data-testid": "message-pinned-badge", className: clsx("absolute -top-2.5 z-[1] flex h-[22px] w-[26px] items-center justify-center rounded-full border border-white bg-gray-25", isMine ? "left-0" : "right-0"), children: _jsx(Icon, { icon: "thumbtack-b", size: 12, className: "text-primary-400" }) })) : null;
159
174
  const wrappedBubble = hasContextMenu ? (_jsx(Dropdown, { menu: { items: contextMenuItems }, trigger: ["contextMenu"], open: contextMenuOpen, onOpenChange: onContextMenuOpenChange, overlayClassName: MESSAGE_TOOLBOX_OVERLAY_CLASSNAME, children: _jsxs("div", { ref: bubbleWrapperRef, className: "relative min-w-0", children: [bubbleNode, pinnedBadgeNode] }) })) : (_jsxs("div", { className: "relative min-w-0", children: [bubbleNode, pinnedBadgeNode] }));
@@ -1 +1 @@
1
- {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AAmBA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAID,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDAigBjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"GroupThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupThreadInfo.tsx"],"names":[],"mappings":"AAoBA,MAAM,WAAW,qBAAqB;IACpC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,UAAU,oBAAoB;IAC5B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,MAAM,CAAC,EAAE,qBAAqB,CAAC;CAChC;AAID,QAAA,MAAM,eAAe,GAAI,qBAAqB,oBAAoB,mDAyjBjE,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useEffect, useRef, useState } from "react";
3
3
  import { Input, Modal, Switch, message } from "antd";
4
+ import ConfirmModal from "../../components/common/ConfirmModal";
4
5
  import { useTranslation } from "react-i18next";
5
6
  import { GroupMemberRole, GroupStatus, MessageReceiveOptType } from "@droppii-org/wasm-client-sdk";
6
7
  import { Icon } from "../../components/icon";
@@ -13,12 +14,12 @@ import { useToggleGroupSendMessage } from "../../hooks/group/useToggleGroupSendM
13
14
  import { useDismissGroup } from "../../hooks/group/useDismissGroup";
14
15
  import { useGroupPermission } from "../../hooks/group/useGroupPermission";
15
16
  import { useUploadFile } from "../../hooks/common/useUploadFile";
16
- import { validateFile } from "../../utils/fileValidation";
17
+ import { ACCEPTED_IMAGE_TYPES, MAX_IMAGE_SIZE_MB } from "../../utils/fileValidation";
17
18
  import AdminPermissionModal from "../../components/group/AdminPermissionModal";
18
19
  import MemberPermissionPanel from "../../components/group/MemberPermissionPanel";
19
20
  import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
20
21
  const GroupThreadInfo = ({ onClose, config }) => {
21
- var _a, _b, _c;
22
+ var _a, _b, _c, _d;
22
23
  const { t } = useTranslation();
23
24
  const conversationData = useConversationStore((state) => state.conversationData);
24
25
  const currentGroupInfo = useConversationStore((state) => state.currentGroupInfo);
@@ -31,6 +32,10 @@ const GroupThreadInfo = ({ onClose, config }) => {
31
32
  // per-permission.
32
33
  const isAdminOrOwner = (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Admin ||
33
34
  (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Owner;
35
+ // "Cho phép gửi tin nhắn" (group-wide mute) is owner-only per BR-001 —
36
+ // unlike other admin-manageable rows in this panel, admins may view but
37
+ // not change this toggle.
38
+ const isOwner = (currentMemberInGroup === null || currentMemberInGroup === void 0 ? void 0 : currentMemberInGroup.roleLevel) === GroupMemberRole.Owner;
34
39
  const [editingField, setEditingField] = useState(null);
35
40
  const [nameValue, setNameValue] = useState((_a = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) !== null && _a !== void 0 ? _a : "");
36
41
  const [descriptionValue, setDescriptionValue] = useState((_b = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _b !== void 0 ? _b : "");
@@ -48,7 +53,7 @@ const GroupThreadInfo = ({ onClose, config }) => {
48
53
  useEffect(() => {
49
54
  setAllowSendMessage((currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.status) !== GroupStatus.Muted);
50
55
  }, [currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.status]);
51
- const { mutate: updateGroupInfo } = useUpdateGroupInfo();
56
+ const { mutate: updateGroupInfo, isPending: isSavingGroupInfo } = useUpdateGroupInfo();
52
57
  const { mutate: uploadFile, isPending: isAvatarUploading } = useUploadFile();
53
58
  const { mutate: toggleSendMessage, isPending: isTogglingSendMessage } = useToggleGroupSendMessage();
54
59
  const { mutate: toggleNotification, isPending: isTogglingNotification } = useToggleConversationNotification();
@@ -65,12 +70,23 @@ const GroupThreadInfo = ({ onClose, config }) => {
65
70
  setDescriptionValue((_a = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _a !== void 0 ? _a : "");
66
71
  setEditingField("description");
67
72
  };
73
+ const cancelEditName = () => {
74
+ var _a;
75
+ setNameValue((_a = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) !== null && _a !== void 0 ? _a : "");
76
+ setEditingField(null);
77
+ };
68
78
  const saveName = () => {
79
+ if (isSavingGroupInfo)
80
+ return;
69
81
  const trimmed = nameValue.trim();
70
- setEditingField(null);
71
- if (!groupID || !trimmed || trimmed === (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName))
82
+ if (!groupID || !trimmed || trimmed === (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName)) {
83
+ setEditingField(null);
72
84
  return;
73
- updateGroupInfo({ groupID, groupName: trimmed }, { onError: () => message.error(t("update_group_info_failed")) });
85
+ }
86
+ updateGroupInfo({ groupID, groupName: trimmed }, {
87
+ onSuccess: () => setEditingField(null),
88
+ onError: () => message.error(t("update_group_info_failed")),
89
+ });
74
90
  };
75
91
  const cancelEditDescription = () => {
76
92
  var _a;
@@ -78,11 +94,17 @@ const GroupThreadInfo = ({ onClose, config }) => {
78
94
  setEditingField(null);
79
95
  };
80
96
  const saveDescription = () => {
97
+ if (isSavingGroupInfo)
98
+ return;
81
99
  const trimmed = descriptionValue.trim();
82
- setEditingField(null);
83
- if (!groupID || trimmed === (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction))
100
+ if (!groupID || trimmed === (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction)) {
101
+ setEditingField(null);
84
102
  return;
85
- updateGroupInfo({ groupID, introduction: trimmed }, { onError: () => message.error(t("update_group_info_failed")) });
103
+ }
104
+ updateGroupInfo({ groupID, introduction: trimmed }, {
105
+ onSuccess: () => setEditingField(null),
106
+ onError: () => message.error(t("update_group_info_failed")),
107
+ });
86
108
  };
87
109
  const handleAvatarClick = () => {
88
110
  var _a;
@@ -96,9 +118,13 @@ const GroupThreadInfo = ({ onClose, config }) => {
96
118
  event.target.value = "";
97
119
  if (!file || !groupID)
98
120
  return;
99
- const validation = validateFile(file, t);
100
- if (!validation.isValid) {
101
- message.error(validation.error);
121
+ if (!ACCEPTED_IMAGE_TYPES.includes(file.type)) {
122
+ message.error(t("avatar_invalid_format"));
123
+ return;
124
+ }
125
+ const fileSizeMB = file.size / 1024 / 1024;
126
+ if (fileSizeMB > MAX_IMAGE_SIZE_MB) {
127
+ message.error(t("avatar_size_exceeded", { maxSize: MAX_IMAGE_SIZE_MB }));
102
128
  return;
103
129
  }
104
130
  uploadFile(file, {
@@ -125,7 +151,7 @@ const GroupThreadInfo = ({ onClose, config }) => {
125
151
  toggleNotification({ conversationID, notify: checked });
126
152
  };
127
153
  const handleToggleSendMessage = (checked) => {
128
- if (!groupID)
154
+ if (!groupID || !isOwner)
129
155
  return;
130
156
  const previous = allowSendMessage;
131
157
  setAllowSendMessage(checked);
@@ -187,6 +213,9 @@ const GroupThreadInfo = ({ onClose, config }) => {
187
213
  if (!groupID) {
188
214
  return null;
189
215
  }
190
- return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(GroupCompositeAvatar, { groupID: groupID, faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName, size: 56 }), isAvatarUploading && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), permissions.updateGroupAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: avatarInputRef, type: "file", accept: "image/jpeg, image/png, image/jpg", className: "hidden", onChange: handleAvatarSelect }), _jsx("button", { type: "button", disabled: isAvatarUploading, onClick: handleAvatarClick, className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField === "name" ? (_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), onPressEnter: saveName, onBlur: saveName, maxLength: 100 })) : (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), _jsx("div", { className: "px-4 pb-4", children: editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-gray-900", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "text-gray-500" }), t("description")] }), _jsx(Input.TextArea, { autoFocus: true, value: descriptionValue, onChange: (event) => setDescriptionValue(event.target.value), placeholder: t("enter_group_description"), autoSize: { minRows: 1, maxRows: 4 }, maxLength: 500, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full border border-primary-500 text-primary-500 text-sm font-medium", onClick: cancelEditDescription, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-full text-primary-500 text-sm font-medium disabled:text-gray-300", disabled: descriptionValue.trim() === ((_c = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _c !== void 0 ? _c : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), _jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center gap-3 px-3 py-3 text-left text-sm text-gray-400 cursor-not-allowed", disabled: true, title: t("invite_via_link_pending"), children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }), _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] }), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] }), _jsx(Modal, { centered: true, open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, getContainer: false, forceRender: true, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDismissing, getContainer: false, forceRender: true, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(Modal, { centered: true, open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, forceRender: true, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(MemberPermissionPanel, { open: activeRow === "member-permission", groupID: groupID, onClose: () => setActiveRow(null) }), _jsx(AdminPermissionModal, { open: activeRow === "admin-permission", groupID: groupID, onClose: () => setActiveRow(null), inline: true }), (activeRow === "muted-chat-list" || activeRow === "block-list") && (_jsx(Modal, { centered: true, open: true, footer: null, onCancel: () => setActiveRow(null), title: t(activeRow === "muted-chat-list" ? "muted_chat_list" : "block_list"), getContainer: false, forceRender: true, children: _jsx("p", { className: "text-sm text-gray-500", children: t("feature_coming_soon") }) }))] }));
216
+ return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsxs("div", { className: "relative shrink-0", children: [_jsx(GroupCompositeAvatar, { groupID: groupID, faceURL: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.faceURL, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName, size: 56 }), isAvatarUploading && (_jsx("span", { className: "absolute inset-0 flex items-center justify-center rounded-full bg-black/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), permissions.updateGroupAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: handleAvatarSelect }), _jsx("button", { type: "button", disabled: isAvatarUploading, onClick: handleAvatarClick, className: "absolute -bottom-1 -right-1 flex items-center justify-center w-5 h-5 rounded-full bg-black text-white", children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsx("div", { className: "flex-1 min-w-0", children: editingField !== "name" && (_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("p", { className: "text-base font-medium truncate", children: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName }), permissions.updateGroupName && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditName }))] })) })] }), editingField === "name" && (_jsx("div", { className: "px-4 pb-4", children: _jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsx(Input, { autoFocus: true, value: nameValue, onChange: (event) => setNameValue(event.target.value), maxLength: 255, showCount: true, disabled: isSavingGroupInfo, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg border border-primary-500 text-primary-500 text-sm font-medium disabled:border-gray-200 disabled:text-gray-300", disabled: isSavingGroupInfo, onClick: cancelEditName, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg bg-primary-500 text-white text-sm font-medium disabled:bg-gray-100 disabled:text-gray-300", disabled: isSavingGroupInfo ||
217
+ !nameValue.trim() ||
218
+ nameValue.trim() === ((_c = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.groupName) !== null && _c !== void 0 ? _c : ""), onClick: saveName, children: t("save") })] })] }) })), _jsx("div", { className: "px-4 pb-4", children: editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-3 bg-[#f5f5f5] rounded-lg p-3", children: [_jsxs("span", { className: "flex items-center gap-2 text-sm font-medium text-gray-900", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "text-gray-500" }), t("description")] }), _jsx(Input.TextArea, { autoFocus: true, value: descriptionValue, onChange: (event) => setDescriptionValue(event.target.value), placeholder: t("enter_group_description"), autoSize: { minRows: 1, maxRows: 4 }, maxLength: 500, showCount: true, disabled: isSavingGroupInfo, className: "bg-white" }), _jsxs("div", { className: "flex items-center justify-end gap-2", children: [_jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg border border-primary-500 text-primary-500 text-sm font-medium disabled:border-gray-200 disabled:text-gray-300", disabled: isSavingGroupInfo, onClick: cancelEditDescription, children: t("cancel") }), _jsx("button", { type: "button", className: "px-4 py-1.5 rounded-lg bg-primary-500 text-white text-sm font-medium disabled:bg-gray-100 disabled:text-gray-300", disabled: isSavingGroupInfo ||
219
+ descriptionValue.trim() === ((_d = currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) !== null && _d !== void 0 ? _d : ""), onClick: saveDescription, children: t("save") })] })] })) : (_jsxs("div", { className: "flex items-start justify-between gap-2 bg-[#f5f5f5] rounded-lg px-3 py-2.5", children: [_jsxs("div", { className: "flex items-start gap-2 flex-1 min-w-0", children: [_jsx(Icon, { icon: "info-circle-o", size: 18, className: "shrink-0 mt-0.5 text-gray-900" }), _jsxs("div", { className: "flex flex-col gap-0.5 min-w-0", children: [_jsx("span", { className: "text-sm font-semibold text-gray-900", children: t("description") }), _jsx("p", { className: "text-sm text-gray-400 truncate", children: (currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.introduction) || t("no_description") })] })] }), permissions.updateGroupDescription && (_jsx(Icon, { icon: "edit-o", size: 16, className: "shrink-0 cursor-pointer text-gray-500", onClick: startEditDescription }))] })) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: [_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }), (config === null || config === void 0 ? void 0 : config.showAllowSendMessage) && isOwner && (_jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-check-o", size: 18 }), t("allow_send_message")] }), _jsx(Switch, { checked: allowSendMessage, onChange: handleToggleSendMessage, loading: isTogglingSendMessage })] })), isAdminOrOwner && (config === null || config === void 0 ? void 0 : config.showMutedChatList) && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("muted-chat-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-off-o", size: 18 }), t("muted_chat_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("block-list"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("block_list")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }))] }), permissions.configGroupPermission && (_jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: [_jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("member-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-o", size: 18 }), t("member_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] }), _jsxs("button", { type: "button", className: "flex items-center justify-between px-3 py-3 text-left", onClick: () => setActiveRow("admin-permission"), children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "shield-done-o", size: 18 }), t("admin_permission_settings")] }), _jsx(Icon, { icon: "angle-right-o", size: 16, className: "text-gray-400" })] })] })), _jsx("div", { className: "mx-4 mt-3 rounded-lg overflow-hidden bg-[#f5f5f5]", children: _jsxs("button", { type: "button", className: "w-full flex items-center gap-3 px-3 py-3 text-left text-sm text-gray-400 cursor-not-allowed", disabled: true, title: t("invite_via_link_pending"), children: [_jsx(Icon, { icon: "link-alt-o", size: 18 }), t("invite_via_link")] }) }), _jsxs("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 mb-4 rounded-lg overflow-hidden", children: [isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("delete"), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] })), _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("leave"), children: [_jsx(Icon, { icon: "logout-o", size: 18 }), t("leave_group")] }), isAdminOrOwner && (_jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmAction("disband"), children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t("disband_group")] }))] })] }), _jsx(ConfirmModal, { open: confirmAction === "leave", onOk: handleConfirmLeave, onCancel: () => setConfirmAction(null), title: t("leave_group_confirm_title"), okText: t("leave_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isLeaving, children: _jsx("p", { children: t("leave_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "disband", onOk: handleConfirmDisband, onCancel: () => setConfirmAction(null), title: t("disband_group_confirm_title"), okText: t("disband_group"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDismissing, children: _jsx("p", { children: t("disband_group_confirm_message") }) }), _jsx(ConfirmModal, { open: confirmAction === "delete", onOk: handleConfirmDelete, onCancel: () => setConfirmAction(null), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) }), _jsx(MemberPermissionPanel, { open: activeRow === "member-permission", groupID: groupID, onClose: () => setActiveRow(null) }), _jsx(AdminPermissionModal, { open: activeRow === "admin-permission", groupID: groupID, onClose: () => setActiveRow(null), inline: true }), (activeRow === "muted-chat-list" || activeRow === "block-list") && (_jsx(Modal, { centered: true, open: true, footer: null, onCancel: () => setActiveRow(null), title: t(activeRow === "muted-chat-list" ? "muted_chat_list" : "block_list"), getContainer: false, forceRender: true, children: _jsx("p", { className: "text-sm text-gray-500", children: t("feature_coming_soon") }) }))] }));
191
220
  };
192
221
  export default GroupThreadInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"SingleThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SingleThreadInfo.tsx"],"names":[],"mappings":"AAYA,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,aAAa,qBAAqB,mDAoJ3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"SingleThreadInfo.d.ts","sourceRoot":"","sources":["../../../src/components/thread/SingleThreadInfo.tsx"],"names":[],"mappings":"AAaA,UAAU,qBAAqB;IAC7B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,gBAAgB,GAAI,aAAa,qBAAqB,mDAiJ3D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useState } from "react";
3
- import { Avatar, Modal, Switch, message } from "antd";
3
+ import { Avatar, Switch, message } from "antd";
4
+ import ConfirmModal from "../../components/common/ConfirmModal";
4
5
  import { useTranslation } from "react-i18next";
5
6
  import { MessageReceiveOptType } from "@droppii-org/wasm-client-sdk";
6
7
  import { Icon } from "../../components/icon";
@@ -65,6 +66,6 @@ const SingleThreadInfo = ({ onClose }) => {
65
66
  if (!conversationID) {
66
67
  return null;
67
68
  }
68
- return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsx(Avatar, { src: avatar, size: 56, className: "shrink-0", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [_jsx("p", { className: "text-base font-medium truncate", children: displayName }), isBot && (_jsx("span", { className: "shrink-0 rounded px-1.5 py-0.5 text-xs font-semibold bg-orange-50 text-orange-500", children: t("bot_tag") }))] })] }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: _jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }) }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm w-full", onClick: handleToggleBlock, disabled: isTogglingBlock, children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t(isBlocked ? "unblock_user" : "block_user")] }) }), _jsx("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmDelete(true), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }) })] }), _jsx(Modal, { centered: true, open: confirmDelete, onOk: handleConfirmDelete, onCancel: () => setConfirmDelete(false), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, getContainer: false, forceRender: true, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) })] }));
69
+ return (_jsxs("div", { className: "h-full w-[330px] bg-white shadow-md flex flex-col relative", children: [_jsxs("div", { className: "flex items-center justify-between px-4 py-4 border-b border-gray-100", children: [_jsx("span", { className: "text-lg font-medium", children: t("thread_info_title") }), _jsx("button", { type: "button", className: "flex items-center justify-center w-8 h-8 rounded-full text-gray-500 hover:bg-gray-100", onClick: onClose, children: _jsx(Icon, { icon: "close-o", size: 20 }) })] }), _jsxs("div", { className: "flex-1 overflow-y-auto", children: [_jsxs("div", { className: "flex items-center gap-3 px-4 py-4", children: [_jsx(Avatar, { src: avatar, size: 56, className: "shrink-0", children: ((_a = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _a === void 0 ? void 0 : _a.call(displayName, 0)) || "A" }), _jsxs("div", { className: "flex-1 min-w-0 flex items-center gap-2", children: [_jsx("p", { className: "text-base font-medium truncate", children: displayName }), isBot && (_jsx("span", { className: "shrink-0 rounded px-1.5 py-0.5 text-xs font-semibold bg-orange-50 text-orange-500", children: t("bot_tag") }))] })] }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 rounded-lg overflow-hidden", children: _jsxs("div", { className: "flex items-center justify-between px-3 py-3", children: [_jsxs("span", { className: "flex items-center gap-3 text-sm", children: [_jsx(Icon, { icon: "bell-o", size: 18 }), t("notification")] }), _jsx(Switch, { checked: notifyEnabled, onChange: handleToggleNotification, loading: isTogglingNotification })] }) }), _jsx("div", { className: "bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm w-full", onClick: handleToggleBlock, disabled: isTogglingBlock, children: [_jsx(Icon, { icon: "user-del-o", size: 18 }), t(isBlocked ? "unblock_user" : "block_user")] }) }), _jsx("div", { className: "flex flex-col gap-1 bg-[#f5f5f5] mx-4 mt-3 rounded-lg overflow-hidden", children: _jsxs("button", { type: "button", className: "flex items-center gap-3 px-3 py-3 text-left text-sm text-red-500", onClick: () => setConfirmDelete(true), children: [_jsx(Icon, { icon: "trash-o", size: 18 }), t("delete_conversation")] }) })] }), _jsx(ConfirmModal, { open: confirmDelete, onOk: handleConfirmDelete, onCancel: () => setConfirmDelete(false), title: t("delete_conversation_confirm_title"), okText: t("delete_conversation"), cancelText: t("cancel"), okType: "danger", confirmLoading: isDeleting, children: _jsx("p", { children: t("delete_conversation_confirm_message") }) })] }));
69
70
  };
70
71
  export default SingleThreadInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAuCA,eAAO,MAAM,cAAc,YA8Y1B,CAAC"}
1
+ {"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAwCA,eAAO,MAAM,cAAc,YA8a1B,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { useEffect } from "react";
2
+ import { usePathname, useRouter, useSearchParams } from "next/navigation";
2
3
  import { useLatest } from "ahooks";
3
4
  import { DChatSDK } from "../../constants/sdk";
4
5
  import { CbEvents, MessageType, SessionType, } from "@droppii-org/wasm-client-sdk";
@@ -22,11 +23,16 @@ export const useGlobalEvent = () => {
22
23
  const { user } = useChatContext();
23
24
  const userRef = useLatest(user);
24
25
  const queryClient = useQueryClient();
26
+ const router = useRouter();
27
+ const pathname = usePathname();
28
+ const searchParams = useSearchParams();
29
+ const searchParamsRef = useLatest(searchParams);
25
30
  const { updateConnectStatus, updateSyncStatus, getSelfUserInfo } = useChatContext();
26
31
  const updateConversationList = useConversationStore((state) => state.updateConversationList);
27
32
  const getConversationListByReq = useConversationStore((state) => state.getConversationListByReq);
28
33
  const getCurrentGroupInfoByReq = useConversationStore((state) => state.getCurrentGroupInfoByReq);
29
34
  const getSelfGroupPermissionByReq = useConversationStore((state) => state.getSelfGroupPermissionByReq);
35
+ const getCurrentMemberInGroupByReq = useConversationStore((state) => state.getCurrentMemberInGroupByReq);
30
36
  const { mutate: refetchChatToken } = useRefetchChatToken();
31
37
  const accessToken = useAuthStore((state) => state.accessToken);
32
38
  const chatToken = useAuthStore((state) => state.chatToken);
@@ -43,6 +49,9 @@ export const useGlobalEvent = () => {
43
49
  await Promise.all([
44
50
  getCurrentGroupInfoByReq(currentConversation.groupID),
45
51
  getSelfGroupPermissionByReq(currentConversation.groupID),
52
+ // roleLevel comes only from this call — without it, isAdminOrOwner
53
+ // checks (disband, mute toggle, etc.) fail closed.
54
+ getCurrentMemberInGroupByReq(currentConversation.groupID),
46
55
  ]);
47
56
  };
48
57
  const revokedMessageHandler = ({ data }) => {
@@ -210,10 +219,28 @@ export const useGlobalEvent = () => {
210
219
  const groupMemberInfoChangedHandler = () => {
211
220
  void refreshCurrentGroupState();
212
221
  };
213
- const groupDismissedHandler = ({ data }) => {
222
+ // Shared by OnGroupDismissed (group disbanded for everyone) and
223
+ // OnJoinedGroupDeleted (this client specifically removed from the group,
224
+ // e.g. kicked by an admin) — both leave the current user out of the group,
225
+ // so the local conversation state needs the same cleanup either way.
226
+ //
227
+ // Clearing the Zustand store alone isn't enough: both consumer screens
228
+ // (DeskConversationList for CRM, useActiveConversation for BIZ) re-derive
229
+ // the open conversation from the ?threadId= URL param on their own
230
+ // effects, so they'd immediately re-select the (now filtered-out) group
231
+ // unless the URL itself is cleared too — hence the router.replace below.
232
+ const leftGroupHandler = ({ data }) => {
233
+ var _a;
214
234
  const currentConversation = useConversationStore.getState().currentConversation;
215
235
  if ((currentConversation === null || currentConversation === void 0 ? void 0 : currentConversation.groupID) === data.groupID) {
216
236
  useConversationStore.getState().clearSelectedConversation();
237
+ const newSearchParams = new URLSearchParams((_a = searchParamsRef.current) === null || _a === void 0 ? void 0 : _a.toString());
238
+ newSearchParams.delete("threadId");
239
+ newSearchParams.delete("userId");
240
+ newSearchParams.delete("groupId");
241
+ newSearchParams.delete("botId");
242
+ const query = newSearchParams.toString();
243
+ router.replace(query ? `${pathname}?${query}` : pathname);
217
244
  }
218
245
  useConversationStore.setState((state) => ({
219
246
  conversationList: state.conversationList.filter((conversation) => conversation.groupID !== data.groupID),
@@ -258,7 +285,8 @@ export const useGlobalEvent = () => {
258
285
  // group info
259
286
  DChatSDK.on(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler);
260
287
  DChatSDK.on(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler);
261
- DChatSDK.on(CbEvents.OnGroupDismissed, groupDismissedHandler);
288
+ DChatSDK.on(CbEvents.OnGroupDismissed, leftGroupHandler);
289
+ DChatSDK.on(CbEvents.OnJoinedGroupDeleted, leftGroupHandler);
262
290
  // black list
263
291
  DChatSDK.on(CbEvents.OnBlackAdded, blackListChangedHandler);
264
292
  DChatSDK.on(CbEvents.OnBlackDeleted, blackListChangedHandler);
@@ -291,7 +319,8 @@ export const useGlobalEvent = () => {
291
319
  // group info
292
320
  DChatSDK.off(CbEvents.OnGroupInfoChanged, groupInfoChangedHandler);
293
321
  DChatSDK.off(CbEvents.OnGroupMemberInfoChanged, groupMemberInfoChangedHandler);
294
- DChatSDK.off(CbEvents.OnGroupDismissed, groupDismissedHandler);
322
+ DChatSDK.off(CbEvents.OnGroupDismissed, leftGroupHandler);
323
+ DChatSDK.off(CbEvents.OnJoinedGroupDeleted, leftGroupHandler);
295
324
  // black list
296
325
  DChatSDK.off(CbEvents.OnBlackAdded, blackListChangedHandler);
297
326
  DChatSDK.off(CbEvents.OnBlackDeleted, blackListChangedHandler);
@@ -1 +1 @@
1
- {"version":3,"file":"useConversationSessionState.d.ts","sourceRoot":"","sources":["../../../src/hooks/session/useConversationSessionState.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAI3D,UAAU,iCAAiC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,2BAA2B,GAAI,gDAIzC,iCAAiC;;;;;CAmBnC,CAAC"}
1
+ {"version":3,"file":"useConversationSessionState.d.ts","sourceRoot":"","sources":["../../../src/hooks/session/useConversationSessionState.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAI3D,UAAU,iCAAiC;IACzC,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,WAAW,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,2BAA2B,GAAI,gDAIzC,iCAAiC;;;;;CAoBnC,CAAC"}
@@ -7,6 +7,7 @@ export const useConversationSessionState = ({ conversationId, conversationType,
7
7
  const currentGroupId = isGroupConversation ? groupId : undefined;
8
8
  const { data: conversationSessions, refetch: refetchConversationSessions, } = useGetListSessionByConversation({
9
9
  conversationId,
10
+ enabled: !isGroupConversation,
10
11
  });
11
12
  const latestConversationSession = conversationSessions === null || conversationSessions === void 0 ? void 0 : conversationSessions[0];
12
13
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.tsx"],"names":[],"mappings":"AAIA,OAAO,iBAAiB,CAAC;AAKzB,UAAU,eAAe;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AACD,QAAA,MAAM,UAAU,GAAI,cAAc,eAAe,4CAKhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.tsx"],"names":[],"mappings":"AAIA,OAAO,iBAAiB,CAAC;AAUzB,UAAU,eAAe;IACvB,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AACD,QAAA,MAAM,UAAU,GAAI,cAAc,eAAe,4CAKhD,CAAC;AAEF,eAAe,UAAU,CAAC"}
@@ -3,7 +3,12 @@ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
3
3
  import { useGlobalEvent } from "../hooks/global/useGlobalEvent";
4
4
  import dayjs from "dayjs";
5
5
  import "dayjs/locale/vi";
6
+ import utc from "dayjs/plugin/utc";
7
+ import timezone from "dayjs/plugin/timezone";
6
8
  import { useSyncUsersInfo } from "../hooks/user/useUsersInfo";
9
+ dayjs.extend(utc);
10
+ dayjs.extend(timezone);
11
+ dayjs.tz.setDefault("Asia/Ho_Chi_Minh");
7
12
  dayjs.locale("vi");
8
13
  const MainLayout = ({ children }) => {
9
14
  useGlobalEvent();
@@ -102,6 +102,8 @@
102
102
  "select_status": "Chọn trạng thái",
103
103
  "invalid_file_format": "{{fileName}} không đúng định dạng JPG, JPEG, PNG hoặc VIDEO",
104
104
  "file_size_exceeded": "{{fileName}} có kích thước tập tin vượt quá {{maxSize}}MB",
105
+ "avatar_invalid_format": "Vui lòng dùng file PNG, JPG, JPEG, WEBP",
106
+ "avatar_size_exceeded": "Vui lòng dùng ảnh dưới {{maxSize}}MB",
105
107
  "file_processing_error": "Đã xảy ra lỗi khi xử lý tệp",
106
108
  "invalid_document_format": "{{fileName}} không đúng định dạng (chỉ hỗ trợ PDF, DOC, DOCX)",
107
109
  "view_message": "Xem tin nhắn",
@@ -154,10 +156,10 @@
154
156
  "mute_member_success": "Đã tắt quyền gửi tin nhắn",
155
157
  "unmute_member_success": "Đã bật lại quyền gửi tin nhắn",
156
158
  "send_message": "Gửi tin nhắn",
157
- "transfer_owner": "Chuyển quyền chủ nhóm",
158
- "transfer_owner_success": "Đã chuyển quyền chủ nhóm",
159
- "transfer_owner_confirm_title": "Chuyển quyền chủ nhóm",
160
- "transfer_owner_confirm_message": "Bạn có chắc muốn chuyển quyền chủ nhóm cho {{name}}? Bạn sẽ trở thành quản trị viên.",
159
+ "transfer_owner": "Chuyển quyền sở hữu nhóm",
160
+ "transfer_owner_success": "Đã chuyển quyền sở hữu nhóm",
161
+ "transfer_owner_confirm_title": "Chuyển quyền sở hữu nhóm",
162
+ "transfer_owner_confirm_message": "Bạn có chắc muốn chuyển quyền sở hữu nhóm cho {{name}}?",
161
163
  "assign_as_admin": "Chỉ định làm quản trị viên",
162
164
  "assign_as_admin_success": "Đã chỉ định làm quản trị viên",
163
165
  "assign_admin_confirm_title": "Cấp quyền quản trị viên",
@@ -167,9 +169,9 @@
167
169
  "remove_from_admin_success": "Đã xoá khỏi quản trị viên",
168
170
  "remove_from_group": "Xoá khỏi nhóm",
169
171
  "remove_member_success": "Đã xoá thành viên khỏi nhóm",
170
- "remove_member_failed": "Không thể xoá thành viên. Vui lòng thử lại",
171
- "remove_member_confirm_title": "Xoá thành viên khỏi nhóm",
172
- "remove_member_confirm_message": "Bạn chắc muốn xoá {{name}} khỏi nhóm?",
172
+ "remove_member_failed": "Xoá thành viên không thành công, vui lòng thử lại!",
173
+ "remove_member_confirm_title": "Xóa khỏi nhóm",
174
+ "remove_member_confirm_message": "Bạn chắc chắn muốn xóa \"{{name}}\" khỏi nhóm ?",
173
175
  "remove_and_block": "Xoá và chặn",
174
176
  "choose_emoji": "Chọn biểu tượng cảm xúc",
175
177
  "emoji_smileys": "Mặt cười",
@@ -194,6 +196,7 @@
194
196
  "team_messages": "Tin nhắn nhóm",
195
197
  "join_group_required": "Bạn phải là thành viên để gửi tin nhắn",
196
198
  "send_message_disabled": "Chỉ quản trị viên được phép gửi tin nhắn",
199
+ "send_message_disabled_group_mute": "Chỉ chủ nhóm và quản trị viên được phép gửi tin nhắn",
197
200
  "join_group": "Tham gia",
198
201
  "join_group_success": "Tham gia nhóm thành công",
199
202
  "join_group_failed": "Tham gia nhóm thất bại",
@@ -248,4 +251,4 @@
248
251
  "block_user_success": "Đã chặn người dùng",
249
252
  "unblock_user_success": "Đã bỏ chặn người dùng",
250
253
  "block_user_failed": "Thao tác chặn/bỏ chặn thất bại"
251
- }
254
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAM3C,QAAA,MAAM,oBAAoB,gFAgSvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../src/store/conversation.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,iBAAiB,EAAE,MAAM,QAAQ,CAAC;AAM3C,QAAA,MAAM,oBAAoB,gFA4SvB,CAAC;AAEJ,eAAe,oBAAoB,CAAC"}
@@ -102,6 +102,9 @@ const useConversationStore = create((set, get) => ({
102
102
  await Promise.all([
103
103
  get().getCurrentGroupInfoByReq(conversation.groupID),
104
104
  get().getSelfGroupPermissionByReq(conversation.groupID),
105
+ // roleLevel comes only from this call — without it, role checks
106
+ // fail closed until an unrelated WS event happens to refresh it.
107
+ get().getCurrentMemberInGroupByReq(conversation.groupID),
105
108
  ]);
106
109
  }
107
110
  else {
@@ -152,13 +155,14 @@ const useConversationStore = create((set, get) => ({
152
155
  memberInfo = data[0];
153
156
  }
154
157
  catch (error) {
155
- set(() => ({ currentMemberInGroup: undefined }));
156
158
  console.error("Error fetching group members:", error);
157
159
  return;
158
160
  }
159
161
  const currentConversationData = get().conversationData;
160
162
  const shouldApplyMemberInfo = (currentConversationData === null || currentConversationData === void 0 ? void 0 : currentConversationData.groupID) === groupID &&
161
163
  isGroupSession(currentConversationData === null || currentConversationData === void 0 ? void 0 : currentConversationData.conversationType);
164
+ // Runs concurrently with getSelfGroupPermissionByReq — only apply to
165
+ // the conversation still open, so a stale response can't clobber it.
162
166
  if (!shouldApplyMemberInfo) {
163
167
  return;
164
168
  }
@@ -186,9 +190,17 @@ const useConversationStore = create((set, get) => ({
186
190
  if (!shouldApplyMemberInfo || !selfInfo) {
187
191
  return;
188
192
  }
189
- set((state) => ({
190
- currentMemberInGroup: Object.assign(Object.assign({}, state.currentMemberInGroup), { groupID, userID: selfInfo.userID, nickname: selfInfo.nickname, faceURL: selfInfo.faceURL, permissions: selfInfo.permissions }),
191
- }));
193
+ set((state) => {
194
+ var _a;
195
+ // Only merge onto a record for the SAME group, or a race can spread
196
+ // a stale conversation's roleLevel onto the new groupID.
197
+ const base = ((_a = state.currentMemberInGroup) === null || _a === void 0 ? void 0 : _a.groupID) === groupID
198
+ ? state.currentMemberInGroup
199
+ : undefined;
200
+ return {
201
+ currentMemberInGroup: Object.assign(Object.assign({}, base), { groupID, userID: selfInfo.userID, nickname: selfInfo.nickname, faceURL: selfInfo.faceURL, permissions: selfInfo.permissions }),
202
+ };
203
+ });
192
204
  },
193
205
  clearSelectedConversation: () => {
194
206
  set({
@@ -1 +1 @@
1
- *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(40,138,230,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(40,138,230,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #a8adaf}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#747b7e}input::placeholder,textarea::placeholder{opacity:1;color:#747b7e}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.static{position:static}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-bottom-1{bottom:-.25rem}.-bottom-px{bottom:-1px}.-right-1{right:-.25rem}.-right-px{right:-1px}.-top-1{top:-.25rem}.-top-2\.5{top:-.625rem}.bottom-0{bottom:0}.bottom-1{bottom:.25rem}.bottom-full{bottom:100%}.left-0{left:0}.left-1\/2{left:50%}.left-2{left:.5rem}.left-3{left:.75rem}.right-0{right:0}.right-1{right:.25rem}.right-2{right:.5rem}.top-0{top:0}.top-1\/2{top:50%}.top-2{top:.5rem}.top-3{top:.75rem}.\!z-\[9999\]{z-index:9999!important}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[1\]{z-index:1}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.-mr-1\.5{margin-right:-.375rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-\[2px\]{margin-top:2px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/9\]{aspect-ratio:16/9}.aspect-square{aspect-ratio:1/1}.aspect-video{aspect-ratio:16/9}.\!h-full{height:100%!important}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[100px\]{height:100px}.h-\[120px\]{height:120px}.h-\[144px\]{height:144px}.h-\[17px\]{height:17px}.h-\[22px\]{height:22px}.h-\[36px\]{height:36px}.h-\[3px\]{height:3px}.h-\[400px\]{height:400px}.h-\[42px\]{height:42px}.h-\[51px\]{height:51px}.h-\[59px\]{height:59px}.h-\[600px\]{height:600px}.h-\[76px\]{height:76px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-80{max-height:20rem}.max-h-\[140px\]{max-height:140px}.max-h-\[70vh\]{max-height:70vh}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0}.min-h-10{min-height:2.5rem}.min-h-40{min-height:10rem}.min-h-6{min-height:1.5rem}.min-h-\[200px\]{min-height:200px}.min-h-\[25\.6px\]{min-height:25.6px}.min-h-\[32px\]{min-height:32px}.min-h-\[64px\]{min-height:64px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-96{width:24rem}.w-\[100px\]{width:100px}.w-\[120px\]{width:120px}.w-\[168px\]{width:168px}.w-\[170px\]{width:170px}.w-\[26px\]{width:26px}.w-\[292px\]{width:292px}.w-\[320px\]{width:320px}.w-\[330px\]{width:330px}.w-\[36px\]{width:36px}.w-\[3px\]{width:3px}.w-\[400px\]{width:400px}.w-\[42px\]{width:42px}.w-\[51px\]{width:51px}.w-\[52px\]{width:52px}.w-\[600px\]{width:600px}.w-\[76px\]{width:76px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.min-w-0{min-width:0}.min-w-10{min-width:2.5rem}.min-w-5{min-width:1.25rem}.min-w-6{min-width:1.5rem}.min-w-8{min-width:2rem}.min-w-\[100px\]{min-width:100px}.min-w-\[26px\]{min-width:26px}.max-w-\[120px\]{max-width:120px}.max-w-\[200px\]{max-width:200px}.max-w-\[292px\]{max-width:292px}.max-w-\[75\%\]{max-width:75%}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.flex-\[1_0_0\]{flex:1 0 0}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-pan-y{--tw-pan-y:pan-y;touch-action:var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[repeat\(1\2c 100px\)\]{grid-template-columns:repeat(1,100px)}.grid-cols-\[repeat\(2\2c 100px\)\]{grid-template-columns:repeat(2,100px)}.grid-cols-\[repeat\(3\2c 100px\)\]{grid-template-columns:repeat(3,100px)}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-\[7px\]{gap:7px}.gap-px{gap:1px}.gap-y-5{row-gap:1.25rem}.self-end{align-self:flex-end}.self-center{align-self:center}.self-stretch{align-self:stretch}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-normal{overflow-wrap:normal;word-break:normal}.\!rounded-lg{border-radius:.5rem!important}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[12px\]{border-radius:12px}.rounded-\[20px\]{border-radius:20px}.rounded-\[32px\]{border-radius:32px}.rounded-\[4px\]{border-radius:4px}.rounded-\[8px\]{border-radius:8px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-r-xl{border-top-right-radius:.75rem;border-bottom-right-radius:.75rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-bl-none{border-bottom-left-radius:0}.rounded-br-none{border-bottom-right-radius:0}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-none{border-style:none}.\!border-danger-400{--tw-border-opacity:1!important;border-color:rgb(240 68 56/var(--tw-border-opacity,1))!important}.\!border-gray-25{--tw-border-opacity:1!important;border-color:rgb(239 239 239/var(--tw-border-opacity,1))!important}.\!border-primary-400{--tw-border-opacity:1!important;border-color:rgb(27 63 228/var(--tw-border-opacity,1))!important}.border-blue-500{--tw-border-opacity:1;border-color:rgb(40 138 230/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(194 197 199/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(168 173 175/var(--tw-border-opacity,1))}.border-gray-200\/20{border-color:hsla(197,4%,67%,.2)}.border-gray-25{--tw-border-opacity:1;border-color:rgb(239 239 239/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(142 148 150/var(--tw-border-opacity,1))}.border-gray-50{--tw-border-opacity:1;border-color:rgb(221 222 223/var(--tw-border-opacity,1))}.border-gray-900\/10{border-color:rgba(57,62,64,.1)}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.border-orange-300{--tw-border-opacity:1;border-color:rgb(253 186 116/var(--tw-border-opacity,1))}.border-primary-200{--tw-border-opacity:1;border-color:rgb(96 124 251/var(--tw-border-opacity,1))}.border-primary-400{--tw-border-opacity:1;border-color:rgb(27 63 228/var(--tw-border-opacity,1))}.border-primary-500{--tw-border-opacity:1;border-color:rgb(15 51 214/var(--tw-border-opacity,1))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-t-transparent{border-top-color:transparent}.\!bg-amber-100{--tw-bg-opacity:1!important;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))!important}.\!bg-amber-500{--tw-bg-opacity:1!important;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))!important}.\!bg-blue-100{--tw-bg-opacity:1!important;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))!important}.\!bg-blue-500{--tw-bg-opacity:1!important;background-color:rgb(40 138 230/var(--tw-bg-opacity,1))!important}.\!bg-danger-400{--tw-bg-opacity:1!important;background-color:rgb(240 68 56/var(--tw-bg-opacity,1))!important}.\!bg-gray-100{--tw-bg-opacity:1!important;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))!important}.\!bg-gray-25{--tw-bg-opacity:1!important;background-color:rgb(239 239 239/var(--tw-bg-opacity,1))!important}.\!bg-gray-500{--tw-bg-opacity:1!important;background-color:rgb(104 111 114/var(--tw-bg-opacity,1))!important}.\!bg-green-100{--tw-bg-opacity:1!important;background-color:rgb(246 255 237/var(--tw-bg-opacity,1))!important}.\!bg-green-500{--tw-bg-opacity:1!important;background-color:rgb(38 191 135/var(--tw-bg-opacity,1))!important}.\!bg-orange-100{--tw-bg-opacity:1!important;background-color:rgb(255 237 213/var(--tw-bg-opacity,1))!important}.\!bg-orange-500{--tw-bg-opacity:1!important;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))!important}.\!bg-primary-400{--tw-bg-opacity:1!important;background-color:rgb(27 63 228/var(--tw-bg-opacity,1))!important}.\!bg-purple-100{--tw-bg-opacity:1!important;background-color:rgb(249 240 255/var(--tw-bg-opacity,1))!important}.\!bg-purple-500{--tw-bg-opacity:1!important;background-color:rgb(146 84 222/var(--tw-bg-opacity,1))!important}.\!bg-red-100{--tw-bg-opacity:1!important;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))!important}.\!bg-red-500{--tw-bg-opacity:1!important;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))!important}.bg-\[\#f5f5f5\]{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-\[\#f5f5f5\]\/20{background-color:hsla(0,0%,96%,.2)}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/10{background-color:rgba(0,0,0,.1)}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-black\/5{background-color:rgba(0,0,0,.05)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-black\/60{background-color:rgba(0,0,0,.6)}.bg-black\/70{background-color:rgba(0,0,0,.7)}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))}.bg-blue-25{--tw-bg-opacity:1;background-color:rgb(234 245 255/var(--tw-bg-opacity,1))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(89 171 255/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(198 226 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(40 138 230/var(--tw-bg-opacity,1))}.bg-chat-bubble-mine\/10{background-color:rgba(0,81,255,.1)}.bg-chat-bubble-neutral\/10{background-color:rgba(131,137,157,.1)}.bg-chat-bubble-neutral\/\[0\.05\]{background-color:rgba(131,137,157,.05)}.bg-chat-internal\/10{background-color:rgba(255,149,0,.1)}.bg-chat-send{--tw-bg-opacity:1;background-color:rgb(0 43 235/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.bg-gray-200\/10{background-color:hsla(197,4%,67%,.1)}.bg-gray-25{--tw-bg-opacity:1;background-color:rgb(239 239 239/var(--tw-bg-opacity,1))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(116 123 126/var(--tw-bg-opacity,1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(104 111 114/var(--tw-bg-opacity,1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(57 62 64/var(--tw-bg-opacity,1))}.bg-gray-cool-200{--tw-bg-opacity:1;background-color:rgb(169 178 208/var(--tw-bg-opacity,1))}.bg-gray-cool-25{--tw-bg-opacity:1;background-color:rgb(241 243 248/var(--tw-bg-opacity,1))}.bg-neutral-100{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-neutral-200{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-orange-900{--tw-bg-opacity:1;background-color:rgb(242 133 4/var(--tw-bg-opacity,1))}.bg-primary-25{--tw-bg-opacity:1;background-color:rgb(230 233 255/var(--tw-bg-opacity,1))}.bg-primary-400{--tw-bg-opacity:1;background-color:rgb(27 63 228/var(--tw-bg-opacity,1))}.bg-primary-400\/60{background-color:rgba(27,63,228,.6)}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(184 194 255/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/70{background-color:hsla(0,0%,100%,.7)}.bg-gradient-danger-light{background-image:linear-gradient(93deg,#ff7d74,#f04438)}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\!p-0{padding:0!important}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[3px\]{padding-left:3px;padding-right:3px}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[42px\]{padding-top:42px;padding-bottom:42px}.py-\[4px\]{padding-top:4px;padding-bottom:4px}.pb-1{padding-bottom:.25rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-60{padding-bottom:15rem}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-12{padding-left:3rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pr-1{padding-right:.25rem}.pr-12{padding-right:3rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pr-5{padding-right:1.25rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.\!align-\[-4px\]{vertical-align:-4px!important}.\!text-\[16px\]{font-size:16px!important}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[16px\]{font-size:16px}.text-\[18px\]{font-size:18px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.\!font-medium{font-weight:500!important}.font-\[510\]{font-weight:510}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-3{line-height:.75rem}.leading-4{line-height:1rem}.leading-\[1\.4\]{line-height:1.4}.leading-\[1\.6\]{line-height:1.6}.leading-\[160\%\]{line-height:160%}.leading-none{line-height:1}.tracking-\[-0\.14px\]{letter-spacing:-.14px}.tracking-\[0\.12px\]{letter-spacing:.12px}.tracking-\[0\.14px\]{letter-spacing:.14px}.tracking-\[0\.16px\]{letter-spacing:.16px}.tracking-\[0\.1px\]{letter-spacing:.1px}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.\!text-amber-500{--tw-text-opacity:1!important;color:rgb(245 158 11/var(--tw-text-opacity,1))!important}.\!text-blue-500{--tw-text-opacity:1!important;color:rgb(40 138 230/var(--tw-text-opacity,1))!important}.\!text-gray-500{--tw-text-opacity:1!important;color:rgb(104 111 114/var(--tw-text-opacity,1))!important}.\!text-gray-900{--tw-text-opacity:1!important;color:rgb(57 62 64/var(--tw-text-opacity,1))!important}.\!text-green-500{--tw-text-opacity:1!important;color:rgb(38 191 135/var(--tw-text-opacity,1))!important}.\!text-orange-400{--tw-text-opacity:1!important;color:rgb(251 146 60/var(--tw-text-opacity,1))!important}.\!text-orange-500{--tw-text-opacity:1!important;color:rgb(249 115 22/var(--tw-text-opacity,1))!important}.\!text-purple-500{--tw-text-opacity:1!important;color:rgb(146 84 222/var(--tw-text-opacity,1))!important}.\!text-red-500{--tw-text-opacity:1!important;color:rgb(239 68 68/var(--tw-text-opacity,1))!important}.\!text-white{--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity,1))!important}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(40 138 230/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(27 122 204/var(--tw-text-opacity,1))}.text-chat-bubble-mine{--tw-text-opacity:1;color:rgb(0 81 255/var(--tw-text-opacity,1))}.text-chat-bubble-neutral{--tw-text-opacity:1;color:rgb(131 137 157/var(--tw-text-opacity,1))}.text-chat-internal{--tw-text-opacity:1;color:rgb(255 149 0/var(--tw-text-opacity,1))}.text-danger-400{--tw-text-opacity:1;color:rgb(240 68 56/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(142 148 150/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(104 111 114/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(92 99 102/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(80 87 89/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(68 74 77/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(57 62 64/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12/var(--tw-text-opacity,1))}.text-primary-400{--tw-text-opacity:1;color:rgb(27 63 228/var(--tw-text-opacity,1))}.text-primary-500{--tw-text-opacity:1;color:rgb(15 51 214/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.\!shadow-none{--tw-shadow:0 0 #0000!important;--tw-shadow-colored:0 0 #0000!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}.shadow-badge-inset{--tw-shadow:inset 2px 6px 8px 0 rgba(0,0,0,.4);--tw-shadow-colored:inset 2px 6px 8px 0 var(--tw-shadow-color)}.shadow-badge-inset,.shadow-inset-gray-divider{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-inset-gray-divider{--tw-shadow:inset 0px -1px 0px 0px rgba(61,63,64,.1);--tw-shadow-colored:inset 0px -1px 0px 0px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-primary-focus{--tw-shadow:0px 0px 2px rgba(27,63,228,.5);--tw-shadow-colored:0px 0px 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-0{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-none{transition-property:none}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[font-feature-settings\:\'liga\'_off\2c \'clig\'_off\]{font-feature-settings:"liga" off,"clig" off}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.ant-tabs-tab{margin:0!important;min-width:80px!important;justify-content:center!important;align-items:center!important}.ant-tabs-content,.ant-tabs-content-holder,.ant-tabs-tabpane{height:100%}.zoom-in-out-element{animation:zoom-in-zoom-out 1.5s ease none}@keyframes zoom-in-zoom-out{0%{scale:100%}25%{scale:125%}50%{scale:100%}75%{scale:125%}to{scale:100%}}.conversation-message-input-scrollbar{-moz-appearance:none!important;-webkit-appearance:none!important;appearance:none!important;background:transparent!important;border:0!important;box-shadow:none!important;outline:none!important;scrollbar-width:thin;scrollbar-color:rgba(40,43,54,.3) transparent}.conversation-message-input-scrollbar:active,.conversation-message-input-scrollbar:focus,.conversation-message-input-scrollbar:focus-visible{background:transparent!important;border:0!important;border-color:transparent!important;box-shadow:none!important;outline:none!important;--tw-ring-color:transparent!important;--tw-ring-offset-shadow:0 0 #0000!important;--tw-ring-shadow:0 0 #0000!important}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.last\:border-b-0:last-child{border-bottom-width:0}.focus-within\:border-chat-focus:focus-within{--tw-border-opacity:1;border-color:rgb(50 120 247/var(--tw-border-opacity,1))}.focus-within\:shadow-chat-focus-ring:focus-within{--tw-shadow:0 0 0 2px rgba(50,120,247,.12);--tw-shadow-colored:0 0 0 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:rounded-sm:hover{border-radius:.125rem}.hover\:\!border-danger-300:hover{--tw-border-opacity:1!important;border-color:rgb(250 95 84/var(--tw-border-opacity,1))!important}.hover\:\!border-primary-300:hover{--tw-border-opacity:1!important;border-color:rgb(60 92 241/var(--tw-border-opacity,1))!important}.hover\:\!bg-danger-300:hover{--tw-bg-opacity:1!important;background-color:rgb(250 95 84/var(--tw-bg-opacity,1))!important}.hover\:\!bg-primary-300:hover{--tw-bg-opacity:1!important;background-color:rgb(60 92 241/var(--tw-bg-opacity,1))!important}.hover\:bg-\[\#f5f5f5\]:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.hover\:bg-black\/70:hover{background-color:rgba(0,0,0,.7)}.hover\:bg-blue-100:hover{--tw-bg-opacity:1;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(138 158 255/var(--tw-bg-opacity,1))}.hover\:text-blue-700:hover{--tw-text-opacity:1;color:rgb(17 107 179/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(92 99 102/var(--tw-text-opacity,1))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(80 87 89/var(--tw-text-opacity,1))}.hover\:text-primary-500:hover{--tw-text-opacity:1;color:rgb(15 51 214/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.focus\:border-0:focus{border-width:0}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-chat-ring:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(22 119 255/var(--tw-ring-opacity,1))}.active\:bg-chat-bubble-neutral\/\[0\.08\]:active{background-color:rgba(131,137,157,.08)}.active\:bg-primary-400\/90:active{background-color:rgba(27,63,228,.9)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:bg-gray-200:disabled{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.disabled\:text-gray-300:disabled{--tw-text-opacity:1;color:rgb(142 148 150/var(--tw-text-opacity,1))}.disabled\:text-gray-400:disabled{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.disabled\:opacity-60:disabled{opacity:.6}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:px-4{padding-left:1rem;padding-right:1rem}}.\[\&\>svg\]\:h-6>svg{height:1.5rem}.\[\&\>svg\]\:h-8>svg{height:2rem}.\[\&\>svg\]\:h-full>svg{height:100%}.\[\&\>svg\]\:w-6>svg{width:1.5rem}.\[\&\>svg\]\:w-8>svg{width:2rem}.\[\&\>svg\]\:w-auto>svg{width:auto}.\[\&_\.ant-dropdown-menu-item\]\:rounded-none .ant-dropdown-menu-item{border-radius:0}.\[\&_\.ant-dropdown-menu-item\]\:\!px-4 .ant-dropdown-menu-item{padding-left:1rem!important;padding-right:1rem!important}.\[\&_\.ant-dropdown-menu-item\]\:\!py-1\.5 .ant-dropdown-menu-item{padding-top:.375rem!important;padding-bottom:.375rem!important}.\[\&_\.ant-dropdown-menu\]\:min-w-\[200px\] .ant-dropdown-menu{min-width:200px}.\[\&_\.ant-dropdown-menu\]\:rounded-2xl .ant-dropdown-menu{border-radius:1rem}.\[\&_\.ant-dropdown-menu\]\:p-0 .ant-dropdown-menu{padding:0}.\[\&_\.ant-dropdown-menu\]\:py-2 .ant-dropdown-menu{padding-top:.5rem;padding-bottom:.5rem}.\[\&_\.ant-dropdown-menu\]\:shadow-message-toolbox .ant-dropdown-menu{--tw-shadow:0px 0px 24px 0px rgba(14,28,52,.1);--tw-shadow-colored:0px 0px 24px 0px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.\[\&_\.ant-tabs-content-holder\]\:hidden .ant-tabs-content-holder{display:none}.\[\&_\.ant-tabs-extra-content\]\:flex .ant-tabs-extra-content{display:flex}.\[\&_\.ant-tabs-extra-content\]\:items-center .ant-tabs-extra-content{align-items:center}.\[\&_\.ant-tabs-extra-content\]\:overflow-hidden .ant-tabs-extra-content{overflow:hidden}.\[\&_\.ant-tabs-extra-content\]\:text-ellipsis .ant-tabs-extra-content{text-overflow:ellipsis}.\[\&_\.ant-tabs-ink-bar\]\:hidden .ant-tabs-ink-bar{display:none}.\[\&_\.ant-tabs-nav-wrap\]\:justify-end .ant-tabs-nav-wrap{justify-content:flex-end}.\[\&_\.ant-tabs-nav\]\:mb-0 .ant-tabs-nav{margin-bottom:0}.\[\&_\.ant-tabs-nav\]\:px-4 .ant-tabs-nav{padding-left:1rem;padding-right:1rem}.\[\&_\.ant-tabs-nav\]\:pt-0 .ant-tabs-nav{padding-top:0}.\[\&_\.ant-tabs-nav\]\:before\:border-b-0 .ant-tabs-nav:before{content:var(--tw-content);border-bottom-width:0}.\[\&_\.ant-tabs-tab-active\]\:border-indigo-200 .ant-tabs-tab-active{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:border-orange-200 .ant-tabs-tab-active{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:bg-indigo-50 .ant-tabs-tab-active{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:bg-orange-50 .ant-tabs-tab-active{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.\[\&_\.ant-tabs-tab-btn\]\:leading-5 .ant-tabs-tab-btn{line-height:1.25rem}.\[\&_\.ant-tabs-tab\]\:mb-0 .ant-tabs-tab{margin-bottom:0}.\[\&_\.ant-tabs-tab\]\:rounded-t-\[16px\] .ant-tabs-tab{border-top-left-radius:16px;border-top-right-radius:16px}.\[\&_\.ant-tabs-tab\]\:border .ant-tabs-tab{border-width:1px}.\[\&_\.ant-tabs-tab\]\:border-b-0 .ant-tabs-tab{border-bottom-width:0}.\[\&_\.ant-tabs-tab\]\:border-transparent .ant-tabs-tab{border-color:transparent}.\[\&_\.ant-tabs-tab\]\:px-3 .ant-tabs-tab{padding-left:.75rem;padding-right:.75rem}.\[\&_\.ant-tabs-tab\]\:py-1\.5 .ant-tabs-tab{padding-top:.375rem;padding-bottom:.375rem}.\[\&_\.ant-tabs-tab\]\:leading-5 .ant-tabs-tab{line-height:1.25rem}.\[\&_code\]\:font-\[inherit\] code,.\[\&_kbd\]\:font-\[inherit\] kbd,.\[\&_pre\]\:font-\[inherit\] pre,.\[\&_samp\]\:font-\[inherit\] samp{font-family:inherit}
1
+ *,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(40,138,230,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(40,138,230,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: ;--tw-contain-size: ;--tw-contain-layout: ;--tw-contain-paint: ;--tw-contain-style: }/*! tailwindcss v3.4.17 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #a8adaf}:after,:before{--tw-content:""}:host,html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal;-webkit-tap-highlight-color:transparent}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-feature-settings:normal;font-variation-settings:normal;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;letter-spacing:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}button,input:where([type=button]),input:where([type=reset]),input:where([type=submit]){-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#747b7e}input::placeholder,textarea::placeholder{opacity:1;color:#747b7e}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]:where(:not([hidden=until-found])){display:none}.\!container{width:100%!important}.container{width:100%}@media (min-width:640px){.\!container{max-width:640px!important}.container{max-width:640px}}@media (min-width:768px){.\!container{max-width:768px!important}.container{max-width:768px}}@media (min-width:1024px){.\!container{max-width:1024px!important}.container{max-width:1024px}}@media (min-width:1280px){.\!container{max-width:1280px!important}.container{max-width:1280px}}@media (min-width:1536px){.\!container{max-width:1536px!important}.container{max-width:1536px}}.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.static{position:static}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.inset-0{inset:0}.inset-y-0{top:0;bottom:0}.-bottom-1{bottom:-.25rem}.-bottom-2{bottom:-.5rem}.-bottom-px{bottom:-1px}.-right-1{right:-.25rem}.-right-px{right:-1px}.-top-1{top:-.25rem}.-top-2\.5{top:-.625rem}.bottom-0{bottom:0}.bottom-1{bottom:.25rem}.bottom-full{bottom:100%}.left-0{left:0}.left-1{left:.25rem}.left-1\/2{left:50%}.left-2{left:.5rem}.left-3{left:.75rem}.right-0{right:0}.right-1{right:.25rem}.right-2{right:.5rem}.top-0{top:0}.top-1\/2{top:50%}.top-2{top:.5rem}.top-3{top:.75rem}.\!z-\[9999\]{z-index:9999!important}.z-10{z-index:10}.z-20{z-index:20}.z-50{z-index:50}.z-\[1\]{z-index:1}.-mx-1{margin-left:-.25rem;margin-right:-.25rem}.mx-1{margin-left:.25rem;margin-right:.25rem}.mx-4{margin-left:1rem;margin-right:1rem}.my-2{margin-top:.5rem;margin-bottom:.5rem}.-mr-1\.5{margin-right:-.375rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-2{margin-left:.5rem}.mt-0\.5{margin-top:.125rem}.mt-1{margin-top:.25rem}.mt-1\.5{margin-top:.375rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-\[2px\]{margin-top:2px}.line-clamp-2{overflow:hidden;display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.hidden{display:none}.aspect-\[16\/9\]{aspect-ratio:16/9}.aspect-square{aspect-ratio:1/1}.aspect-video{aspect-ratio:16/9}.\!h-10{height:2.5rem!important}.\!h-full{height:100%!important}.h-10{height:2.5rem}.h-11{height:2.75rem}.h-12{height:3rem}.h-2{height:.5rem}.h-2\.5{height:.625rem}.h-20{height:5rem}.h-24{height:6rem}.h-3{height:.75rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-7{height:1.75rem}.h-8{height:2rem}.h-\[100px\]{height:100px}.h-\[120px\]{height:120px}.h-\[144px\]{height:144px}.h-\[17px\]{height:17px}.h-\[19px\]{height:19px}.h-\[22px\]{height:22px}.h-\[36px\]{height:36px}.h-\[3px\]{height:3px}.h-\[400px\]{height:400px}.h-\[42px\]{height:42px}.h-\[51px\]{height:51px}.h-\[59px\]{height:59px}.h-\[600px\]{height:600px}.h-\[76px\]{height:76px}.h-full{height:100%}.h-px{height:1px}.h-screen{height:100vh}.max-h-48{max-height:12rem}.max-h-64{max-height:16rem}.max-h-72{max-height:18rem}.max-h-80{max-height:20rem}.max-h-\[140px\]{max-height:140px}.max-h-\[70vh\]{max-height:70vh}.max-h-\[80vh\]{max-height:80vh}.min-h-0{min-height:0}.min-h-10{min-height:2.5rem}.min-h-40{min-height:10rem}.min-h-6{min-height:1.5rem}.min-h-\[200px\]{min-height:200px}.min-h-\[25\.6px\]{min-height:25.6px}.min-h-\[32px\]{min-height:32px}.min-h-\[64px\]{min-height:64px}.w-1{width:.25rem}.w-1\/2{width:50%}.w-1\/3{width:33.333333%}.w-10{width:2.5rem}.w-11{width:2.75rem}.w-12{width:3rem}.w-16{width:4rem}.w-2{width:.5rem}.w-20{width:5rem}.w-24{width:6rem}.w-4{width:1rem}.w-40{width:10rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-64{width:16rem}.w-7{width:1.75rem}.w-8{width:2rem}.w-9{width:2.25rem}.w-96{width:24rem}.w-\[100px\]{width:100px}.w-\[120px\]{width:120px}.w-\[168px\]{width:168px}.w-\[170px\]{width:170px}.w-\[26px\]{width:26px}.w-\[292px\]{width:292px}.w-\[30px\]{width:30px}.w-\[320px\]{width:320px}.w-\[330px\]{width:330px}.w-\[36px\]{width:36px}.w-\[3px\]{width:3px}.w-\[400px\]{width:400px}.w-\[42px\]{width:42px}.w-\[51px\]{width:51px}.w-\[52px\]{width:52px}.w-\[600px\]{width:600px}.w-\[76px\]{width:76px}.w-fit{width:-moz-fit-content;width:fit-content}.w-full{width:100%}.min-w-0{min-width:0}.min-w-10{min-width:2.5rem}.min-w-5{min-width:1.25rem}.min-w-6{min-width:1.5rem}.min-w-8{min-width:2rem}.min-w-\[100px\]{min-width:100px}.min-w-\[26px\]{min-width:26px}.max-w-\[120px\]{max-width:120px}.max-w-\[200px\]{max-width:200px}.max-w-\[292px\]{max-width:292px}.max-w-\[75\%\]{max-width:75%}.max-w-full{max-width:100%}.flex-1{flex:1 1 0%}.flex-\[1_0_0\]{flex:1 0 0}.flex-none{flex:none}.flex-shrink-0,.shrink-0{flex-shrink:0}.flex-grow{flex-grow:1}.-translate-x-1\/2{--tw-translate-x:-50%}.-translate-x-1\/2,.-translate-y-1\/2{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.-translate-y-1\/2{--tw-translate-y:-50%}.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}@keyframes pulse{50%{opacity:.5}}.animate-pulse{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite}@keyframes spin{to{transform:rotate(1turn)}}.animate-spin{animation:spin 1s linear infinite}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.touch-pan-y{--tw-pan-y:pan-y;touch-action:var(--tw-pan-x) var(--tw-pan-y) var(--tw-pinch-zoom)}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.resize-none{resize:none}.resize{resize:both}.list-inside{list-style-position:inside}.list-decimal{list-style-type:decimal}.list-disc{list-style-type:disc}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.grid-cols-\[repeat\(1\2c 100px\)\]{grid-template-columns:repeat(1,100px)}.grid-cols-\[repeat\(2\2c 100px\)\]{grid-template-columns:repeat(2,100px)}.grid-cols-\[repeat\(3\2c 100px\)\]{grid-template-columns:repeat(3,100px)}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-0\.5{gap:.125rem}.gap-1{gap:.25rem}.gap-1\.5{gap:.375rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-4{gap:1rem}.gap-\[7px\]{gap:7px}.gap-px{gap:1px}.gap-y-5{row-gap:1.25rem}.self-end{align-self:flex-end}.self-center{align-self:center}.self-stretch{align-self:stretch}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.overflow-y-auto{overflow-y:auto}.overflow-x-hidden{overflow-x:hidden}.truncate{overflow:hidden;text-overflow:ellipsis}.truncate,.whitespace-nowrap{white-space:nowrap}.whitespace-pre-line{white-space:pre-line}.whitespace-pre-wrap{white-space:pre-wrap}.break-normal{overflow-wrap:normal;word-break:normal}.\!rounded-lg{border-radius:.5rem!important}.rounded{border-radius:.25rem}.rounded-2xl{border-radius:1rem}.rounded-\[12px\]{border-radius:12px}.rounded-\[20px\]{border-radius:20px}.rounded-\[32px\]{border-radius:32px}.rounded-\[4px\]{border-radius:4px}.rounded-\[8px\]{border-radius:8px}.rounded-full{border-radius:9999px}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-xl{border-radius:.75rem}.rounded-r-xl{border-top-right-radius:.75rem;border-bottom-right-radius:.75rem}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-bl-none{border-bottom-left-radius:0}.rounded-br-none{border-bottom-right-radius:0}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-b{border-bottom-width:1px}.border-l-4{border-left-width:4px}.border-r{border-right-width:1px}.border-t{border-top-width:1px}.border-none{border-style:none}.\!border-danger-400{--tw-border-opacity:1!important;border-color:rgb(240 68 56/var(--tw-border-opacity,1))!important}.\!border-gray-25{--tw-border-opacity:1!important;border-color:rgb(239 239 239/var(--tw-border-opacity,1))!important}.\!border-primary-400{--tw-border-opacity:1!important;border-color:rgb(27 63 228/var(--tw-border-opacity,1))!important}.border-blue-500{--tw-border-opacity:1;border-color:rgb(40 138 230/var(--tw-border-opacity,1))}.border-gray-100{--tw-border-opacity:1;border-color:rgb(194 197 199/var(--tw-border-opacity,1))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(168 173 175/var(--tw-border-opacity,1))}.border-gray-200\/20{border-color:hsla(197,4%,67%,.2)}.border-gray-25{--tw-border-opacity:1;border-color:rgb(239 239 239/var(--tw-border-opacity,1))}.border-gray-300{--tw-border-opacity:1;border-color:rgb(142 148 150/var(--tw-border-opacity,1))}.border-gray-50{--tw-border-opacity:1;border-color:rgb(221 222 223/var(--tw-border-opacity,1))}.border-gray-900\/10{border-color:rgba(57,62,64,.1)}.border-indigo-500{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity,1))}.border-orange-300{--tw-border-opacity:1;border-color:rgb(253 186 116/var(--tw-border-opacity,1))}.border-primary-200{--tw-border-opacity:1;border-color:rgb(96 124 251/var(--tw-border-opacity,1))}.border-primary-400{--tw-border-opacity:1;border-color:rgb(27 63 228/var(--tw-border-opacity,1))}.border-primary-500{--tw-border-opacity:1;border-color:rgb(15 51 214/var(--tw-border-opacity,1))}.border-white{--tw-border-opacity:1;border-color:rgb(255 255 255/var(--tw-border-opacity,1))}.border-t-transparent{border-top-color:transparent}.\!bg-amber-100{--tw-bg-opacity:1!important;background-color:rgb(254 243 199/var(--tw-bg-opacity,1))!important}.\!bg-amber-500{--tw-bg-opacity:1!important;background-color:rgb(245 158 11/var(--tw-bg-opacity,1))!important}.\!bg-blue-100{--tw-bg-opacity:1!important;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))!important}.\!bg-blue-500{--tw-bg-opacity:1!important;background-color:rgb(40 138 230/var(--tw-bg-opacity,1))!important}.\!bg-danger-400{--tw-bg-opacity:1!important;background-color:rgb(240 68 56/var(--tw-bg-opacity,1))!important}.\!bg-gray-100{--tw-bg-opacity:1!important;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))!important}.\!bg-gray-25{--tw-bg-opacity:1!important;background-color:rgb(239 239 239/var(--tw-bg-opacity,1))!important}.\!bg-gray-500{--tw-bg-opacity:1!important;background-color:rgb(104 111 114/var(--tw-bg-opacity,1))!important}.\!bg-green-100{--tw-bg-opacity:1!important;background-color:rgb(246 255 237/var(--tw-bg-opacity,1))!important}.\!bg-green-500{--tw-bg-opacity:1!important;background-color:rgb(38 191 135/var(--tw-bg-opacity,1))!important}.\!bg-orange-100{--tw-bg-opacity:1!important;background-color:rgb(255 237 213/var(--tw-bg-opacity,1))!important}.\!bg-orange-500{--tw-bg-opacity:1!important;background-color:rgb(249 115 22/var(--tw-bg-opacity,1))!important}.\!bg-primary-400{--tw-bg-opacity:1!important;background-color:rgb(27 63 228/var(--tw-bg-opacity,1))!important}.\!bg-purple-100{--tw-bg-opacity:1!important;background-color:rgb(249 240 255/var(--tw-bg-opacity,1))!important}.\!bg-purple-500{--tw-bg-opacity:1!important;background-color:rgb(146 84 222/var(--tw-bg-opacity,1))!important}.\!bg-red-100{--tw-bg-opacity:1!important;background-color:rgb(254 226 226/var(--tw-bg-opacity,1))!important}.\!bg-red-500{--tw-bg-opacity:1!important;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))!important}.bg-\[\#f5f5f5\]{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-\[\#f5f5f5\]\/20{background-color:hsla(0,0%,96%,.2)}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity,1))}.bg-black\/10{background-color:rgba(0,0,0,.1)}.bg-black\/30{background-color:rgba(0,0,0,.3)}.bg-black\/5{background-color:rgba(0,0,0,.05)}.bg-black\/50{background-color:rgba(0,0,0,.5)}.bg-black\/60{background-color:rgba(0,0,0,.6)}.bg-black\/70{background-color:rgba(0,0,0,.7)}.bg-blue-100{--tw-bg-opacity:1;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))}.bg-blue-25{--tw-bg-opacity:1;background-color:rgb(234 245 255/var(--tw-bg-opacity,1))}.bg-blue-300{--tw-bg-opacity:1;background-color:rgb(89 171 255/var(--tw-bg-opacity,1))}.bg-blue-50{--tw-bg-opacity:1;background-color:rgb(198 226 255/var(--tw-bg-opacity,1))}.bg-blue-500{--tw-bg-opacity:1;background-color:rgb(40 138 230/var(--tw-bg-opacity,1))}.bg-chat-bubble-mine\/10{background-color:rgba(0,81,255,.1)}.bg-chat-bubble-neutral\/10{background-color:rgba(131,137,157,.1)}.bg-chat-bubble-neutral\/\[0\.05\]{background-color:rgba(131,137,157,.05)}.bg-chat-internal\/10{background-color:rgba(255,149,0,.1)}.bg-chat-send{--tw-bg-opacity:1;background-color:rgb(0 43 235/var(--tw-bg-opacity,1))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.bg-gray-200\/10{background-color:hsla(197,4%,67%,.1)}.bg-gray-25{--tw-bg-opacity:1;background-color:rgb(239 239 239/var(--tw-bg-opacity,1))}.bg-gray-400{--tw-bg-opacity:1;background-color:rgb(116 123 126/var(--tw-bg-opacity,1))}.bg-gray-500{--tw-bg-opacity:1;background-color:rgb(104 111 114/var(--tw-bg-opacity,1))}.bg-gray-900{--tw-bg-opacity:1;background-color:rgb(57 62 64/var(--tw-bg-opacity,1))}.bg-gray-cool-200{--tw-bg-opacity:1;background-color:rgb(169 178 208/var(--tw-bg-opacity,1))}.bg-gray-cool-25{--tw-bg-opacity:1;background-color:rgb(241 243 248/var(--tw-bg-opacity,1))}.bg-neutral-100{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.bg-neutral-200{--tw-bg-opacity:1;background-color:rgb(229 229 229/var(--tw-bg-opacity,1))}.bg-orange-50{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.bg-orange-900{--tw-bg-opacity:1;background-color:rgb(242 133 4/var(--tw-bg-opacity,1))}.bg-primary-25{--tw-bg-opacity:1;background-color:rgb(230 233 255/var(--tw-bg-opacity,1))}.bg-primary-400{--tw-bg-opacity:1;background-color:rgb(27 63 228/var(--tw-bg-opacity,1))}.bg-primary-400\/60{background-color:rgba(27,63,228,.6)}.bg-primary-50{--tw-bg-opacity:1;background-color:rgb(184 194 255/var(--tw-bg-opacity,1))}.bg-primary-500{--tw-bg-opacity:1;background-color:rgb(15 51 214/var(--tw-bg-opacity,1))}.bg-red-500{--tw-bg-opacity:1;background-color:rgb(239 68 68/var(--tw-bg-opacity,1))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity,1))}.bg-white\/70{background-color:hsla(0,0%,100%,.7)}.bg-gradient-danger-light{background-image:linear-gradient(93deg,#ff7d74,#f04438)}.object-contain{-o-object-fit:contain;object-fit:contain}.object-cover{-o-object-fit:cover;object-fit:cover}.\!p-0{padding:0!important}.p-0{padding:0}.p-1{padding:.25rem}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.px-0{padding-left:0;padding-right:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.px-\[3px\]{padding-left:3px;padding-right:3px}.py-0{padding-top:0;padding-bottom:0}.py-0\.5{padding-top:.125rem;padding-bottom:.125rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-1\.5{padding-top:.375rem;padding-bottom:.375rem}.py-12{padding-top:3rem;padding-bottom:3rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-2\.5{padding-top:.625rem;padding-bottom:.625rem}.py-3{padding-top:.75rem;padding-bottom:.75rem}.py-3\.5{padding-top:.875rem;padding-bottom:.875rem}.py-4{padding-top:1rem;padding-bottom:1rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.py-6{padding-top:1.5rem;padding-bottom:1.5rem}.py-8{padding-top:2rem;padding-bottom:2rem}.py-\[42px\]{padding-top:42px;padding-bottom:42px}.py-\[4px\]{padding-top:4px;padding-bottom:4px}.pb-1{padding-bottom:.25rem}.pb-1\.5{padding-bottom:.375rem}.pb-2{padding-bottom:.5rem}.pb-3{padding-bottom:.75rem}.pb-4{padding-bottom:1rem}.pb-60{padding-bottom:15rem}.pl-0{padding-left:0}.pl-1{padding-left:.25rem}.pl-12{padding-left:3rem}.pl-2{padding-left:.5rem}.pl-3{padding-left:.75rem}.pl-4{padding-left:1rem}.pr-1{padding-right:.25rem}.pr-12{padding-right:3rem}.pr-2{padding-right:.5rem}.pr-3{padding-right:.75rem}.pr-4{padding-right:1rem}.pr-5{padding-right:1.25rem}.pt-0\.5{padding-top:.125rem}.pt-1{padding-top:.25rem}.pt-2{padding-top:.5rem}.pt-3{padding-top:.75rem}.pt-4{padding-top:1rem}.text-left{text-align:left}.text-center{text-align:center}.\!align-\[-4px\]{vertical-align:-4px!important}.\!text-\[16px\]{font-size:16px!important}.text-2xl{font-size:1.5rem;line-height:2rem}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[12px\]{font-size:12px}.text-\[13px\]{font-size:13px}.text-\[14px\]{font-size:14px}.text-\[16px\]{font-size:16px}.text-\[18px\]{font-size:18px}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.\!font-medium{font-weight:500!important}.font-\[510\]{font-weight:510}.font-bold{font-weight:700}.font-light{font-weight:300}.font-medium{font-weight:500}.font-normal{font-weight:400}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-3{line-height:.75rem}.leading-4{line-height:1rem}.leading-\[1\.4\]{line-height:1.4}.leading-\[1\.6\]{line-height:1.6}.leading-\[160\%\]{line-height:160%}.leading-none{line-height:1}.tracking-\[-0\.14px\]{letter-spacing:-.14px}.tracking-\[0\.12px\]{letter-spacing:.12px}.tracking-\[0\.14px\]{letter-spacing:.14px}.tracking-\[0\.16px\]{letter-spacing:.16px}.tracking-\[0\.1px\]{letter-spacing:.1px}.tracking-wide{letter-spacing:.025em}.tracking-wider{letter-spacing:.05em}.\!text-amber-500{--tw-text-opacity:1!important;color:rgb(245 158 11/var(--tw-text-opacity,1))!important}.\!text-blue-500{--tw-text-opacity:1!important;color:rgb(40 138 230/var(--tw-text-opacity,1))!important}.\!text-gray-500{--tw-text-opacity:1!important;color:rgb(104 111 114/var(--tw-text-opacity,1))!important}.\!text-gray-900{--tw-text-opacity:1!important;color:rgb(57 62 64/var(--tw-text-opacity,1))!important}.\!text-green-500{--tw-text-opacity:1!important;color:rgb(38 191 135/var(--tw-text-opacity,1))!important}.\!text-orange-400{--tw-text-opacity:1!important;color:rgb(251 146 60/var(--tw-text-opacity,1))!important}.\!text-orange-500{--tw-text-opacity:1!important;color:rgb(249 115 22/var(--tw-text-opacity,1))!important}.\!text-purple-500{--tw-text-opacity:1!important;color:rgb(146 84 222/var(--tw-text-opacity,1))!important}.\!text-red-500{--tw-text-opacity:1!important;color:rgb(239 68 68/var(--tw-text-opacity,1))!important}.\!text-white{--tw-text-opacity:1!important;color:rgb(255 255 255/var(--tw-text-opacity,1))!important}.text-amber-500{--tw-text-opacity:1;color:rgb(245 158 11/var(--tw-text-opacity,1))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity,1))}.text-blue-500{--tw-text-opacity:1;color:rgb(40 138 230/var(--tw-text-opacity,1))}.text-blue-600{--tw-text-opacity:1;color:rgb(27 122 204/var(--tw-text-opacity,1))}.text-chat-bubble-mine{--tw-text-opacity:1;color:rgb(0 81 255/var(--tw-text-opacity,1))}.text-chat-bubble-neutral{--tw-text-opacity:1;color:rgb(131 137 157/var(--tw-text-opacity,1))}.text-chat-internal{--tw-text-opacity:1;color:rgb(255 149 0/var(--tw-text-opacity,1))}.text-danger-400{--tw-text-opacity:1;color:rgb(240 68 56/var(--tw-text-opacity,1))}.text-gray-300{--tw-text-opacity:1;color:rgb(142 148 150/var(--tw-text-opacity,1))}.text-gray-400{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.text-gray-500{--tw-text-opacity:1;color:rgb(104 111 114/var(--tw-text-opacity,1))}.text-gray-600{--tw-text-opacity:1;color:rgb(92 99 102/var(--tw-text-opacity,1))}.text-gray-700{--tw-text-opacity:1;color:rgb(80 87 89/var(--tw-text-opacity,1))}.text-gray-800{--tw-text-opacity:1;color:rgb(68 74 77/var(--tw-text-opacity,1))}.text-gray-900{--tw-text-opacity:1;color:rgb(57 62 64/var(--tw-text-opacity,1))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity,1))}.text-orange-500{--tw-text-opacity:1;color:rgb(249 115 22/var(--tw-text-opacity,1))}.text-orange-600{--tw-text-opacity:1;color:rgb(234 88 12/var(--tw-text-opacity,1))}.text-primary-400{--tw-text-opacity:1;color:rgb(27 63 228/var(--tw-text-opacity,1))}.text-primary-500{--tw-text-opacity:1;color:rgb(15 51 214/var(--tw-text-opacity,1))}.text-red-500{--tw-text-opacity:1;color:rgb(239 68 68/var(--tw-text-opacity,1))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity,1))}.underline{text-decoration-line:underline}.line-through{text-decoration-line:line-through}.underline-offset-2{text-underline-offset:2px}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-30{opacity:.3}.opacity-40{opacity:.4}.opacity-50{opacity:.5}.opacity-60{opacity:.6}.\!shadow-none{--tw-shadow:0 0 #0000!important;--tw-shadow-colored:0 0 #0000!important;box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)!important}.shadow-badge-inset{--tw-shadow:inset 2px 6px 8px 0 rgba(0,0,0,.4);--tw-shadow-colored:inset 2px 6px 8px 0 var(--tw-shadow-color)}.shadow-badge-inset,.shadow-inset-gray-divider{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-inset-gray-divider{--tw-shadow:inset 0px -1px 0px 0px rgba(61,63,64,.1);--tw-shadow-colored:inset 0px -1px 0px 0px var(--tw-shadow-color)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-lg,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color)}.shadow-primary-focus{--tw-shadow:0px 0px 2px rgba(27,63,228,.5);--tw-shadow-colored:0px 0px 2px var(--tw-shadow-color)}.shadow-primary-focus,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.outline-none{outline:2px solid transparent;outline-offset:2px}.ring-0{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.blur{--tw-blur:blur(8px)}.blur,.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.backdrop-blur-sm{--tw-backdrop-blur:blur(4px);backdrop-filter:var(--tw-backdrop-blur) var(--tw-backdrop-brightness) var(--tw-backdrop-contrast) var(--tw-backdrop-grayscale) var(--tw-backdrop-hue-rotate) var(--tw-backdrop-invert) var(--tw-backdrop-opacity) var(--tw-backdrop-saturate) var(--tw-backdrop-sepia)}.transition-colors{transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-none{transition-property:none}.transition-opacity{transition-property:opacity;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-shadow{transition-property:box-shadow;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s}.transition-transform{transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-150,.transition-transform{transition-duration:.15s}.duration-200{transition-duration:.2s}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[font-feature-settings\:\'liga\'_off\2c \'clig\'_off\]{font-feature-settings:"liga" off,"clig" off}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.ant-tabs-tab{margin:0!important;min-width:80px!important;justify-content:center!important;align-items:center!important}.ant-tabs-content,.ant-tabs-content-holder,.ant-tabs-tabpane{height:100%}.zoom-in-out-element{animation:zoom-in-zoom-out 1.5s ease none}@keyframes zoom-in-zoom-out{0%{scale:100%}25%{scale:125%}50%{scale:100%}75%{scale:125%}to{scale:100%}}.conversation-message-input-scrollbar{-moz-appearance:none!important;-webkit-appearance:none!important;appearance:none!important;background:transparent!important;border:0!important;box-shadow:none!important;outline:none!important;scrollbar-width:thin;scrollbar-color:rgba(40,43,54,.3) transparent}.conversation-message-input-scrollbar:active,.conversation-message-input-scrollbar:focus,.conversation-message-input-scrollbar:focus-visible{background:transparent!important;border:0!important;border-color:transparent!important;box-shadow:none!important;outline:none!important;--tw-ring-color:transparent!important;--tw-ring-offset-shadow:0 0 #0000!important;--tw-ring-shadow:0 0 #0000!important}.placeholder\:text-gray-400::-moz-placeholder{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.placeholder\:text-gray-400::placeholder{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.last\:border-b-0:last-child{border-bottom-width:0}.focus-within\:border-chat-focus:focus-within{--tw-border-opacity:1;border-color:rgb(50 120 247/var(--tw-border-opacity,1))}.focus-within\:shadow-chat-focus-ring:focus-within{--tw-shadow:0 0 0 2px rgba(50,120,247,.12);--tw-shadow-colored:0 0 0 2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.hover\:rounded-sm:hover{border-radius:.125rem}.hover\:\!border-danger-300:hover{--tw-border-opacity:1!important;border-color:rgb(250 95 84/var(--tw-border-opacity,1))!important}.hover\:\!border-primary-300:hover{--tw-border-opacity:1!important;border-color:rgb(60 92 241/var(--tw-border-opacity,1))!important}.hover\:\!bg-danger-300:hover{--tw-bg-opacity:1!important;background-color:rgb(250 95 84/var(--tw-bg-opacity,1))!important}.hover\:\!bg-primary-300:hover{--tw-bg-opacity:1!important;background-color:rgb(60 92 241/var(--tw-bg-opacity,1))!important}.hover\:bg-\[\#f5f5f5\]:hover{--tw-bg-opacity:1;background-color:rgb(245 245 245/var(--tw-bg-opacity,1))}.hover\:bg-black\/70:hover{background-color:rgba(0,0,0,.7)}.hover\:bg-blue-100:hover{--tw-bg-opacity:1;background-color:rgb(161 208 255/var(--tw-bg-opacity,1))}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.hover\:bg-primary-100:hover{--tw-bg-opacity:1;background-color:rgb(138 158 255/var(--tw-bg-opacity,1))}.hover\:text-blue-700:hover{--tw-text-opacity:1;color:rgb(17 107 179/var(--tw-text-opacity,1))}.hover\:text-gray-600:hover{--tw-text-opacity:1;color:rgb(92 99 102/var(--tw-text-opacity,1))}.hover\:text-gray-700:hover{--tw-text-opacity:1;color:rgb(80 87 89/var(--tw-text-opacity,1))}.hover\:text-primary-500:hover{--tw-text-opacity:1;color:rgb(15 51 214/var(--tw-text-opacity,1))}.hover\:underline:hover{text-decoration-line:underline}.hover\:opacity-80:hover{opacity:.8}.focus\:border-0:focus{border-width:0}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-2:focus-visible{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus-visible\:ring-chat-ring:focus-visible{--tw-ring-opacity:1;--tw-ring-color:rgb(22 119 255/var(--tw-ring-opacity,1))}.active\:bg-chat-bubble-neutral\/\[0\.08\]:active{background-color:rgba(131,137,157,.08)}.active\:bg-primary-400\/90:active{background-color:rgba(27,63,228,.9)}.disabled\:cursor-not-allowed:disabled{cursor:not-allowed}.disabled\:border-gray-200:disabled{--tw-border-opacity:1;border-color:rgb(168 173 175/var(--tw-border-opacity,1))}.disabled\:bg-gray-100:disabled{--tw-bg-opacity:1;background-color:rgb(194 197 199/var(--tw-bg-opacity,1))}.disabled\:bg-gray-200:disabled{--tw-bg-opacity:1;background-color:rgb(168 173 175/var(--tw-bg-opacity,1))}.disabled\:text-gray-300:disabled{--tw-text-opacity:1;color:rgb(142 148 150/var(--tw-text-opacity,1))}.disabled\:text-gray-400:disabled{--tw-text-opacity:1;color:rgb(116 123 126/var(--tw-text-opacity,1))}.disabled\:opacity-60:disabled{opacity:.6}@media (min-width:640px){.sm\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:px-4{padding-left:1rem;padding-right:1rem}}.\[\&\>svg\]\:h-6>svg{height:1.5rem}.\[\&\>svg\]\:h-8>svg{height:2rem}.\[\&\>svg\]\:h-full>svg{height:100%}.\[\&\>svg\]\:w-6>svg{width:1.5rem}.\[\&\>svg\]\:w-8>svg{width:2rem}.\[\&\>svg\]\:w-auto>svg{width:auto}.\[\&_\.ant-dropdown-menu-item\]\:rounded-none .ant-dropdown-menu-item{border-radius:0}.\[\&_\.ant-dropdown-menu-item\]\:\!px-4 .ant-dropdown-menu-item{padding-left:1rem!important;padding-right:1rem!important}.\[\&_\.ant-dropdown-menu-item\]\:\!py-1\.5 .ant-dropdown-menu-item{padding-top:.375rem!important;padding-bottom:.375rem!important}.\[\&_\.ant-dropdown-menu\]\:min-w-\[200px\] .ant-dropdown-menu{min-width:200px}.\[\&_\.ant-dropdown-menu\]\:rounded-2xl .ant-dropdown-menu{border-radius:1rem}.\[\&_\.ant-dropdown-menu\]\:p-0 .ant-dropdown-menu{padding:0}.\[\&_\.ant-dropdown-menu\]\:py-2 .ant-dropdown-menu{padding-top:.5rem;padding-bottom:.5rem}.\[\&_\.ant-dropdown-menu\]\:shadow-message-toolbox .ant-dropdown-menu{--tw-shadow:0px 0px 24px 0px rgba(14,28,52,.1);--tw-shadow-colored:0px 0px 24px 0px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.\[\&_\.ant-tabs-content-holder\]\:hidden .ant-tabs-content-holder{display:none}.\[\&_\.ant-tabs-extra-content\]\:flex .ant-tabs-extra-content{display:flex}.\[\&_\.ant-tabs-extra-content\]\:items-center .ant-tabs-extra-content{align-items:center}.\[\&_\.ant-tabs-extra-content\]\:overflow-hidden .ant-tabs-extra-content{overflow:hidden}.\[\&_\.ant-tabs-extra-content\]\:text-ellipsis .ant-tabs-extra-content{text-overflow:ellipsis}.\[\&_\.ant-tabs-ink-bar\]\:hidden .ant-tabs-ink-bar{display:none}.\[\&_\.ant-tabs-nav-wrap\]\:justify-end .ant-tabs-nav-wrap{justify-content:flex-end}.\[\&_\.ant-tabs-nav\]\:mb-0 .ant-tabs-nav{margin-bottom:0}.\[\&_\.ant-tabs-nav\]\:px-4 .ant-tabs-nav{padding-left:1rem;padding-right:1rem}.\[\&_\.ant-tabs-nav\]\:pt-0 .ant-tabs-nav{padding-top:0}.\[\&_\.ant-tabs-nav\]\:before\:border-b-0 .ant-tabs-nav:before{content:var(--tw-content);border-bottom-width:0}.\[\&_\.ant-tabs-tab-active\]\:border-indigo-200 .ant-tabs-tab-active{--tw-border-opacity:1;border-color:rgb(199 210 254/var(--tw-border-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:border-orange-200 .ant-tabs-tab-active{--tw-border-opacity:1;border-color:rgb(254 215 170/var(--tw-border-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:bg-indigo-50 .ant-tabs-tab-active{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity,1))}.\[\&_\.ant-tabs-tab-active\]\:bg-orange-50 .ant-tabs-tab-active{--tw-bg-opacity:1;background-color:rgb(255 247 237/var(--tw-bg-opacity,1))}.\[\&_\.ant-tabs-tab-btn\]\:leading-5 .ant-tabs-tab-btn{line-height:1.25rem}.\[\&_\.ant-tabs-tab\]\:mb-0 .ant-tabs-tab{margin-bottom:0}.\[\&_\.ant-tabs-tab\]\:rounded-t-\[16px\] .ant-tabs-tab{border-top-left-radius:16px;border-top-right-radius:16px}.\[\&_\.ant-tabs-tab\]\:border .ant-tabs-tab{border-width:1px}.\[\&_\.ant-tabs-tab\]\:border-b-0 .ant-tabs-tab{border-bottom-width:0}.\[\&_\.ant-tabs-tab\]\:border-transparent .ant-tabs-tab{border-color:transparent}.\[\&_\.ant-tabs-tab\]\:px-3 .ant-tabs-tab{padding-left:.75rem;padding-right:.75rem}.\[\&_\.ant-tabs-tab\]\:py-1\.5 .ant-tabs-tab{padding-top:.375rem;padding-bottom:.375rem}.\[\&_\.ant-tabs-tab\]\:leading-5 .ant-tabs-tab{line-height:1.25rem}.\[\&_code\]\:font-\[inherit\] code,.\[\&_kbd\]\:font-\[inherit\] kbd,.\[\&_pre\]\:font-\[inherit\] pre,.\[\&_samp\]\:font-\[inherit\] samp{font-family:inherit}
@@ -34,6 +34,7 @@ interface FormatOptions {
34
34
  dateMonthFormat?: string;
35
35
  }
36
36
  export declare function formatTimestamp(timestamp: number, options?: FormatOptions): string;
37
+ export declare function formatDividerTimestamp(timestamp: number): string;
37
38
  export declare const urlRegex: RegExp;
38
39
  export declare function wrapLinksInHtml(htmlContent: string): string;
39
40
  export declare const getHostFromUrl: (url: string) => string | null;
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACZ,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAqB,eAAe,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOhD,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,EACnB,WAAW,MAAM,KAChB,MAAmE,CAAC;AAEvE,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,CAAC,CAQlE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,eAAe,GAAG,SAQhE,CAAC;AAmCF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,UAAU,sBAAsB;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,UAAS,sBAA2B,WAoBrC,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAC5C,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,IAAI,SAAS,EACb,YAAY;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EACpD,aAAa;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,WAwC1D,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,YAAY,MAAM,KAAG,OAS5D,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,eAAe,gBAAgB,EAAE,EACjC,OAAO,OAAO,KACb,gBAAgB,EAMlB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,IAAI,SAAS,EACb,eAAe;IAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAClE,UAAU;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAE,WAuG5C,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,kBAAc,WA2Cf,CAAC;AAEF,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAqBR;AAED,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqC3D;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAC;AAKF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,OACf,CAAC;AAEnC,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAO9B,CAAC;AAEZ;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgEjD"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/utils/common.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAEhB,WAAW,EACZ,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAqB,eAAe,EAAE,MAAM,cAAc,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAOhD,eAAO,MAAM,iBAAiB,GAC5B,aAAa,MAAM,EACnB,WAAW,MAAM,KAChB,MAAmE,CAAC;AAEvE,eAAO,MAAM,mBAAmB,GAAI,CAAC,EAAE,UAAU,MAAM,KAAG,OAAO,CAAC,CAAC,CAQlE,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,KAAK,MAAM,KAAG,eAAe,GAAG,SAQhE,CAAC;AAmCF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAItD;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAapD;AAED,UAAU,sBAAsB;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,OAAO,MAAM,EACb,UAAS,sBAA2B,WAoBrC,CAAC;AAEF,eAAO,MAAM,iCAAiC,GAC5C,aAAa,WAAW,EACxB,YAAY,MAAM,EAClB,IAAI,SAAS,EACb,YAAY;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EACpD,aAAa;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,WAwC1D,CAAC;AAEF,eAAO,MAAM,uBAAuB,GAAI,YAAY,MAAM,KAAG,OAS5D,CAAC;AAEF,eAAO,MAAM,2BAA2B,GACtC,eAAe,gBAAgB,EAAE,EACjC,OAAO,OAAO,KACb,gBAAgB,EAMlB,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,WAAW,MAAM,EACjB,gBAAgB,MAAM,EACtB,IAAI,SAAS,EACb,eAAe;IAAE,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,EAClE,UAAU;IAAE,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAAE,WAuG5C,CAAC;AAEF,eAAO,MAAM,eAAe,GAC1B,MAAM,MAAM,EACZ,SAAS,MAAM,EACf,kBAAc,WA2Cf,CAAC;AAEF,UAAU,aAAa;IACrB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,aAAa,GACtB,MAAM,CAqBR;AAMD,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAiBhE;AAED,eAAO,MAAM,QAAQ,QAAkD,CAAC;AAExE,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAqC3D;AAED,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,KAAG,MAAM,GAAG,IAOrD,CAAC;AAKF,eAAO,MAAM,iBAAiB,GAAI,MAAM,MAAM,KAAG,OACf,CAAC;AAEnC,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MAO9B,CAAC;AAEZ;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAgEjD"}
@@ -267,6 +267,24 @@ export function formatTimestamp(timestamp, options) {
267
267
  ? date.format(`HH:mm ${dateMonthFormat} YYYY`)
268
268
  : date.format(`${dateMonthFormat} YYYY`);
269
269
  }
270
+ // Date/time divider format for the message thread (AC-D1): "HH:mm Hôm nay" /
271
+ // "HH:mm Hôm qua" / "HH:mm DD/MM" / "HH:mm DD/MM/YYYY". Kept separate from
272
+ // formatTimestamp, which other UI (conversation list, search) relies on for
273
+ // its compact HH:mm-only-when-today behavior.
274
+ export function formatDividerTimestamp(timestamp) {
275
+ const date = dayjs.tz(timestamp);
276
+ const now = dayjs.tz();
277
+ if (date.isSame(now, "day")) {
278
+ return `${date.format("HH:mm")} Hôm nay`;
279
+ }
280
+ if (date.isSame(now.subtract(1, "day"), "day")) {
281
+ return `${date.format("HH:mm")} Hôm qua`;
282
+ }
283
+ if (date.isSame(now, "year")) {
284
+ return date.format("HH:mm DD/MM");
285
+ }
286
+ return date.format("HH:mm DD/MM/YYYY");
287
+ }
270
288
  export const urlRegex = /\bhttps?:\/\/[^\s<>"']*[^\s<>"',.!?()\[\]{}]/g;
271
289
  export function wrapLinksInHtml(htmlContent) {
272
290
  var _a;
@@ -1 +1 @@
1
- {"version":3,"file":"fileValidation.d.ts","sourceRoot":"","sources":["../../src/utils/fileValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,UAAU,EAAE,MAAM,MAAM,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,eAAO,MAAM,oBAAoB,UAA2C,CAAC;AAC7E,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,mBAAmB,UAI/B,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,SAAS,CAAC;IACb,oBAAoB,CAAC,EAAE,UAAU,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,IAAI,EACV,GAAG,SAAS,KACX,oBAuBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,IAAI,EAAE,EAChB,sBAAsB,UAAU,EAAE,EAClC,GAAG,SAAS,KACX,oBAYF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,KAAG,UAO5C,CAAC;AAEH,eAAO,MAAM,2BAA2B,GACtC,OAAO,IAAI,EAAE,EACb,GAAG,SAAS,KACX,UAAU,EA4BZ,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,IAAI,EAAE,EACb,SAAS,qBAAqB,KAC7B,UAAU,EA+BZ,CAAC"}
1
+ {"version":3,"file":"fileValidation.d.ts","sourceRoot":"","sources":["../../src/utils/fileValidation.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,UAAU,EAAE,MAAM,MAAM,CAAC;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAEpC,eAAO,MAAM,oBAAoB,UAAyD,CAAC;AAC3F,eAAO,MAAM,iBAAiB,KAAK,CAAC;AACpC,eAAO,MAAM,iBAAiB,MAAM,CAAC;AACrC,eAAO,MAAM,oBAAoB,KAAK,CAAC;AACvC,eAAO,MAAM,mBAAmB,UAI/B,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,SAAS,CAAC;IACb,oBAAoB,CAAC,EAAE,UAAU,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,IAAI,EACV,GAAG,SAAS,KACX,oBAuBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,GAC7B,UAAU,IAAI,EAAE,EAChB,sBAAsB,UAAU,EAAE,EAClC,GAAG,SAAS,KACX,oBAYF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAI,MAAM,IAAI,KAAG,UAO5C,CAAC;AAEH,eAAO,MAAM,2BAA2B,GACtC,OAAO,IAAI,EAAE,EACb,GAAG,SAAS,KACX,UAAU,EA4BZ,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,OAAO,IAAI,EAAE,EACb,SAAS,qBAAqB,KAC7B,UAAU,EA+BZ,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import { message as antdMessage } from "antd";
2
- export const ACCEPTED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/jpg"];
2
+ export const ACCEPTED_IMAGE_TYPES = ["image/jpeg", "image/png", "image/jpg", "image/webp"];
3
3
  export const MAX_IMAGE_SIZE_MB = 15;
4
4
  export const MAX_VIDEO_SIZE_MB = 200;
5
5
  export const MAX_DOCUMENT_SIZE_MB = 20;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droppii-org/chat-sdk",
3
- "version": "0.3.6",
3
+ "version": "0.3.7",
4
4
  "description": "Droppii React Chat SDK",
5
5
  "repository": {
6
6
  "type": "git",