@droppii-org/chat-mobile 0.2.75 → 0.2.77

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 (74) hide show
  1. package/lib/module/components/GroupPermissionGate/GroupPermissionGate.js +33 -0
  2. package/lib/module/components/GroupPermissionGate/GroupPermissionGate.js.map +1 -0
  3. package/lib/module/components/GroupPermissionGate/index.js +4 -0
  4. package/lib/module/components/GroupPermissionGate/index.js.map +1 -0
  5. package/lib/module/context/ChatDetailContext.js +24 -11
  6. package/lib/module/context/ChatDetailContext.js.map +1 -1
  7. package/lib/module/core/useChatListener.js +13 -7
  8. package/lib/module/core/useChatListener.js.map +1 -1
  9. package/lib/module/hooks/groups/useDismissGroup.js +79 -0
  10. package/lib/module/hooks/groups/useDismissGroup.js.map +1 -0
  11. package/lib/module/hooks/groups/useJoinGroup.js +1 -3
  12. package/lib/module/hooks/groups/useJoinGroup.js.map +1 -1
  13. package/lib/module/hooks/message/useSendMessage.js +16 -8
  14. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  15. package/lib/module/hooks/useGroupPermission.js +42 -7
  16. package/lib/module/hooks/useGroupPermission.js.map +1 -1
  17. package/lib/module/screens/ChatInfo/ChatInfo.js +8 -10
  18. package/lib/module/screens/ChatInfo/ChatInfo.js.map +1 -1
  19. package/lib/module/screens/ChatInfo/ChatInfoActions.js +48 -6
  20. package/lib/module/screens/ChatInfo/ChatInfoActions.js.map +1 -1
  21. package/lib/module/screens/ChatInfo/ChatInfoDescriptionRow.js +2 -1
  22. package/lib/module/screens/ChatInfo/ChatInfoDescriptionRow.js.map +1 -1
  23. package/lib/module/screens/chat-detail/ChatComposer.js +17 -8
  24. package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
  25. package/lib/module/screens/chat-detail/ChatDetailHeader.js +4 -8
  26. package/lib/module/screens/chat-detail/ChatDetailHeader.js.map +1 -1
  27. package/lib/module/translation/resources/i18n.js +8 -1
  28. package/lib/module/translation/resources/i18n.js.map +1 -1
  29. package/lib/module/types/chat.js.map +1 -1
  30. package/lib/typescript/src/components/GroupPermissionGate/GroupPermissionGate.d.ts +19 -0
  31. package/lib/typescript/src/components/GroupPermissionGate/GroupPermissionGate.d.ts.map +1 -0
  32. package/lib/typescript/src/components/GroupPermissionGate/index.d.ts +3 -0
  33. package/lib/typescript/src/components/GroupPermissionGate/index.d.ts.map +1 -0
  34. package/lib/typescript/src/context/ChatDetailContext.d.ts.map +1 -1
  35. package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
  36. package/lib/typescript/src/hooks/groups/useDismissGroup.d.ts +8 -0
  37. package/lib/typescript/src/hooks/groups/useDismissGroup.d.ts.map +1 -0
  38. package/lib/typescript/src/hooks/groups/useJoinGroup.d.ts.map +1 -1
  39. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  40. package/lib/typescript/src/hooks/useGroupPermission.d.ts +6 -1
  41. package/lib/typescript/src/hooks/useGroupPermission.d.ts.map +1 -1
  42. package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts +2 -2
  43. package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts.map +1 -1
  44. package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts +3 -2
  45. package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts.map +1 -1
  46. package/lib/typescript/src/screens/ChatInfo/ChatInfoDescriptionRow.d.ts +1 -2
  47. package/lib/typescript/src/screens/ChatInfo/ChatInfoDescriptionRow.d.ts.map +1 -1
  48. package/lib/typescript/src/screens/ChatInfo/types.d.ts +1 -0
  49. package/lib/typescript/src/screens/ChatInfo/types.d.ts.map +1 -1
  50. package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
  51. package/lib/typescript/src/screens/chat-detail/ChatDetailHeader.d.ts.map +1 -1
  52. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  53. package/lib/typescript/src/types/chat.d.ts +4 -2
  54. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  55. package/lib/typescript/src/types/events.d.ts +2 -4
  56. package/lib/typescript/src/types/events.d.ts.map +1 -1
  57. package/package.json +1 -1
  58. package/src/components/GroupPermissionGate/GroupPermissionGate.tsx +51 -0
  59. package/src/components/GroupPermissionGate/index.ts +5 -0
  60. package/src/context/ChatDetailContext.tsx +26 -11
  61. package/src/core/useChatListener.ts +13 -7
  62. package/src/hooks/groups/useDismissGroup.tsx +80 -0
  63. package/src/hooks/groups/useJoinGroup.ts +1 -3
  64. package/src/hooks/message/useSendMessage.ts +15 -12
  65. package/src/hooks/useGroupPermission.ts +49 -7
  66. package/src/screens/ChatInfo/ChatInfo.tsx +7 -11
  67. package/src/screens/ChatInfo/ChatInfoActions.tsx +79 -32
  68. package/src/screens/ChatInfo/ChatInfoDescriptionRow.tsx +3 -2
  69. package/src/screens/ChatInfo/types.ts +1 -0
  70. package/src/screens/chat-detail/ChatComposer.tsx +21 -25
  71. package/src/screens/chat-detail/ChatDetailHeader.tsx +4 -19
  72. package/src/translation/resources/i18n.ts +9 -0
  73. package/src/types/chat.ts +5 -2
  74. package/src/types/events.ts +2 -4
@@ -1,4 +1,8 @@
1
- import { PeerType, type GroupPermission } from '@droppii/openim-rn-client-sdk';
1
+ import {
2
+ GroupMemberRole,
3
+ GroupPermission,
4
+ GroupStatus,
5
+ } from '@droppii/openim-rn-client-sdk';
2
6
  import { useChatDetailContext } from '../context';
3
7
  import { useCallback, useMemo } from 'react';
4
8
  import { trans } from '../translation';
@@ -8,17 +12,17 @@ export const useHasGroupPermission = (
8
12
  permission: GroupPermission | GroupPermission[],
9
13
  mode: 'every' | 'some' = 'every'
10
14
  ): boolean => {
11
- const { conversation, groupPermissions } = useChatDetailContext();
12
- const isNotGroup = conversation?.peerType !== PeerType.Group;
15
+ const { isGroupConversation, userInfo } = useChatDetailContext();
13
16
  const required = Array.isArray(permission) ? permission : [permission];
17
+ const granted = userInfo?.permissions || [];
14
18
 
15
19
  return useMemo(() => {
16
- if (isNotGroup) return true;
20
+ if (!isGroupConversation) return true;
17
21
  return mode === 'every'
18
- ? required.every((p) => groupPermissions?.includes(p))
19
- : required.some((p) => groupPermissions?.includes(p));
22
+ ? required.every((p) => granted?.includes(p))
23
+ : required.some((p) => granted?.includes(p));
20
24
  // eslint-disable-next-line react-hooks/exhaustive-deps
21
- }, [groupPermissions, isNotGroup, mode]);
25
+ }, [isGroupConversation, mode]);
22
26
  };
23
27
 
24
28
  export const useGuardedAction = <T extends (...args: any[]) => any>(
@@ -41,3 +45,41 @@ export const useGuardedAction = <T extends (...args: any[]) => any>(
41
45
  [allowed, action, options?.deniedMessage]
42
46
  ) as T;
43
47
  };
48
+
49
+ export const useHasRoleLevel = (minRoleLevel: GroupMemberRole): boolean => {
50
+ const { isGroupConversation, userInfo } = useChatDetailContext();
51
+
52
+ return useMemo(() => {
53
+ if (!isGroupConversation) return true;
54
+ return (userInfo?.roleLevel ?? GroupMemberRole.Normal) >= minRoleLevel;
55
+ }, [isGroupConversation, userInfo?.roleLevel, minRoleLevel]);
56
+ };
57
+
58
+ export const useCanSendMessage = (): {
59
+ allowed: boolean;
60
+ reason?: string;
61
+ } => {
62
+ const { userInfo, groupInfo, isGroupConversation } = useChatDetailContext();
63
+
64
+ const hasRolePermission = useMemo(
65
+ () => userInfo?.permissions?.includes(GroupPermission.SendMessage) ?? false,
66
+ [userInfo?.permissions]
67
+ );
68
+ const isOwnerOrAdmin = useHasRoleLevel(GroupMemberRole.Admin);
69
+
70
+ if (!isGroupConversation) return { allowed: true };
71
+
72
+ if (!hasRolePermission)
73
+ return {
74
+ allowed: false,
75
+ reason: trans('group:cannot_send_message'),
76
+ };
77
+
78
+ if (groupInfo?.status === GroupStatus.Muted && !isOwnerOrAdmin) {
79
+ return {
80
+ allowed: false,
81
+ reason: trans('group:messaging_muted_by_owner'),
82
+ };
83
+ }
84
+ return { allowed: true };
85
+ };
@@ -2,7 +2,6 @@ import { memo } from 'react';
2
2
  import { KContainer, KNavigation } from '@droppii/libs';
3
3
  import { useNavigation } from '@react-navigation/native';
4
4
  import { useGetConversationTarget } from '../../hooks/conversation/useGetConversationDetail';
5
- import { useGetGroupInfo } from '../../hooks/conversation/useGetGroupInfo';
6
5
  import { useConversation } from '../../store';
7
6
  import ChatInfoProfile from './ChatInfoProfile';
8
7
  import ChatInfoMediaRow from './ChatInfoMediaRow';
@@ -10,7 +9,8 @@ import ChatInfoDescriptionRow from './ChatInfoDescriptionRow';
10
9
  import ChatInfoActions from './ChatInfoActions';
11
10
  import type { ChatInfoProps } from './types';
12
11
  import { trans } from '../../translation';
13
- import { isGroupConversation } from '../../utils/conversation';
12
+ import { withChatDetailProvider } from '../../context';
13
+ import { useChatDetailContext } from '../../context';
14
14
 
15
15
  const ChatInfo = memo(
16
16
  ({
@@ -22,16 +22,14 @@ const ChatInfo = memo(
22
22
  onPressCreateGroup,
23
23
  onPressAddToGroup,
24
24
  onPressLeaveGroup,
25
+ onDismissGroup,
25
26
  }: ChatInfoProps) => {
26
27
  const navigation = useNavigation();
27
28
 
28
29
  const conversation = useConversation(conversationId);
29
30
  const { data: target } = useGetConversationTarget(conversationId);
30
31
  const isTargetActive = target ? target.isActive : true;
31
- const isGroup = isGroupConversation(conversation);
32
- const { data: groupInfo } = useGetGroupInfo(
33
- isGroup ? conversation?.groupID : undefined
34
- );
32
+ const isGroup = useChatDetailContext().isGroupConversation;
35
33
 
36
34
  return (
37
35
  <KContainer.Page flex edges={['bottom']} background="#EBEDF2">
@@ -54,10 +52,7 @@ const ChatInfo = memo(
54
52
  />
55
53
  <ChatInfoMediaRow onPressMedia={onPressMedia} />
56
54
  <KContainer.VisibleView visible={isGroup}>
57
- <ChatInfoDescriptionRow
58
- introduction={groupInfo?.introduction}
59
- groupName={conversation?.showName}
60
- />
55
+ <ChatInfoDescriptionRow groupName={conversation?.showName} />
61
56
  </KContainer.VisibleView>
62
57
  <ChatInfoActions
63
58
  conversation={conversation}
@@ -67,6 +62,7 @@ const ChatInfo = memo(
67
62
  onPressCreateGroup={onPressCreateGroup}
68
63
  onPressAddToGroup={onPressAddToGroup}
69
64
  onPressLeaveGroup={onPressLeaveGroup}
65
+ onDismissGroup={onDismissGroup}
70
66
  />
71
67
  </KContainer.ScrollView>
72
68
  </KContainer.Page>
@@ -74,4 +70,4 @@ const ChatInfo = memo(
74
70
  }
75
71
  );
76
72
 
77
- export default ChatInfo;
73
+ export default withChatDetailProvider(ChatInfo);
@@ -6,9 +6,14 @@ import {
6
6
  type KListItemBaseItemProps,
7
7
  KLabel,
8
8
  } from '@droppii/libs';
9
- import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
9
+ import {
10
+ GroupMemberRole,
11
+ type ConversationItem,
12
+ } from '@droppii/openim-rn-client-sdk';
10
13
  import { usePinConversation } from '../../hooks/usePinConversation';
11
14
  import { trans } from '../../translation';
15
+ import { useChatDetailContext } from '../../context';
16
+ import { useDismissGroup } from '../../hooks/groups/useDismissGroup';
12
17
 
13
18
  interface ChatInfoActionsProps {
14
19
  conversation?: ConversationItem;
@@ -18,6 +23,7 @@ interface ChatInfoActionsProps {
18
23
  onPressCreateGroup?: () => void;
19
24
  onPressAddToGroup?: () => void;
20
25
  onPressLeaveGroup?: () => void;
26
+ onDismissGroup?: () => void;
21
27
  }
22
28
 
23
29
  const ChatInfoActions = memo(
@@ -29,10 +35,17 @@ const ChatInfoActions = memo(
29
35
  onPressCreateGroup,
30
36
  onPressAddToGroup,
31
37
  onPressLeaveGroup,
38
+ onDismissGroup,
32
39
  }: ChatInfoActionsProps) => {
33
40
  const { pinConversation, unpinConversation } = usePinConversation();
34
41
  const isPinned = Boolean(conversation?.isPinned);
35
42
  const showName = conversation?.showName || '';
43
+ const { userInfo } = useChatDetailContext();
44
+ const { dismissGroup } = useDismissGroup({ onSuccess: onDismissGroup });
45
+
46
+ const isOwner = useMemo(() => {
47
+ return userInfo?.roleLevel === GroupMemberRole.Owner;
48
+ }, [userInfo?.roleLevel]);
36
49
 
37
50
  const handlePinPress = useCallback(() => {
38
51
  if (isPinned) {
@@ -44,6 +57,11 @@ const ChatInfoActions = memo(
44
57
 
45
58
  const handleDeleteHistory = useCallback(() => {}, []);
46
59
 
60
+ const handleDismissGroup = useCallback(() => {
61
+ if (!conversation?.groupID) return;
62
+ dismissGroup(conversation?.groupID);
63
+ }, [dismissGroup, conversation?.groupID]);
64
+
47
65
  const primaryData = useMemo(() => {
48
66
  const items: KListItemBaseItemProps[] = [];
49
67
 
@@ -118,17 +136,40 @@ const ChatInfoActions = memo(
118
136
  ]);
119
137
 
120
138
  const dangerData: KListItemBaseItemProps[] = useMemo(() => {
139
+ const items: KListItemBaseItemProps[] = [];
121
140
  if (isGroup) {
122
- return [
123
- {
141
+ items.push({
142
+ leftNode: {
143
+ icon: {
144
+ vectorName: 'logout-o',
145
+ tintColor: KColors.danger.normal,
146
+ },
147
+ },
148
+ tintColor: KColors.danger.normal,
149
+ onPress: onPressLeaveGroup,
150
+ showChevron: false,
151
+ paddingH: '0.75rem',
152
+ paddingV: '0.75rem',
153
+ customLabel: (
154
+ <KLabel.Text
155
+ typo="TextMdMedium"
156
+ color={KColors.danger.normal}
157
+ numberOfLines={1}
158
+ >
159
+ {trans('chat:info_leave_group')}
160
+ </KLabel.Text>
161
+ ),
162
+ });
163
+ if (isOwner) {
164
+ items.push({
124
165
  leftNode: {
125
166
  icon: {
126
- vectorName: 'logout-o',
167
+ vectorName: 'minus-circle-o',
127
168
  tintColor: KColors.danger.normal,
128
169
  },
129
170
  },
130
171
  tintColor: KColors.danger.normal,
131
- onPress: onPressLeaveGroup,
172
+ onPress: handleDismissGroup,
132
173
  showChevron: false,
133
174
  paddingH: '0.75rem',
134
175
  paddingV: '0.75rem',
@@ -138,39 +179,45 @@ const ChatInfoActions = memo(
138
179
  color={KColors.danger.normal}
139
180
  numberOfLines={1}
140
181
  >
141
- {trans('chat:info_leave_group')}
182
+ {trans('chat:dismiss_group')}
142
183
  </KLabel.Text>
143
184
  ),
144
- },
145
- ];
185
+ });
186
+ }
146
187
  }
147
188
 
148
- return [
149
- {
150
- label: trans('chat:info_delete_history'),
151
- leftNode: {
152
- icon: {
153
- vectorName: 'trash-alt-o-1',
154
- tintColor: KColors.danger.normal,
155
- },
189
+ items.push({
190
+ label: trans('chat:info_delete_history'),
191
+ leftNode: {
192
+ icon: {
193
+ vectorName: 'trash-alt-o-1',
194
+ tintColor: KColors.danger.normal,
156
195
  },
157
- tintColor: KColors.danger.normal,
158
- onPress: handleDeleteHistory,
159
- showChevron: false,
160
- paddingH: '0.75rem',
161
- paddingV: '0.75rem',
162
- customLabel: (
163
- <KLabel.Text
164
- typo="TextMdMedium"
165
- color={KColors.danger.normal}
166
- numberOfLines={1}
167
- >
168
- {trans('chat:info_delete_history')}
169
- </KLabel.Text>
170
- ),
171
196
  },
172
- ];
173
- }, [isGroup, onPressLeaveGroup, handleDeleteHistory]);
197
+ tintColor: KColors.danger.normal,
198
+ onPress: handleDeleteHistory,
199
+ showChevron: false,
200
+ paddingH: '0.75rem',
201
+ paddingV: '0.75rem',
202
+ customLabel: (
203
+ <KLabel.Text
204
+ typo="TextMdMedium"
205
+ color={KColors.danger.normal}
206
+ numberOfLines={1}
207
+ >
208
+ {trans('chat:info_delete_history')}
209
+ </KLabel.Text>
210
+ ),
211
+ });
212
+
213
+ return items;
214
+ }, [
215
+ isGroup,
216
+ onPressLeaveGroup,
217
+ handleDeleteHistory,
218
+ isOwner,
219
+ handleDismissGroup,
220
+ ]);
174
221
 
175
222
  return (
176
223
  <>
@@ -3,9 +3,9 @@ import { StyleSheet, type TextLayoutEvent } from 'react-native';
3
3
  import { KContainer, KLabel, KColors } from '@droppii/libs';
4
4
  import { trans } from '../../translation';
5
5
  import GroupDescriptionModal from './GroupDescriptionModal';
6
+ import { useChatDetailContext } from '../../context';
6
7
 
7
8
  interface ChatInfoDescriptionRowProps {
8
- introduction?: string;
9
9
  groupName?: string;
10
10
  }
11
11
 
@@ -13,7 +13,8 @@ const EXTRA_TEXT_LENGTH = 14; // Length of "...View More" text
13
13
  const MAX_LINES = 2;
14
14
 
15
15
  const ChatInfoDescriptionRow = memo(
16
- ({ introduction, groupName }: ChatInfoDescriptionRowProps) => {
16
+ ({ groupName }: ChatInfoDescriptionRowProps) => {
17
+ const introduction = useChatDetailContext().groupInfo?.introduction;
17
18
  const [modalVisible, setModalVisible] = useState(false);
18
19
  const handlePressDescription = useCallback(() => setModalVisible(true), []);
19
20
  const handleCloseDescription = useCallback(
@@ -9,4 +9,5 @@ export interface ChatInfoProps {
9
9
  onPressCreateGroup?: () => void;
10
10
  onPressAddToGroup?: () => void;
11
11
  onPressLeaveGroup?: () => void;
12
+ onDismissGroup?: () => void;
12
13
  }
@@ -63,11 +63,8 @@ import { ChatCurrentQuotedMessage } from './ChatCurrentQuotedMessage';
63
63
  import { useSendMessage } from '../../hooks/message/useSendMessage';
64
64
  import { openBotMenuSheet } from './BotMenuSheet';
65
65
  import { UIUtils } from '../../utils/UIUtils';
66
- import { GroupPermission, PeerType } from '@droppii/openim-rn-client-sdk';
67
- import {
68
- useGuardedAction,
69
- useHasGroupPermission,
70
- } from '../../hooks/useGroupPermission';
66
+ import { PeerType } from '@droppii/openim-rn-client-sdk';
67
+ import { useCanSendMessage } from '../../hooks/useGroupPermission';
71
68
  import { useIsJoinedGroup } from '../../hooks/useIsJoinedGroup';
72
69
 
73
70
  interface ChatComposerInternalProps {
@@ -107,9 +104,8 @@ export const ChatComposer = memo(
107
104
  const { mutateAsync: closeSupportSession } = useCloseSupportSession();
108
105
  const { sendMessage } = useSendMessage();
109
106
  const compose = useChatCompose();
110
- const isSendMessageAllowed = useHasGroupPermission(
111
- GroupPermission.SendMessage
112
- );
107
+ const { allowed: isSendMessageAllowed, reason: sendDeniedReason } =
108
+ useCanSendMessage();
113
109
 
114
110
  const { data: isJoinedGroup } = useIsJoinedGroup(conversation?.groupID);
115
111
 
@@ -149,20 +145,22 @@ export const ChatComposer = memo(
149
145
  onAttachmentOpenChange: setIsAttachmentOpen,
150
146
  });
151
147
 
152
- const handleSend = useGuardedAction(
153
- GroupPermission.SendMessage,
154
- useCallback(async () => {
155
- if (compose.isUploading || !compose.canSend) return;
156
- try {
157
- await compose.send();
158
- } catch (error) {
159
- if (__DEV__) console.error('[ChatComposer] Failed to send:', error);
160
- }
161
- }, [compose]),
162
- {
163
- deniedMessage: trans('chat:no_send_permission'),
148
+ const handleSend = useCallback(async () => {
149
+ if (!isSendMessageAllowed) {
150
+ UIUtils.toast.open({
151
+ title: sendDeniedReason,
152
+ theme: 'info',
153
+ });
154
+ return;
164
155
  }
165
- );
156
+
157
+ if (compose.isUploading || !compose.canSend) return;
158
+ try {
159
+ await compose.send();
160
+ } catch (error) {
161
+ if (__DEV__) console.error('[ChatComposer] Failed to send:', error);
162
+ }
163
+ }, [compose, isSendMessageAllowed, sendDeniedReason]);
166
164
 
167
165
  const handleInputFocus = useCallback(() => {
168
166
  setIsInputFocused(true);
@@ -474,7 +472,7 @@ export const ChatComposer = memo(
474
472
  );
475
473
  } else if (!isSendMessageAllowed) {
476
474
  content = (
477
- <KContainer.View row alignItems justifyContent>
475
+ <KContainer.View row alignItems justifyContent paddingT={'1rem'}>
478
476
  <KContainer.View marginR="0.25rem">
479
477
  <KImage.VectorIcons
480
478
  name="info-circle-o"
@@ -482,9 +480,7 @@ export const ChatComposer = memo(
482
480
  color={KColors.palette.gray.w600}
483
481
  />
484
482
  </KContainer.View>
485
- <KLabel.Text typo="TextXsNormal">
486
- {trans('group:cannot_send_message')}
487
- </KLabel.Text>
483
+ <KLabel.Text typo="TextXsNormal">{sendDeniedReason}</KLabel.Text>
488
484
  </KContainer.View>
489
485
  );
490
486
  } else {
@@ -11,9 +11,8 @@ import { NamePrefixIcon } from '../../components/ThreadCard/NamePrefixIcon';
11
11
  import type { ChatDetailHeaderProps } from './types';
12
12
  import { getConversationSubtitle } from './conversationHeader.utils';
13
13
  import { useGetUsersInfo } from '../../hooks/users/useGetUsersInfo';
14
- import { useGetGroupInfo } from '../../hooks/conversation/useGetGroupInfo';
15
- import { isGroupConversation } from '../../utils/conversation';
16
14
  import { useGetConversationDetail } from '../../hooks/conversation/useGetConversationDetail';
15
+ import { useChatDetailContext } from '../../context';
17
16
 
18
17
  const ChatDetailHeader = memo(
19
18
  ({
@@ -34,11 +33,7 @@ const ChatDetailHeader = memo(
34
33
  const { data: usersInfo } = useGetUsersInfo(
35
34
  targetUserId ? [targetUserId] : []
36
35
  );
37
-
38
- const isGroup = isGroupConversation(conversation);
39
- const { data: groupInfo } = useGetGroupInfo(
40
- isGroup ? conversation?.groupID : undefined
41
- );
36
+ const memberCount = useChatDetailContext().groupInfo?.memberCount;
42
37
 
43
38
  const { faceURL, showName } = useMemo(() => {
44
39
  const userInfo = usersInfo?.[0];
@@ -135,24 +130,14 @@ const ChatDetailHeader = memo(
135
130
  color={KColors.palette.gray.w500}
136
131
  numberOfLines={1}
137
132
  >
138
- {getConversationSubtitle(
139
- conversation,
140
- groupInfo?.memberCount
141
- )}
133
+ {getConversationSubtitle(conversation, memberCount)}
142
134
  </KLabel.Text>
143
135
  )}
144
136
  </KContainer.View>
145
137
  </KContainer.Touchable>
146
138
  </KContainer.View>
147
139
  ),
148
- [
149
- onBack,
150
- onPressAvatar,
151
- conversation,
152
- faceURL,
153
- showName,
154
- groupInfo?.memberCount,
155
- ]
140
+ [onBack, onPressAvatar, conversation, faceURL, showName, memberCount]
156
141
  );
157
142
 
158
143
  return (
@@ -124,6 +124,7 @@ const i18nKey: Record<string, string> = {
124
124
  'chat:info_unpin_message': 'Bỏ ghim trò chuyện',
125
125
  'chat:info_delete_history': 'Xoá lịch sử trò chuyện',
126
126
  'chat:info_leave_group': 'Rời nhóm',
127
+ 'chat:dismiss_group': 'Giải tán nhóm',
127
128
  'chat:info_view_more': 'Xem thêm',
128
129
  'chat:group_description_title': 'Mô tả nhóm',
129
130
  'start': 'Bắt đầu',
@@ -171,9 +172,17 @@ const i18nKey: Record<string, string> = {
171
172
  'group:join': 'Tham gia',
172
173
  'group:not_in_group': 'Bạn cần tham gia nhóm để gửi tin nhắn',
173
174
  'group:cannot_send_message': 'Bạn không thể gửi tin nhắn vào nhóm này',
175
+ 'group:messaging_muted_by_owner':
176
+ 'Chỉ chủ nhóm và quản trị viên được phép gửi tin nhắn',
174
177
  'group:joined_group': 'Đã tham gia nhóm {{groupName}}',
175
178
  'group:public_group': 'Nhóm công khai',
176
179
  'group:private_group': 'Nhóm riêng tư',
180
+ 'group:dismiss_confirm_title': 'Giải tán nhóm?',
181
+ 'group:dismiss_confirm_desc':
182
+ 'Tất cả thành viên và tin nhắn sẽ bị xoá. Bạn có chắc chắn muốn giải tán nhóm?',
183
+ 'group:dismiss_confirm_primary': 'Giải tán',
184
+ 'group:dismiss_confirm_secondary': 'Quay lại',
185
+ 'group:dismiss_toast_success': 'Đã giải tán nhóm',
177
186
  };
178
187
 
179
188
  export default {
package/src/types/chat.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import {
2
- GroupPermission,
3
2
  MessageType,
4
3
  type ConversationItem,
4
+ type GroupItem,
5
5
  type MessageItem,
6
+ type SelfUserInfo,
6
7
  } from '@droppii/openim-rn-client-sdk';
7
8
  import type { PropsWithChildren } from 'react';
8
9
  import type { IUrlMetadata } from './common';
@@ -206,6 +207,7 @@ export interface MessageStore {
206
207
  export interface ChatDetailContextType {
207
208
  conversationFlow?: IConversationFlow;
208
209
  isBotConversation: boolean;
210
+ isGroupConversation: boolean;
209
211
  setConverationFlowStep: (
210
212
  step?: IConversationFlowStep,
211
213
  isEnd?: boolean,
@@ -217,7 +219,8 @@ export interface ChatDetailContextType {
217
219
  quotedMessage?: MessageItem;
218
220
  setQuotedMessage: (item?: MessageItem) => void;
219
221
  conversationFlowMainMenu?: InputButtonItem[];
220
- groupPermissions: GroupPermission[];
222
+ userInfo?: SelfUserInfo;
223
+ groupInfo?: GroupItem | null;
221
224
  }
222
225
 
223
226
  export interface ChatDetailProviderProps extends PropsWithChildren {}
@@ -1,4 +1,4 @@
1
- import type { GroupPermission } from '@droppii/openim-rn-client-sdk';
1
+ import type { SelfUserInfo } from '@droppii/openim-rn-client-sdk';
2
2
 
3
3
  export enum ChatEvent {
4
4
  ScrollToMessage = 'chat:scroll_to_message',
@@ -16,9 +16,7 @@ export interface MessageRevokedPayload {
16
16
  clientMsgID: string;
17
17
  }
18
18
 
19
- export interface GroupPermissionUpdatedPayload {
20
- permissions: GroupPermission[];
21
- }
19
+ export type GroupPermissionUpdatedPayload = Partial<SelfUserInfo>;
22
20
 
23
21
  export interface GroupRemovedPayload {
24
22
  groupID: string;