@droppii-org/chat-sdk 0.7.4 → 0.7.6

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 (90) hide show
  1. package/dist/assets/images/defaultAvatarGroup.png +0 -0
  2. package/dist/components/conversation/ConversationByGroupItem.d.ts.map +1 -1
  3. package/dist/components/conversation/ConversationByGroupItem.js +2 -2
  4. package/dist/components/conversation/ConversationBySessionItem.d.ts.map +1 -1
  5. package/dist/components/conversation/ConversationBySessionItem.js +3 -3
  6. package/dist/components/conversation/DeskBackgroundSyncStatus.d.ts +4 -0
  7. package/dist/components/conversation/DeskBackgroundSyncStatus.d.ts.map +1 -0
  8. package/dist/components/conversation/DeskBackgroundSyncStatus.js +17 -0
  9. package/dist/components/conversation/DeskConversationList.d.ts.map +1 -1
  10. package/dist/components/conversation/DeskConversationList.js +13 -3
  11. package/dist/components/conversation-detail/ConversationMessageList.d.ts.map +1 -1
  12. package/dist/components/conversation-detail/ConversationMessageList.js +3 -6
  13. package/dist/components/conversation-detail/PinnedMessagesPanel.d.ts.map +1 -1
  14. package/dist/components/conversation-detail/PinnedMessagesPanel.js +1 -1
  15. package/dist/components/conversation-detail/bot/BotMenuSheet.d.ts.map +1 -1
  16. package/dist/components/conversation-detail/bot/BotMenuSheet.js +1 -1
  17. package/dist/components/conversation-inbox/ConversationPeerAvatar.d.ts.map +1 -1
  18. package/dist/components/conversation-inbox/ConversationPeerAvatar.js +3 -1
  19. package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.d.ts.map +1 -1
  20. package/dist/components/conversation-inbox/contact-search/PublicGroupResultItem.js +3 -2
  21. package/dist/components/conversation-inbox/contact-search/constants.d.ts +0 -1
  22. package/dist/components/conversation-inbox/contact-search/constants.d.ts.map +1 -1
  23. package/dist/components/conversation-inbox/contact-search/constants.js +0 -2
  24. package/dist/components/conversation-inbox/contact-search/index.d.ts +0 -1
  25. package/dist/components/conversation-inbox/contact-search/index.d.ts.map +1 -1
  26. package/dist/components/conversation-inbox/contact-search/index.js +0 -1
  27. package/dist/components/group/GroupAvatar.d.ts +9 -0
  28. package/dist/components/group/GroupAvatar.d.ts.map +1 -0
  29. package/dist/components/group/GroupAvatar.js +13 -0
  30. package/dist/components/group/JoinGroupConfirmModal.d.ts.map +1 -1
  31. package/dist/components/group/JoinGroupConfirmModal.js +3 -2
  32. package/dist/components/message/MessageHeader.d.ts.map +1 -1
  33. package/dist/components/message/MessageHeader.js +2 -2
  34. package/dist/components/message/MessageList.d.ts.map +1 -1
  35. package/dist/components/message/MessageList.js +8 -6
  36. package/dist/components/search-conversation/item/SearchItemAsGroup.d.ts.map +1 -1
  37. package/dist/components/search-conversation/item/SearchItemAsGroup.js +2 -2
  38. package/dist/components/search-conversation/item/SearchItemAsMessage.d.ts.map +1 -1
  39. package/dist/components/search-conversation/item/SearchItemAsMessage.js +3 -1
  40. package/dist/components/thread/GroupInfoBodyCrm.d.ts +0 -2
  41. package/dist/components/thread/GroupInfoBodyCrm.d.ts.map +1 -1
  42. package/dist/components/thread/GroupInfoBodyCrm.js +2 -2
  43. package/dist/components/thread/GroupThreadInfo.d.ts.map +1 -1
  44. package/dist/components/thread/GroupThreadInfo.js +2 -2
  45. package/dist/constants/images.d.ts +1 -0
  46. package/dist/constants/images.d.ts.map +1 -1
  47. package/dist/constants/images.js +3 -0
  48. package/dist/hooks/conversation/useResolveConversation.d.ts.map +1 -1
  49. package/dist/hooks/conversation/useResolveConversation.js +2 -5
  50. package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
  51. package/dist/hooks/global/useGlobalEvent.js +2 -0
  52. package/dist/hooks/group/useCreateGroup.d.ts.map +1 -1
  53. package/dist/hooks/group/useCreateGroup.js +2 -3
  54. package/dist/hooks/init/useCanLoadChatData.d.ts +7 -0
  55. package/dist/hooks/init/useCanLoadChatData.d.ts.map +1 -0
  56. package/dist/hooks/init/useCanLoadChatData.js +15 -0
  57. package/dist/hooks/message/useCanPinMessage.d.ts +2 -0
  58. package/dist/hooks/message/useCanPinMessage.d.ts.map +1 -0
  59. package/dist/hooks/message/useCanPinMessage.js +29 -0
  60. package/dist/hooks/message/useMessage.d.ts.map +1 -1
  61. package/dist/hooks/message/useMessage.js +3 -5
  62. package/dist/hooks/message/useUnreadMessageIndicator.d.ts.map +1 -1
  63. package/dist/hooks/message/useUnreadMessageIndicator.js +3 -5
  64. package/dist/hooks/session/useAgentSupportThreadJoin.d.ts +1 -0
  65. package/dist/hooks/session/useAgentSupportThreadJoin.d.ts.map +1 -1
  66. package/dist/hooks/session/useAgentSupportThreadJoin.js +13 -2
  67. package/dist/hooks/session/useSessionLatestPreview.d.ts +4 -1
  68. package/dist/hooks/session/useSessionLatestPreview.d.ts.map +1 -1
  69. package/dist/hooks/session/useSessionLatestPreview.js +4 -1
  70. package/dist/locales/vi/boot.json +3 -2
  71. package/dist/locales/vi/common.json +1 -0
  72. package/dist/screens/conversation-detail/index.d.ts.map +1 -1
  73. package/dist/screens/conversation-detail/index.js +3 -1
  74. package/dist/screens/desk-message/DeskWorkspace.d.ts +3 -1
  75. package/dist/screens/desk-message/DeskWorkspace.d.ts.map +1 -1
  76. package/dist/screens/desk-message/DeskWorkspace.js +4 -4
  77. package/dist/screens/desk-message/index.d.ts +2 -0
  78. package/dist/screens/desk-message/index.d.ts.map +1 -1
  79. package/dist/screens/desk-message/index.js +26 -8
  80. package/dist/store/boot.d.ts +15 -0
  81. package/dist/store/boot.d.ts.map +1 -1
  82. package/dist/store/boot.js +20 -2
  83. package/dist/styles/global.css +1 -1
  84. package/package.json +1 -1
  85. package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts +0 -9
  86. package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.d.ts.map +0 -1
  87. package/dist/components/conversation-inbox/contact-search/PublicGroupAvatar.js +0 -19
  88. package/dist/components/group/GroupCompositeAvatar.d.ts +0 -11
  89. package/dist/components/group/GroupCompositeAvatar.d.ts.map +0 -1
  90. package/dist/components/group/GroupCompositeAvatar.js +0 -87
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationByGroupItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationByGroupItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAaxF,UAAU,4BAA4B;IACpC,KAAK,EAAE,4BAA4B,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,uBAAuB,GAAI,2BAG9B,4BAA4B,4CA8D9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationByGroupItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationByGroupItem.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAaxF,UAAU,4BAA4B;IACpC,KAAK,EAAE,4BAA4B,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,uBAAuB,GAAI,2BAG9B,4BAA4B,4CA6D9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -5,7 +5,7 @@ import useConversationStore from "../../store/conversation";
5
5
  import { useChatContext } from "../../context/ChatContext";
6
6
  import { useDeskThreadNavigation } from "../../hooks/conversation/useDeskThreadNavigation";
7
7
  import { parseLatestMessage } from "../../utils/common";
8
- import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
8
+ import GroupAvatar from "../../components/group/GroupAvatar";
9
9
  import DeskConversationRow from "./DeskConversationRow";
10
10
  import { GroupVisibility } from "@droppii-org/wasm-client-sdk";
11
11
  import { StrokeIcon } from "../../components/icon/StrokeIcon";
@@ -33,6 +33,6 @@ const ConversationByGroupItem = ({ group, latestPreview, }) => {
33
33
  showName: conversation.showName,
34
34
  }), mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: conversation.groupAtType }), time: latestMsgSendTime > 0
35
35
  ? formatListRowTime(latestMsgSendTime, t)
36
- : undefined, avatar: _jsx(GroupCompositeAvatar, { groupID: group.groupId, faceURL: conversation.faceURL, groupName: conversation.showName, size: 40 }), name: conversation.showName, meta: group.visibility === GroupVisibility.Private ? (_jsxs(RowChip, { tone: "primary", children: [_jsx(StrokeIcon, { name: "lock", size: 14 }), t("group_visibility_private")] })) : undefined }));
36
+ : undefined, avatar: _jsx(GroupAvatar, { faceURL: conversation.faceURL, groupName: conversation.showName, size: 40 }), name: conversation.showName, meta: group.visibility === GroupVisibility.Private ? (_jsxs(RowChip, { tone: "primary", children: [_jsx(StrokeIcon, { name: "lock", size: 14 }), t("group_visibility_private")] })) : undefined }));
37
37
  };
38
38
  export default ConversationByGroupItem;
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQhD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAU1C,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qFAAqF;IACrF,SAAS,CAAC,EAAE,UAAU,CAAC;CACxB;AAaD,QAAA,MAAM,yBAAyB,GAAI,4CAIhC,8BAA8B,mDAiGhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
1
+ {"version":3,"file":"ConversationBySessionItem.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/ConversationBySessionItem.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yCAAyC,CAAC;AAE7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAQhD,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAU1C,UAAU,8BAA8B;IACtC,WAAW,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,qFAAqF;IACrF,SAAS,CAAC,EAAE,UAAU,CAAC;CACxB;AAaD,QAAA,MAAM,yBAAyB,GAAI,4CAIhC,8BAA8B,mDAgGhC,CAAC;AAEF,eAAe,yBAAyB,CAAC"}
@@ -6,10 +6,10 @@ import useConversationStore from "../../store/conversation";
6
6
  import { useChatContext } from "../../context/ChatContext";
7
7
  import { useDeskThreadNavigation } from "../../hooks/conversation/useDeskThreadNavigation";
8
8
  import { useConversationDisplayData } from "../../hooks/conversation/useConversation";
9
- import { isGroupSession } from "../../utils/imCommon";
9
+ import { isGroupConversation } from "../../utils/imCommon";
10
10
  import { resolveBotSessionOwnerIdentity } from "../../utils/conversation";
11
11
  import { SessionTag } from "../../types/chat";
12
- import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
12
+ import GroupAvatar from "../../components/group/GroupAvatar";
13
13
  import DeskConversationRow from "./DeskConversationRow";
14
14
  import { formatListRowTime } from "./rowTime";
15
15
  import DeskRowAvatar from "./DeskRowAvatar";
@@ -69,6 +69,6 @@ const ConversationBySessionItem = ({ sessionItem, latestPreview, folderTag, }) =
69
69
  showName: conversation.showName,
70
70
  }), mentionIndicator: _jsx(MentionIndicatorIcon, { groupAtType: conversation.groupAtType }), time: latestMsgSendTime > 0
71
71
  ? formatListRowTime(latestMsgSendTime, t)
72
- : undefined, avatar: !ownerIdentity && isGroupSession(conversation.conversationType) ? (_jsx(GroupCompositeAvatar, { groupID: conversation.groupID, faceURL: avatar, groupName: displayName, size: 40 })) : (_jsx(DeskRowAvatar, { name: name, src: ownerIdentity ? ownerIdentity.avatarUrl : avatar })), name: name, nameTooltip: fullTitle, meta: tagChip ? (_jsx(RowChip, { tone: tagChip.tone, children: t(tagChip.labelKey) })) : undefined }));
72
+ : undefined, avatar: !ownerIdentity && isGroupConversation(conversation) ? (_jsx(GroupAvatar, { faceURL: avatar, groupName: displayName, size: 40 })) : (_jsx(DeskRowAvatar, { name: name, src: ownerIdentity ? ownerIdentity.avatarUrl : avatar })), name: name, nameTooltip: fullTitle, meta: tagChip ? (_jsx(RowChip, { tone: tagChip.tone, children: t(tagChip.labelKey) })) : undefined }));
73
73
  };
74
74
  export default ConversationBySessionItem;
@@ -0,0 +1,4 @@
1
+ /** Under the list header while a fresh device's first sync keeps pulling the other conversations. */
2
+ declare const DeskBackgroundSyncStatus: () => import("react/jsx-runtime").JSX.Element | null;
3
+ export default DeskBackgroundSyncStatus;
4
+ //# sourceMappingURL=DeskBackgroundSyncStatus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DeskBackgroundSyncStatus.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskBackgroundSyncStatus.tsx"],"names":[],"mappings":"AAQA,qGAAqG;AACrG,QAAA,MAAM,wBAAwB,sDA+B7B,CAAC;AAEF,eAAe,wBAAwB,CAAC"}
@@ -0,0 +1,17 @@
1
+ "use client";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useTranslation } from "react-i18next";
4
+ import BootProgressBar from "../../components/boot/BootProgressBar";
5
+ import useBootStore, { CONVERSATIONS_SYNCED_PROGRESS, selectIsSyncingInBackground, } from "../../store/boot";
6
+ /** Under the list header while a fresh device's first sync keeps pulling the other conversations. */
7
+ const DeskBackgroundSyncStatus = () => {
8
+ const { t } = useTranslation("boot");
9
+ const isSyncing = useBootStore(selectIsSyncingInBackground);
10
+ const progress = useBootStore((state) => state.syncProgress);
11
+ if (!isSyncing)
12
+ return null;
13
+ // Core reports exactly 10 when the conversations are stored; only later values say much.
14
+ const showPercent = progress > CONVERSATIONS_SYNCED_PROGRESS;
15
+ return (_jsxs("div", { "data-cp-name": "DeskBackgroundSyncStatus", className: "flex flex-col gap-1.5 border-b border-gray-25 px-4 py-2", children: [_jsxs("p", { role: "status", className: "m-0 flex items-center gap-2 text-xs text-gray-600", children: [_jsx("span", { "aria-hidden": "true", className: "h-3 w-3 shrink-0 rounded-full border-2 border-primary-25 border-t-primary-400 motion-safe:animate-spin" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: t("desk.background_sync") }), showPercent && (_jsxs("span", { className: "font-semibold tabular-nums text-primary-400", children: [progress, "%"] }))] }), _jsx(BootProgressBar, { mode: showPercent ? "progress" : "indeterminate", value: progress, label: t("sync_progress_label") })] }));
16
+ };
17
+ export default DeskBackgroundSyncStatus;
@@ -1 +1 @@
1
- {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AA+BA,UAAU,yBAAyB;IACjC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD;AAED,QAAA,MAAM,oBAAoB,GAAI,mBAAmB,yBAAyB,4CAiRzE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
1
+ {"version":3,"file":"DeskConversationList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/DeskConversationList.tsx"],"names":[],"mappings":"AAiCA,UAAU,yBAAyB;IACjC,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,KAAK,IAAI,CAAC;CACtD;AAED,QAAA,MAAM,oBAAoB,GAAI,mBAAmB,yBAAyB,4CA2RzE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
@@ -20,10 +20,12 @@ import { DChatSDK } from "../../constants/sdk";
20
20
  import emitter from "../../utils/events";
21
21
  import { useGetSessionSummary } from "../../hooks/session/useGetSessionSummary";
22
22
  import { getActiveFolder } from "../../store/sessionFolder";
23
+ import useBootStore from "../../store/boot";
23
24
  import { ALL_GROUPS_KEY } from "../../components/session/sessionFilters";
24
25
  import DeskListHeader from "./DeskListHeader";
25
26
  import DeskListEmptyState from "./DeskListEmptyState";
26
27
  import DeskListSkeleton from "./DeskListSkeleton";
28
+ import DeskBackgroundSyncStatus from "./DeskBackgroundSyncStatus";
27
29
  import { getListHeading } from "./listHeading";
28
30
  import ComposeNewMessageModal from "../../components/compose/ComposeNewMessageModal";
29
31
  import { useCloseOnSidePanelOpen } from "../../hooks/common/useCloseOnSidePanelOpen";
@@ -46,9 +48,9 @@ const DeskConversationList = ({ onOpenAppMenu }) => {
46
48
  options: { isEnabled: !isAllGroupsView },
47
49
  });
48
50
  const { groups: conversationGroups, fetchNextPage: fetchNextGroupsPage, hasNextPage: hasNextGroupsPage, isLoading: isConversationGroupsLoading, } = useConversationGroups({ enabled: isAllGroupsView });
49
- const latestPreviewMap = useSessionLatestPreview(rawSessions);
51
+ const { previews: latestPreviewMap, isLoading: isSessionPreviewLoading } = useSessionLatestPreview(rawSessions);
50
52
  const sessions = useSortedSessions(rawSessions, latestPreviewMap);
51
- const groupLatestPreviewMap = useSessionLatestPreview(conversationGroups);
53
+ const { previews: groupLatestPreviewMap, isLoading: isGroupPreviewLoading } = useSessionLatestPreview(conversationGroups);
52
54
  const { data: mySummary } = useGetSessionSummary();
53
55
  const folder = getActiveFolder(filterSummary, viewMode);
54
56
  const heading = getListHeading({ folder, mySummary, teams: teamSummaries });
@@ -56,6 +58,14 @@ const DeskConversationList = ({ onOpenAppMenu }) => {
56
58
  const isListLoading = isAllGroupsView
57
59
  ? isConversationGroupsLoading
58
60
  : isSessionsLoading || isSyncing;
61
+ // The desk keeps its boot screen until the rows on screen have their conversation and preview.
62
+ const isFirstScreenLoaded = isAllGroupsView
63
+ ? !isConversationGroupsLoading && !isGroupPreviewLoading
64
+ : !isSessionsLoading && !isSyncing && !isSessionPreviewLoading;
65
+ useEffect(() => {
66
+ if (isFirstScreenLoaded)
67
+ useBootStore.getState().markFirstScreenReady();
68
+ }, [isFirstScreenLoaded]);
59
69
  const debouncedSearch = useDebounce(search, { wait: 500 });
60
70
  // Closing hands focus back to the field (drawer focus restore, Esc); that focus
61
71
  // must not reopen the search it just closed.
@@ -150,7 +160,7 @@ const DeskConversationList = ({ onOpenAppMenu }) => {
150
160
  if (!showSearch && value)
151
161
  setShowSearchTrue();
152
162
  setSearch(value);
153
- }, onSearchFocus: onSearchFocus, onCloseSearch: onCloseSearch, onCompose: () => setIsComposeOpen(true), onOpenAppMenu: onOpenAppMenu }), _jsxs("div", { className: "relative flex-1 min-h-0", children: [_jsx("div", { id: "scrollableConversationsDiv", "aria-busy": isListLoading, style: {
163
+ }, onSearchFocus: onSearchFocus, onCloseSearch: onCloseSearch, onCompose: () => setIsComposeOpen(true), onOpenAppMenu: onOpenAppMenu }), _jsx(DeskBackgroundSyncStatus, {}), _jsxs("div", { className: "relative flex-1 min-h-0", children: [_jsx("div", { id: "scrollableConversationsDiv", "aria-busy": isListLoading, style: {
154
164
  height: "100%",
155
165
  overflow: showSearch ? "hidden" : "auto",
156
166
  }, children: isAllGroupsView ? (isConversationGroupsLoading ? (_jsx(DeskListSkeleton, { rows: 8 })) : !(conversationGroups === null || conversationGroups === void 0 ? void 0 : conversationGroups.length) ? (_jsx(DeskListEmptyState, { filterKey: emptyFilterKey })) : (_jsx(InfiniteScroll, { dataLength: conversationGroups.length, next: fetchNextGroupsPage, hasMore: !!hasNextGroupsPage, loader: _jsx(DeskListSkeleton, { rows: 2 }), scrollableTarget: "scrollableConversationsDiv", children: _jsx("div", { className: "flex flex-col gap-0.5 px-1 pb-2", children: conversationGroups.map((group) => (_jsx(ConversationByGroupItem, { group: group, latestPreview: groupLatestPreviewMap.get(group.conversationId) }, group.groupId))) }) }))) : isSessionsLoading || (isSyncing && !(sessions === null || sessions === void 0 ? void 0 : sessions.length)) ? (
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAiCf,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,4DAI9B,4BAA4B,4CAsS9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
1
+ {"version":3,"file":"ConversationMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/ConversationMessageList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAiCf,MAAM,WAAW,4BAA4B;IAC3C,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;CACrC;AAED,QAAA,MAAM,uBAAuB,GAAI,4DAI9B,4BAA4B,4CAkS9B,CAAC;AAEF,eAAe,uBAAuB,CAAC"}
@@ -11,7 +11,7 @@ import { useMessageListScroll } from "../../hooks/message/useMessageListScroll";
11
11
  import { useUnreadMessageIndicator } from "../../hooks/message/useUnreadMessageIndicator";
12
12
  import { usePinMessage } from "../../hooks/message/usePinMessage";
13
13
  import { useRevokeMessage } from "../../hooks/message/useRevokeMessage";
14
- import { useGroupPermission } from "../../hooks/group/useGroupPermission";
14
+ import { useCanPinMessage } from "../../hooks/message/useCanPinMessage";
15
15
  import { useViewOnlyGroupRefresh } from "../../hooks/conversation/useViewOnlyGroupRefresh";
16
16
  import { useConsultantChatNavigation } from "../../hooks/conversation/useConsultantChatNavigation";
17
17
  import useConversationStore from "../../store/conversation";
@@ -27,7 +27,7 @@ import PinLimitModal from "./PinLimitModal";
27
27
  const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessageRevoked, }) => {
28
28
  const { t } = useTranslation("conversation-inbox");
29
29
  const { t: tCommon } = useTranslation();
30
- const { user, allowPinMessageWithoutPermission } = useChatContext();
30
+ const { user } = useChatContext();
31
31
  const authUserID = useAuthStore((state) => state.userID);
32
32
  const conversation = useConversationStore((state) => state.conversationData);
33
33
  const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
@@ -37,10 +37,7 @@ const ConversationMessageList = ({ bottomSlot, onCopyMessageLink, onSearchMessag
37
37
  const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
38
38
  const conversationId = selectedConversationId || (conversation === null || conversation === void 0 ? void 0 : conversation.conversationID) || "";
39
39
  const isGroupChat = conversation ? resolveIsGroupChat(conversation) : false;
40
- const permissions = useGroupPermission(conversation === null || conversation === void 0 ? void 0 : conversation.groupID);
41
- // Some hosts run pin without their backend returning PIN_MESSAGE yet, so
42
- // the permission check would hide a feature that is live for them.
43
- const canPinMessage = !isGroupChat || permissions.pinMessage || allowPinMessageWithoutPermission;
40
+ const canPinMessage = useCanPinMessage();
44
41
  const viewerUserID = (user === null || user === void 0 ? void 0 : user.userID) || authUserID;
45
42
  const isAgentView = isSupportSessionAgentView(Object.assign(Object.assign({}, conversation), { conversationID: conversationId }), viewerUserID);
46
43
  // App history strips the assignment log and session dividers, which an
@@ -1 +1 @@
1
- {"version":3,"file":"PinnedMessagesPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessagesPanel.tsx"],"names":[],"mappings":"AAYA,UAAU,wBAAwB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,8BAI1B,wBAAwB,4CAmH1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"PinnedMessagesPanel.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-detail/PinnedMessagesPanel.tsx"],"names":[],"mappings":"AAYA,UAAU,wBAAwB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,8BAI1B,wBAAwB,4CAoH1B,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -57,6 +57,6 @@ const PinnedMessagesPanel = ({ open, onClose, canUnpin = true, }) => {
57
57
  borderTopRightRadius: 16,
58
58
  overflow: "hidden",
59
59
  },
60
- }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-lg font-bold text-gray-900", children: t("pinned_panel_title") }), _jsx(Button, { type: "text", shape: "default", className: "h-6 w-6 p-0 text-gray-900", onClick: onClose, "aria-label": t("pinned_panel_title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto py-3", children: [_jsx("p", { className: "px-3 text-sm leading-[160%] text-gray-600", children: t("pinned_panel_hint") }), pinnedMessageList.map((message) => (_jsx(PinnedMessageItem, { message: message, contextMenuOpen: openContextMenuId === message.clientMsgID, onContextMenuOpenChange: (isOpen) => setOpenContextMenuId(isOpen ? message.clientMsgID : null), onUnpin: handleUnpin, onJump: handleJump, canUnpin: canUnpin }, message.clientMsgID)))] }, openCount)] }) }));
60
+ }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex h-full flex-col bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-lg font-bold text-gray-900", children: t("pinned_panel_title") }), _jsx(Button, { type: "text", shape: "default", className: "!h-6 !w-6 !p-0 text-gray-900", onClick: onClose, "aria-label": t("pinned_panel_title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsxs("div", { className: "flex flex-1 flex-col gap-3 overflow-y-auto py-3", children: [_jsx("p", { className: "px-3 text-sm leading-[160%] text-gray-600", children: t(canUnpin ? "pinned_panel_hint" : "pinned_panel_hint_view_only") }), pinnedMessageList.map((message) => (_jsx(PinnedMessageItem, { message: message, contextMenuOpen: openContextMenuId === message.clientMsgID, onContextMenuOpenChange: (isOpen) => setOpenContextMenuId(isOpen ? message.clientMsgID : null), onUnpin: handleUnpin, onJump: handleJump, canUnpin: canUnpin }, message.clientMsgID)))] }, openCount)] }) }));
61
61
  };
62
62
  export default PinnedMessagesPanel;
@@ -1 +1 @@
1
- {"version":3,"file":"BotMenuSheet.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotMenuSheet.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,+CAMnB,iBAAiB,4CAkEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"BotMenuSheet.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-detail/bot/BotMenuSheet.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI5D,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,eAAe,EAAE,CAAC;IACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;CAC3C;AAED,QAAA,MAAM,YAAY,GAAI,+CAMnB,iBAAiB,4CAmEnB,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -17,7 +17,7 @@ const BotMenuSheet = ({ open, items, disabled, onClose, onSelect, }) => {
17
17
  body: { padding: "16px 16px 32px" },
18
18
  mask: { backgroundColor: "rgba(0, 0, 0, 0.8)" },
19
19
  content: { background: "transparent", boxShadow: "none" },
20
- }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex flex-col overflow-hidden rounded-2xl bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.bot.menu.title") }), _jsx(Button, { type: "text", shape: "default", className: "h-6 w-6 p-0 text-gray-900", onClick: onClose, "aria-label": t("thread_detail.bot.menu.title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsx("div", { className: "flex flex-col", children: items.map((item, index) => (_jsxs("button", { type: "button", disabled: disabled, onClick: () => handleSelect(item), className: "flex items-center gap-4 border-b border-gray-25 px-3 py-3 text-left transition-colors last:border-b-0 disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx("span", { className: "flex-1 text-[16px] font-medium leading-[1.6] text-gray-900", children: item.id === BOT_DEFAULT_BUTTON_ID
20
+ }, getContainer: false, forceRender: true, children: _jsxs("div", { className: "flex flex-col overflow-hidden rounded-2xl bg-white", children: [_jsxs("div", { className: "flex items-center gap-4 border-b border-gray-25 px-3 py-4", children: [_jsx("span", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("thread_detail.bot.menu.title") }), _jsx(Button, { type: "text", shape: "default", className: "!h-6 !w-6 !p-0 text-gray-900", onClick: onClose, "aria-label": t("thread_detail.bot.menu.title"), children: _jsx(Icon, { icon: "close-b", size: 24 }) })] }), _jsx("div", { className: "flex flex-col", children: items.map((item, index) => (_jsxs("button", { type: "button", disabled: disabled, onClick: () => handleSelect(item), className: "flex items-center gap-4 border-b border-gray-25 px-3 py-3 text-left transition-colors last:border-b-0 disabled:cursor-not-allowed disabled:opacity-60", children: [_jsx("span", { className: "flex-1 text-[16px] font-medium leading-[1.6] text-gray-900", children: item.id === BOT_DEFAULT_BUTTON_ID
21
21
  ? t("thread_detail.bot.restart")
22
22
  : item.label }), _jsx(Icon, { icon: "angle-right-o", size: CHEVRON_SIZE, className: "text-gray-900" })] }, `${item.id}-${index}`))) })] }) }));
23
23
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ConversationPeerAvatar.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationPeerAvatar.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAGhD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,sBAAsB,GAAI,mDAK7B,2BAA2B,4CA4B7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"ConversationPeerAvatar.d.ts","sourceRoot":"","sources":["../../../src/components/conversation-inbox/ConversationPeerAvatar.tsx"],"names":[],"mappings":"AAIA,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAIhD,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,EAAE,QAAQ,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,sBAAsB,GAAI,mDAK7B,2BAA2B,4CAgC7B,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
@@ -2,9 +2,11 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import clsx from "clsx";
4
4
  import { Avatar } from "antd";
5
+ import { PeerType } from "../../types/conversation";
5
6
  import { resolvePeerBadgeColor } from "../../utils/conversation";
7
+ import GroupAvatar from "../../components/group/GroupAvatar";
6
8
  const ConversationPeerAvatar = ({ peerType, displayName, avatarUrl, badgeLabel, }) => {
7
9
  const badge = badgeLabel ? (_jsx("span", { className: clsx("absolute -bottom-px -right-px flex h-[17px] items-center justify-center gap-2 rounded-md border border-white px-1 text-[10px] font-semibold leading-3 text-white shadow-badge-inset", resolvePeerBadgeColor(peerType)), children: badgeLabel })) : null;
8
- return (_jsxs("div", { className: "relative h-12 w-12 shrink-0", "data-cp-name": "ConversationPeerAvatar", children: [_jsx(Avatar, { size: 48, src: avatarUrl || undefined, alt: displayName, className: "uppercase", children: (displayName === null || displayName === void 0 ? void 0 : displayName.charAt(0)) || "A" }), badge] }));
10
+ return (_jsxs("div", { className: "relative h-12 w-12 shrink-0", "data-cp-name": "ConversationPeerAvatar", children: [peerType === PeerType.GROUP ? (_jsx(GroupAvatar, { faceURL: avatarUrl, groupName: displayName, size: 48 })) : (_jsx(Avatar, { size: 48, src: avatarUrl || undefined, alt: displayName, className: "uppercase", children: (displayName === null || displayName === void 0 ? void 0 : displayName.charAt(0)) || "A" })), badge] }));
9
11
  };
10
12
  export default ConversationPeerAvatar;
@@ -1 +1 @@
1
- {"version":3,"file":"PublicGroupResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupResultItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAI1E,UAAU,0BAA0B;IAClC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,qBAAqB,GAAI,oBAG5B,0BAA0B,4CA2E5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"PublicGroupResultItem.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/PublicGroupResultItem.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AAK1E,UAAU,0BAA0B;IAClC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED,QAAA,MAAM,qBAAqB,GAAI,oBAG5B,0BAA0B,4CA4E5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -4,7 +4,8 @@ import clsx from "clsx";
4
4
  import { Spin } from "antd";
5
5
  import { useTranslation } from "react-i18next";
6
6
  import { useJoinPublicGroup } from "../../../hooks/group/useJoinPublicGroup";
7
- import PublicGroupAvatar from "./PublicGroupAvatar";
7
+ import GroupAvatar from "../../../components/group/GroupAvatar";
8
+ import { CONTACT_SEARCH_AVATAR_SIZE } from "./constants";
8
9
  const PublicGroupResultItem = ({ group, onOpen, }) => {
9
10
  var _a, _b;
10
11
  const { t } = useTranslation("conversation-inbox");
@@ -17,7 +18,7 @@ const PublicGroupResultItem = ({ group, onOpen, }) => {
17
18
  }
18
19
  joinGroup({ groupID: group.groupID }, { onSuccess: () => onOpen(group.groupID) });
19
20
  };
20
- return (_jsxs("div", { "data-cp-name": "PublicGroupResultItem", "data-testid": `contact-search-public-group-${group.groupID}`, className: "flex items-center gap-2 border-b border-gray-25 bg-white p-3", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 text-left", onClick: () => onOpen(group.groupID), children: [_jsx(PublicGroupAvatar, { faceURL: group.faceURL, groupName: group.groupName, members: group.members }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1 pb-0.5", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-black", children: group.groupName }), _jsxs("span", { className: "flex min-w-0 flex-col text-[14px] leading-[1.6] tracking-[0.14px] text-gray-600", children: [_jsx("span", { className: "truncate", children: t("contact_search.member_count", {
21
+ return (_jsxs("div", { "data-cp-name": "PublicGroupResultItem", "data-testid": `contact-search-public-group-${group.groupID}`, className: "flex items-center gap-2 border-b border-gray-25 bg-white p-3", children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 text-left", onClick: () => onOpen(group.groupID), children: [_jsx(GroupAvatar, { faceURL: group.faceURL, groupName: group.groupName, size: CONTACT_SEARCH_AVATAR_SIZE, className: "shrink-0" }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col gap-1 pb-0.5", children: [_jsx("span", { className: "truncate text-[16px] font-medium leading-[1.6] text-black", children: group.groupName }), _jsxs("span", { className: "flex min-w-0 flex-col text-[14px] leading-[1.6] tracking-[0.14px] text-gray-600", children: [_jsx("span", { className: "truncate", children: t("contact_search.member_count", {
21
22
  count: (_a = group.memberCount) !== null && _a !== void 0 ? _a : 0,
22
23
  }) }), _jsx("span", { className: "truncate", children: ((_b = group.introduction) === null || _b === void 0 ? void 0 : _b.trim()) ||
23
24
  t("contact_search.public_group_fallback") })] })] })] }), _jsxs("button", { type: "button", disabled: isPending, "data-testid": `contact-search-public-group-action-${group.groupID}`, className: clsx("flex h-7 shrink-0 items-center justify-center gap-2 rounded-lg px-3", "whitespace-nowrap text-center text-[12px] font-medium leading-[1.6] tracking-[0.12px]", group.isJoined
@@ -2,7 +2,6 @@ import { ContactSearchType } from "../../../types/dto";
2
2
  export declare const CONTACT_SEARCH_DEBOUNCE_MS = 300;
3
3
  export declare const CONTACT_SEARCH_ICON_SIZE = 18;
4
4
  export declare const CONTACT_SEARCH_AVATAR_SIZE = 48;
5
- export declare const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
6
5
  export declare const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
7
6
  export declare enum ContactSearchTab {
8
7
  All = "ALL",
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAG7C,eAAO,MAAM,gCAAgC,KAAK,CAAC;AAInD,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE;IAChC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,eAAO,MAAM,0BAA0B,MAAM,CAAC;AAE9C,eAAO,MAAM,wBAAwB,KAAK,CAAC;AAE3C,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAI7C,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,oBAAY,gBAAgB;IAC1B,GAAG,QAAQ;IACX,QAAQ,aAAa;IACrB,QAAQ,aAAa;IACrB,SAAS,cAAc;CACxB;AAED,eAAO,MAAM,mBAAmB,EAAE;IAChC,GAAG,EAAE,gBAAgB,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC;AAEF,eAAO,MAAM,sBAAsB,EAAE;IACnC,IAAI,EAAE,iBAAiB,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;CAClB,EAKA,CAAC"}
@@ -2,8 +2,6 @@ import { ContactSearchType } from "../../../types/dto";
2
2
  export const CONTACT_SEARCH_DEBOUNCE_MS = 300;
3
3
  export const CONTACT_SEARCH_ICON_SIZE = 18;
4
4
  export const CONTACT_SEARCH_AVATAR_SIZE = 48;
5
- // The two overlapping circles of the public-group composite avatar.
6
- export const PUBLIC_GROUP_STACKED_AVATAR_SIZE = 33;
7
5
  // `Tất cả` shows a capped preview of the contact section before handing the
8
6
  // seller over to the full `Liên hệ` tab.
9
7
  export const CONTACT_SEARCH_PREVIEW_LIMIT = 5;
@@ -6,7 +6,6 @@ export { default as ContactSearchTabs } from "./ContactSearchTabs";
6
6
  export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
7
7
  export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
8
8
  export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
9
- export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
10
9
  export * from "./constants";
11
10
  export * from "./utils";
12
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/conversation-inbox/contact-search/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,yBAAyB,EAAE,MAAM,6BAA6B,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AACrF,OAAO,EAAE,OAAO,IAAI,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAC3E,cAAc,aAAa,CAAC;AAC5B,cAAc,SAAS,CAAC"}
@@ -6,6 +6,5 @@ export { default as ContactSearchTabs } from "./ContactSearchTabs";
6
6
  export { default as ContactSearchSectionHeader } from "./ContactSearchSectionHeader";
7
7
  export { default as ContactSearchViewMoreBar } from "./ContactSearchViewMoreBar";
8
8
  export { default as PublicGroupResultItem } from "./PublicGroupResultItem";
9
- export { default as PublicGroupAvatar } from "./PublicGroupAvatar";
10
9
  export * from "./constants";
11
10
  export * from "./utils";
@@ -0,0 +1,9 @@
1
+ interface GroupAvatarProps {
2
+ faceURL?: string | null;
3
+ groupName?: string;
4
+ size?: number;
5
+ className?: string;
6
+ }
7
+ declare const GroupAvatar: ({ faceURL, groupName, size, className }: GroupAvatarProps) => import("react/jsx-runtime").JSX.Element;
8
+ export default GroupAvatar;
9
+ //# sourceMappingURL=GroupAvatar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"GroupAvatar.d.ts","sourceRoot":"","sources":["../../../src/components/group/GroupAvatar.tsx"],"names":[],"mappings":"AAMA,UAAU,gBAAgB;IACxB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,QAAA,MAAM,WAAW,GAAI,yCAA8C,gBAAgB,4CAclF,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -0,0 +1,13 @@
1
+ "use client";
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import { useState } from "react";
4
+ import clsx from "clsx";
5
+ import { images } from "../../constants/images";
6
+ // DROPPII-30928: a group without a photo (or whose photo fails to load) shows
7
+ // the default group image, replacing the owner + member composite of DROPPII-29976.
8
+ const GroupAvatar = ({ faceURL, groupName, size = 56, className }) => {
9
+ const [failedSrc, setFailedSrc] = useState(null);
10
+ const photo = faceURL && faceURL !== failedSrc ? faceURL : null;
11
+ return (_jsx("img", { src: photo !== null && photo !== void 0 ? photo : images.defaultAvatarGroup, alt: groupName !== null && groupName !== void 0 ? groupName : "", "data-testid": photo ? "group-avatar" : "default-group-avatar", style: { width: size, height: size }, className: clsx("shrink-0 rounded-full object-cover", className), onError: photo ? () => setFailedSrc(photo) : undefined }));
12
+ };
13
+ export default GroupAvatar;
@@ -1 +1 @@
1
- {"version":3,"file":"JoinGroupConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/JoinGroupConfirmModal.tsx"],"names":[],"mappings":"AASA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,qBAAqB,GAAI,6EAQ5B,0BAA0B,4CAuE5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"JoinGroupConfirmModal.d.ts","sourceRoot":"","sources":["../../../src/components/group/JoinGroupConfirmModal.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,OAAO,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,qBAAqB,GAAI,6EAQ5B,0BAA0B,4CAqE5B,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -1,8 +1,9 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { Modal, Avatar, Button } from "antd";
3
+ import { Modal, Button } from "antd";
4
4
  import { useTranslation } from "react-i18next";
5
5
  import { Icon } from "../../components/icon";
6
+ import GroupAvatar from "../../components/group/GroupAvatar";
6
7
  const MODAL_WIDTH = 390;
7
8
  const AVATAR_SIZE = 96;
8
9
  const JoinGroupConfirmModal = ({ open, groupName, groupAvatar, memberCount, loading, onConfirm, onClose, }) => {
@@ -10,6 +11,6 @@ const JoinGroupConfirmModal = ({ open, groupName, groupAvatar, memberCount, load
10
11
  return (_jsx(Modal, { "data-cp-name": "JoinGroupConfirmModal", open: open, onCancel: onClose, footer: null, closable: false, centered: true, width: MODAL_WIDTH, maskClosable: !loading, keyboard: !loading, styles: {
11
12
  content: { padding: 0, overflow: "hidden", borderRadius: 16 },
12
13
  body: { padding: 0 },
13
- }, children: _jsxs("div", { role: "dialog", "aria-label": t("join_group_confirm_title"), className: "flex flex-col bg-white", children: [_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-gray-25 p-4", children: [_jsx("p", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("join_group_confirm_title") }), _jsx("button", { type: "button", "aria-label": t("close"), className: "shrink-0", onClick: onClose, disabled: loading, children: _jsx(Icon, { icon: "close-o", size: 24 }) })] }), _jsxs("div", { className: "flex flex-col items-center p-4", children: [_jsx(Avatar, { size: AVATAR_SIZE, src: groupAvatar || undefined, className: "shrink-0 uppercase", children: (groupName === null || groupName === void 0 ? void 0 : groupName.charAt(0)) || "G" }), _jsxs("div", { className: "flex flex-col items-center gap-1 pt-3 text-center", children: [_jsx("p", { className: "max-w-[280px] truncate text-[18px] font-bold leading-[1.6] text-black", children: groupName }), _jsx("p", { className: "text-[16px] leading-[1.6] tracking-[0.16px] text-gray-600", children: t("member_count", { count: memberCount }) })] })] }), _jsx("div", { className: "px-4 pb-4", children: _jsx(Button, { "data-testid": "join-group-confirm", type: "primary", className: "h-12 w-full !rounded-lg !border-[var(--dc-color-primary)] !bg-[var(--dc-color-primary)] !text-[16px] !font-medium !text-white hover:!border-[var(--dc-color-primary-hover)] hover:!bg-[var(--dc-color-primary-hover)]", onClick: onConfirm, loading: loading, children: t("join_group_confirm_cta") }) })] }) }));
14
+ }, children: _jsxs("div", { role: "dialog", "aria-label": t("join_group_confirm_title"), className: "flex flex-col bg-white", children: [_jsxs("div", { className: "flex items-center justify-between gap-4 border-b border-gray-25 p-4", children: [_jsx("p", { className: "flex-1 text-[18px] font-bold leading-[1.6] text-gray-900", children: t("join_group_confirm_title") }), _jsx("button", { type: "button", "aria-label": t("close"), className: "shrink-0", onClick: onClose, disabled: loading, children: _jsx(Icon, { icon: "close-o", size: 24 }) })] }), _jsxs("div", { className: "flex flex-col items-center p-4", children: [_jsx(GroupAvatar, { faceURL: groupAvatar || undefined, groupName: groupName, size: AVATAR_SIZE }), _jsxs("div", { className: "flex flex-col items-center gap-1 pt-3 text-center", children: [_jsx("p", { className: "max-w-[280px] truncate text-[18px] font-bold leading-[1.6] text-black", children: groupName }), _jsx("p", { className: "text-[16px] leading-[1.6] tracking-[0.16px] text-gray-600", children: t("member_count", { count: memberCount }) })] })] }), _jsx("div", { className: "px-4 pb-4", children: _jsx(Button, { "data-testid": "join-group-confirm", type: "primary", className: "h-12 w-full !rounded-lg !border-[var(--dc-color-primary)] !bg-[var(--dc-color-primary)] !text-[16px] !font-medium !text-white hover:!border-[var(--dc-color-primary-hover)] hover:!bg-[var(--dc-color-primary-hover)]", onClick: onConfirm, loading: loading, children: t("join_group_confirm_cta") }) })] }) }));
14
15
  };
15
16
  export default JoinGroupConfirmModal;
@@ -1 +1 @@
1
- {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AASzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgB/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,kEAMpB,kBAAkB,4CAmbpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"MessageHeader.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageHeader.tsx"],"names":[],"mappings":"AAUA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AASzD,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAgB/C,UAAU,kBAAkB;IAC1B,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,cAAc,CAAC,EAAE,gBAAgB,CAAC;IAClC,QAAQ,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,KAAK,sBAAsB,GAAG,aAAa,GAAG,UAAU,CAAC;AAEzD,MAAM,WAAW,mBAAmB;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,sBAAsB,CAAC;IAC9B,kBAAkB,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,QAAA,MAAM,aAAa,GAAI,kEAMpB,kBAAkB,4CAibpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -20,7 +20,7 @@ import { useSidePanel } from "../../hooks/common/useSidePanel";
20
20
  import SearchDrawer from "../../components/search-conversation/SearchDrawer";
21
21
  import { isGroupSession, isGroupConversation } from "../../utils/imCommon";
22
22
  import { useGroupPermission } from "../../hooks/group/useGroupPermission";
23
- import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
23
+ import GroupAvatar from "../../components/group/GroupAvatar";
24
24
  import GroupMembersDrawer from "./GroupMembersDrawer";
25
25
  import { useGroupMembers } from "../../hooks/group/useGroupMembers";
26
26
  import { useBotSessionOwnerIdentity } from "../../hooks/session/useBotSessionOwnerIdentity";
@@ -203,7 +203,7 @@ const MessageHeader = ({ onClose, currentSession, isJoined, onOpenThreadInfo, on
203
203
  setCurrentSessionStatus(currentSession.status);
204
204
  }
205
205
  }, [currentSession]);
206
- const avatarNode = (_jsx(_Fragment, { children: showOwnerPlaceholder ? (_jsx("span", { "aria-hidden": true, className: "h-10 w-10 shrink-0 animate-pulse rounded-full bg-gray-25" })) : ownerIdentity ? (isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: ownerIdentity.avatarUrl, size: 40 })) : (_jsx(Avatar, { src: ownerIdentity.avatarUrl, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_c = headerName === null || headerName === void 0 ? void 0 : headerName.charAt) === null || _c === void 0 ? void 0 : _c.call(headerName, 0)) || "A" }))) : shouldShowMemberCount ? (_jsx(GroupCompositeAvatar, { groupID: conversationData === null || conversationData === void 0 ? void 0 : conversationData.groupID, faceURL: avatar, ownerUserID: currentGroupInfo === null || currentGroupInfo === void 0 ? void 0 : currentGroupInfo.ownerUserID, groupName: displayName, size: 40, className: "min-w-10 min-h-10" })) : isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: avatar, size: 40 })) : (_jsx(Avatar, { src: avatar, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_d = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _d === void 0 ? void 0 : _d.call(displayName, 0)) || "A" })) }));
206
+ const avatarNode = (_jsx(_Fragment, { children: showOwnerPlaceholder ? (_jsx("span", { "aria-hidden": true, className: "h-10 w-10 shrink-0 animate-pulse rounded-full bg-gray-25" })) : ownerIdentity ? (isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: ownerIdentity.avatarUrl, size: 40 })) : (_jsx(Avatar, { src: ownerIdentity.avatarUrl, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_c = headerName === null || headerName === void 0 ? void 0 : headerName.charAt) === null || _c === void 0 ? void 0 : _c.call(headerName, 0)) || "A" }))) : isRealGroup ? (_jsx(GroupAvatar, { faceURL: avatar, groupName: displayName, size: 40, className: "min-w-10 min-h-10" })) : isCrm ? (_jsx(TintedAvatar, { name: headerShortName, src: avatar, size: 40 })) : (_jsx(Avatar, { src: avatar, size: "large", alt: "", className: "min-w-10 min-h-10", children: ((_d = displayName === null || displayName === void 0 ? void 0 : displayName.charAt) === null || _d === void 0 ? void 0 : _d.call(displayName, 0)) || "A" })) }));
207
207
  return (_jsxs("div", { className: `px-4 py-3 flex items-center border-b gap-3 bg-white ${isCrm
208
208
  ? "flex-nowrap border-gray-25 [container-type:inline-size] max-lg:flex-wrap phone:gap-2 phone:px-3"
209
209
  : "flex-wrap"}`, "data-cp-name": "MessageHeader", children: [onBack && (_jsx(Button, { type: "text", shape: "default", "data-desk-back": true, className: "h-10 w-10 shrink-0 p-0 text-gray-900", onClick: onBack, "aria-label": t("back"), children: _jsx(StrokeIcon, { name: "chevron-left", size: 20 }) })), isCrm ? (_jsx("span", { className: "contents phone:hidden", children: avatarNode })) : (avatarNode), _jsxs("div", { className: `flex flex-col overflow-hidden flex-1 ${isCrm ? "min-w-[96px] max-[359px]:min-w-[72px]" : ""}`, children: [showOwnerPlaceholder ? (_jsxs("span", { "aria-hidden": true, className: "flex flex-col gap-1.5 py-0.5", children: [_jsx("span", { className: "h-4 w-36 animate-pulse rounded bg-gray-25" }), _jsx("span", { className: "h-3 w-24 animate-pulse rounded bg-gray-25" })] })) : (_jsx("p", { className: `text-base truncate ${isCrm ? "m-0 font-semibold leading-[normal] text-gray-900" : ""}`, title: headerName || undefined, children: (isCrm ? headerShortName : headerName) || "" })), showMemberCountLine && (_jsx("p", { className: "text-xs text-gray-500 truncate", children: t("member_count", { count: memberCount }) })), isCrm && !showOwnerPlaceholder && metaParts.length > 0 && (_jsx("p", { className: "m-0 flex min-w-0 items-center gap-1 overflow-hidden whitespace-nowrap text-xs text-gray-600 [container-type:inline-size]", "data-testid": "header-meta-line", children: metaParts.map((part, index) => (_jsxs(Fragment, { children: [index > 0 && (_jsx("span", { "aria-hidden": true, className: "h-[3px] w-[3px] shrink-0 rounded-full bg-gray-200" })), part] }, index))) }))] }), _jsxs("div", { className: `flex items-center justify-end ${isCrm
@@ -1 +1 @@
1
- {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,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,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAub3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"MessageList.d.ts","sourceRoot":"","sources":["../../../src/components/message/MessageList.tsx"],"names":[],"mappings":"AAoCA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAIxD,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,CAAC,OAAO,CAAC,EAAE,mBAAmB,KAAK,IAAI,CAAC;IAChE,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,iBAAiB,CAAC,EAAE,CAAC,cAAc,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1E,kGAAkG;IAClG,sBAAsB,CAAC,EAAE,MAAM,IAAI,CAAC;IACpC,uEAAuE;IACvE,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,QAAA,MAAM,WAAW,GAAI,OAAO,gBAAgB,4CAyb3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -74,12 +74,6 @@ const MessageList = (props) => {
74
74
  (!isConfirmedNonMember &&
75
75
  permissions.sendMessage &&
76
76
  !isRestrictedByGroupMute);
77
- // Some hosts run pin without their backend returning PIN_MESSAGE yet, so
78
- // the permission check would hide a feature that is live for them. Group
79
- // membership is still required either way.
80
- const canPinMessage = !isConfirmedGroup ||
81
- (!isConfirmedNonMember &&
82
- (permissions.pinMessage || allowPinMessageWithoutPermission));
83
77
  const setQuotedMessage = useConversationStore((state) => state.setQuotedMessage);
84
78
  const setSearchClientMsgID = useConversationStore((state) => state.setSearchClientMsgID);
85
79
  const [openMenuId, setOpenMenuId] = useState(null);
@@ -104,6 +98,14 @@ const MessageList = (props) => {
104
98
  groupId: rawGroupId,
105
99
  sessionId: latestConversationSession === null || latestConversationSession === void 0 ? void 0 : latestConversationSession.id,
106
100
  });
101
+ // The host flag covers backends without PIN_MESSAGE yet; group membership
102
+ // is still required either way.
103
+ const canPinInGroup = !isConfirmedNonMember &&
104
+ (permissions.pinMessage || !!allowPinMessageWithoutPermission);
105
+ // Only members manage a support thread's pins, so an agent joins first.
106
+ const canPinMessage = isConfirmedGroup
107
+ ? canPinInGroup
108
+ : !rawGroupId || isJoined === true;
107
109
  // A stale isViewOnlyMember=true only ever clears via the WASM join-group
108
110
  // path or a WS event — neither fires for a support thread joined via
109
111
  // useJoinSession's REST call. Sync it off once isJoined confirms true.
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAUxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CA+FvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsGroup.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsGroup.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,qCAAqC,CAAC;AAUxF,UAAU,sBAAsB;IAC9B,KAAK,EAAE,4BAA4B,CAAC;IACpC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,QAAA,MAAM,iBAAiB,GAAI,OAAO,sBAAsB,4CA8FvD,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -9,7 +9,7 @@ import { GroupVisibility } from "@droppii-org/wasm-client-sdk";
9
9
  import useConversationStore from "../../../store/conversation";
10
10
  import { useDeskThreadNavigation } from "../../../hooks/conversation/useDeskThreadNavigation";
11
11
  import { highlightSearch, sanitizeHtml } from "../../../utils/common";
12
- import GroupCompositeAvatar from "../../../components/group/GroupCompositeAvatar";
12
+ import GroupAvatar from "../../../components/group/GroupAvatar";
13
13
  import RowChip from "../../../components/conversation/RowChip";
14
14
  import { StrokeIcon } from "../../../components/icon/StrokeIcon";
15
15
  import { useOpenPdpSearchResult } from "../../../hooks/search/useOpenPdpSearchResult";
@@ -41,7 +41,7 @@ const SearchItemAsGroup = (props) => {
41
41
  newSearchParams.delete("botId");
42
42
  openThread({ threadId: conversation.conversationID }, `${window.location.pathname}?${newSearchParams.toString()}`);
43
43
  };
44
- return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsGroup", children: [_jsx(GroupCompositeAvatar, { groupID: group.groupId, faceURL: conversation.faceURL, groupName: conversation.showName, size: isCrm ? 40 : 48 }), _jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-0.5", children: [_jsx("p", { className: isCrm
44
+ return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsGroup", children: [_jsx(GroupAvatar, { faceURL: conversation.faceURL, groupName: conversation.showName, size: isCrm ? 40 : 48 }), _jsxs("div", { className: "flex flex-col flex-1 min-w-0 gap-0.5", children: [_jsx("p", { className: isCrm
45
45
  ? "m-0 truncate text-sm font-medium text-gray-900"
46
46
  : "text-sm font-semibold truncate", dangerouslySetInnerHTML: {
47
47
  __html: sanitizeHtml(highlightSearch(conversation.showName || "", searchTerm)),
@@ -1 +1 @@
1
- {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AA2BrF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CA+J3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"SearchItemAsMessage.d.ts","sourceRoot":"","sources":["../../../../src/components/search-conversation/item/SearchItemAsMessage.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA4B,MAAM,8BAA8B,CAAC;AA6BrF,UAAU,wBAAwB;IAChC,OAAO,EAAE,WAAW,GAAG;QAAE,SAAS,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;IAC/C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AAED,QAAA,MAAM,mBAAmB,GAAI,OAAO,wBAAwB,4CAqK3D,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -12,6 +12,8 @@ import { useTranslation } from "react-i18next";
12
12
  import useConversationStore from "../../../store/conversation";
13
13
  import { useMemo } from "react";
14
14
  import TintedAvatar from "../../../components/common/TintedAvatar";
15
+ import GroupAvatar from "../../../components/group/GroupAvatar";
16
+ import { isGroupConversation } from "../../../utils/imCommon";
15
17
  import RowChip from "../../../components/conversation/RowChip";
16
18
  import useAuthStore from "../../../store/auth";
17
19
  import { getConversationIdFromMessage } from "../../../utils/conversation";
@@ -94,7 +96,7 @@ const SearchItemAsMessage = (props) => {
94
96
  msgContent = message === null || message === void 0 ? void 0 : message.content;
95
97
  }
96
98
  }
97
- return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsMessage", children: [_jsx("div", { children: isCrm ? (_jsx(TintedAvatar, { name: (_b = (useConversationDisplay
99
+ return (_jsxs("div", Object.assign({ className: searchRowClass(isCrm) }, clickableProps(onPressItem), { "data-cp-name": "SearchItemAsMessage", children: [_jsx("div", { children: !useConversationDisplay && isGroupConversation(conversationData !== null && conversationData !== void 0 ? conversationData : undefined) ? (_jsx(GroupAvatar, { faceURL: conversationData === null || conversationData === void 0 ? void 0 : conversationData.faceURL, groupName: conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName, size: 40 })) : isCrm ? (_jsx(TintedAvatar, { name: (_b = (useConversationDisplay
98
100
  ? message.senderNickname
99
101
  : conversationData === null || conversationData === void 0 ? void 0 : conversationData.showName)) !== null && _b !== void 0 ? _b : "", src: useConversationDisplay
100
102
  ? message.senderFaceUrl
@@ -2,10 +2,8 @@ import type { ChangeEvent } from "react";
2
2
  export type GroupInfoRow = "member-permission" | "admin-permission" | "invite-link";
3
3
  export type GroupInfoConfirm = "leave" | "disband" | "delete";
4
4
  export interface GroupInfoBodyCrmProps {
5
- groupID: string;
6
5
  groupName?: string;
7
6
  faceURL?: string;
8
- ownerUserID?: string;
9
7
  introduction?: string;
10
8
  memberCount?: number;
11
9
  isPublic: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupInfoBodyCrm.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupInfoBodyCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzC,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACtD,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC/D,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC/C;AA6BD,kGAAkG;AAClG,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA8JrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"GroupInfoBodyCrm.d.ts","sourceRoot":"","sources":["../../../src/components/thread/GroupInfoBodyCrm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAUzC,MAAM,MAAM,YAAY,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,aAAa,CAAC;AACpF,MAAM,MAAM,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,QAAQ,CAAC;AAE9D,MAAM,WAAW,qBAAqB;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,WAAW,EAAE,OAAO,CAAC;IACrB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,oBAAoB,EAAE,OAAO,CAAC;IAC9B,cAAc,EAAE,OAAO,CAAC;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,cAAc,EAAE,OAAO,CAAC;IACxB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,aAAa,EAAE,OAAO,CAAC;IACvB,sBAAsB,EAAE,OAAO,CAAC;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAAC;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAClD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,mBAAmB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACrD,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACtD,UAAU,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,aAAa,KAAK,IAAI,CAAC;IACpD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,IAAI,CAAC;IAC/D,oBAAoB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IAChD,SAAS,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;IACvC,SAAS,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC/C;AA6BD,kGAAkG;AAClG,QAAA,MAAM,gBAAgB,GAAI,OAAO,qBAAqB,4CA4JrD,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
@@ -4,7 +4,7 @@ import { useEffect, useRef } from "react";
4
4
  import { Input } from "antd";
5
5
  import { useTranslation } from "react-i18next";
6
6
  import { CrmIcon as Icon } from "../../components/group/crmIcon";
7
- import GroupCompositeAvatar from "../../components/group/GroupCompositeAvatar";
7
+ import GroupAvatar from "../../components/group/GroupAvatar";
8
8
  import { ACCEPTED_IMAGE_TYPES } from "../../utils/fileValidation";
9
9
  import { FOCUS_RING_CLASS } from "../../utils/a11yClickable";
10
10
  import { DangerRow, InfoCard, NavRow, SectionLabel, SwitchRow } from "./GroupInfoRows";
@@ -29,7 +29,7 @@ const GroupInfoBodyCrm = (props) => {
29
29
  const nameChanged = props.nameValue.trim() !== "" && props.nameValue.trim() !== ((_a = props.groupName) !== null && _a !== void 0 ? _a : "");
30
30
  const descChanged = props.descriptionValue.trim() !== ((_b = props.introduction) !== null && _b !== void 0 ? _b : "");
31
31
  const hasAdminRows = props.canConfigPermissions || props.showInviteLink;
32
- return (_jsxs("div", { className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "relative block h-[60px] w-[60px] shrink-0", children: [_jsx(GroupCompositeAvatar, { groupID: props.groupID, faceURL: props.faceURL, ownerUserID: props.ownerUserID, groupName: props.groupName, size: 56 }), props.isAvatarUploading && (_jsx("span", { className: "absolute left-0 top-0 flex h-14 w-14 items-center justify-center rounded-full bg-gray-900/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), props.canEditAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: props.avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: props.onAvatarSelect }), _jsx("button", { type: "button", disabled: props.isAvatarUploading, onClick: props.onAvatarClick, "aria-label": t("group_info_edit_avatar"), title: t("group_info_edit_avatar"), className: `absolute bottom-0 right-0 flex h-6 w-6 items-center justify-center rounded-full border-2 border-white bg-gray-900 text-white ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [editingField === "name" ? (_jsx(Input, { autoFocus: true, value: props.nameValue, onChange: (event) => props.onNameChange(event.target.value), maxLength: 255, disabled: props.isSaving, "aria-label": t("group_info_edit_name"), onPressEnter: () => nameChanged && props.onSaveEdit("name") })) : (_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx("span", { className: "truncate text-base font-semibold text-gray-900", title: props.groupName, children: props.groupName }), props.canEditName && (_jsx("button", { type: "button", className: `h-7 w-7 ${ICON_BUTTON}`, onClick: () => props.onStartEdit("name"), "aria-label": t("group_info_edit_name"), title: t("group_info_edit_name"), children: _jsx(Icon, { icon: "edit-o", size: 16 }) }))] })), _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(Chip, { icon: props.isPublic ? "globe-o" : "lock-o", tone: "primary", children: t(props.isPublic ? "group_visibility_public" : "group_visibility_private") }), typeof props.memberCount === "number" && (_jsx(Chip, { icon: "user-two-o", tone: "neutral", children: t("member_count", { count: props.memberCount }) }))] })] })] }), editingField === "name" && (_jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && nameChanged, onCancel: () => props.onCancelEdit("name"), onSave: () => props.onSaveEdit("name") })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "text-xs font-medium text-gray-600", children: t("description") }), editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input.TextArea, { ref: descriptionRef, value: props.descriptionValue, onChange: (event) => props.onDescriptionChange(event.target.value), placeholder: t("enter_group_description"), "aria-label": t("description"), autoSize: { minRows: 2, maxRows: 5 }, maxLength: 500, showCount: true, disabled: props.isSaving }), _jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && descChanged, onCancel: () => props.onCancelEdit("description"), onSave: () => props.onSaveEdit("description") })] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "m-0 whitespace-pre-wrap break-words text-sm text-gray-600", children: hasDescription ? props.introduction : t("group_info_no_description") }), props.canEditDescription && (_jsxs("button", { type: "button", onClick: () => props.onStartEdit("description"), className: `flex h-6 items-center gap-1.5 self-start rounded-lg text-[13px] font-medium text-primary-500 hover:text-primary-600 ${FOCUS_RING_CLASS}`, children: [_jsx(Icon, { icon: hasDescription ? "edit-o" : "plus-o", size: 14 }), t(hasDescription ? "group_info_edit_description" : "group_info_add_description")] }))] }))] }), _jsx(SectionLabel, { children: t("group_settings_section") }), _jsx(InfoCard, { children: [
32
+ return (_jsxs("div", { className: "flex flex-1 flex-col gap-4 overflow-y-auto p-4", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsxs("span", { className: "relative block h-[60px] w-[60px] shrink-0", children: [_jsx(GroupAvatar, { faceURL: props.faceURL, groupName: props.groupName, size: 56 }), props.isAvatarUploading && (_jsx("span", { className: "absolute left-0 top-0 flex h-14 w-14 items-center justify-center rounded-full bg-gray-900/30", children: _jsx("span", { className: "h-4 w-4 animate-spin rounded-full border-2 border-white border-t-transparent" }) })), props.canEditAvatar && (_jsxs(_Fragment, { children: [_jsx("input", { ref: props.avatarInputRef, type: "file", accept: ACCEPTED_IMAGE_TYPES.join(", "), className: "hidden", onChange: props.onAvatarSelect }), _jsx("button", { type: "button", disabled: props.isAvatarUploading, onClick: props.onAvatarClick, "aria-label": t("group_info_edit_avatar"), title: t("group_info_edit_avatar"), className: `absolute bottom-0 right-0 flex h-6 w-6 items-center justify-center rounded-full border-2 border-white bg-gray-900 text-white ${FOCUS_RING_CLASS}`, children: _jsx(Icon, { icon: "camera-o", size: 12 }) })] }))] }), _jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-1", children: [editingField === "name" ? (_jsx(Input, { autoFocus: true, value: props.nameValue, onChange: (event) => props.onNameChange(event.target.value), maxLength: 255, disabled: props.isSaving, "aria-label": t("group_info_edit_name"), onPressEnter: () => nameChanged && props.onSaveEdit("name") })) : (_jsxs("span", { className: "flex items-center gap-0.5", children: [_jsx("span", { className: "truncate text-base font-semibold text-gray-900", title: props.groupName, children: props.groupName }), props.canEditName && (_jsx("button", { type: "button", className: `h-7 w-7 ${ICON_BUTTON}`, onClick: () => props.onStartEdit("name"), "aria-label": t("group_info_edit_name"), title: t("group_info_edit_name"), children: _jsx(Icon, { icon: "edit-o", size: 16 }) }))] })), _jsxs("span", { className: "flex flex-wrap gap-1.5", children: [_jsx(Chip, { icon: props.isPublic ? "globe-o" : "lock-o", tone: "primary", children: t(props.isPublic ? "group_visibility_public" : "group_visibility_private") }), typeof props.memberCount === "number" && (_jsx(Chip, { icon: "user-two-o", tone: "neutral", children: t("member_count", { count: props.memberCount }) }))] })] })] }), editingField === "name" && (_jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && nameChanged, onCancel: () => props.onCancelEdit("name"), onSave: () => props.onSaveEdit("name") })), _jsxs("div", { className: "flex flex-col gap-1", children: [_jsx("span", { className: "text-xs font-medium text-gray-600", children: t("description") }), editingField === "description" ? (_jsxs("div", { className: "flex flex-col gap-2", children: [_jsx(Input.TextArea, { ref: descriptionRef, value: props.descriptionValue, onChange: (event) => props.onDescriptionChange(event.target.value), placeholder: t("enter_group_description"), "aria-label": t("description"), autoSize: { minRows: 2, maxRows: 5 }, maxLength: 500, showCount: true, disabled: props.isSaving }), _jsx(EditActions, { disabled: props.isSaving, canSave: !props.isSaving && descChanged, onCancel: () => props.onCancelEdit("description"), onSave: () => props.onSaveEdit("description") })] })) : (_jsxs(_Fragment, { children: [_jsx("p", { className: "m-0 whitespace-pre-wrap break-words text-sm text-gray-600", children: hasDescription ? props.introduction : t("group_info_no_description") }), props.canEditDescription && (_jsxs("button", { type: "button", onClick: () => props.onStartEdit("description"), className: `flex h-6 items-center gap-1.5 self-start rounded-lg text-[13px] font-medium text-primary-500 hover:text-primary-600 ${FOCUS_RING_CLASS}`, children: [_jsx(Icon, { icon: hasDescription ? "edit-o" : "plus-o", size: 14 }), t(hasDescription ? "group_info_edit_description" : "group_info_add_description")] }))] }))] }), _jsx(SectionLabel, { children: t("group_settings_section") }), _jsx(InfoCard, { children: [
33
33
  _jsx(SwitchRow, { icon: "bell-o", label: t("notification"), checked: props.notifyEnabled, loading: props.isTogglingNotification, onChange: props.onToggleNotification }, "notify"),
34
34
  props.showAllowSend && (_jsx(SwitchRow, { icon: "chat-square-o", label: t("members_can_send_message"), hint: t("allow_send_message_hint"), checked: props.allowSendMessage, loading: props.isTogglingSendMessage, onChange: props.onToggleSendMessage }, "send")),
35
35
  ] }), hasAdminRows && (_jsxs(_Fragment, { children: [_jsx(SectionLabel, { children: t("group_admin_section") }), _jsx(InfoCard, { children: [