@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.
- package/lib/module/components/GroupPermissionGate/GroupPermissionGate.js +33 -0
- package/lib/module/components/GroupPermissionGate/GroupPermissionGate.js.map +1 -0
- package/lib/module/components/GroupPermissionGate/index.js +4 -0
- package/lib/module/components/GroupPermissionGate/index.js.map +1 -0
- package/lib/module/context/ChatDetailContext.js +24 -11
- package/lib/module/context/ChatDetailContext.js.map +1 -1
- package/lib/module/core/useChatListener.js +13 -7
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/hooks/groups/useDismissGroup.js +79 -0
- package/lib/module/hooks/groups/useDismissGroup.js.map +1 -0
- package/lib/module/hooks/groups/useJoinGroup.js +1 -3
- package/lib/module/hooks/groups/useJoinGroup.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +16 -8
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useGroupPermission.js +42 -7
- package/lib/module/hooks/useGroupPermission.js.map +1 -1
- package/lib/module/screens/ChatInfo/ChatInfo.js +8 -10
- package/lib/module/screens/ChatInfo/ChatInfo.js.map +1 -1
- package/lib/module/screens/ChatInfo/ChatInfoActions.js +48 -6
- package/lib/module/screens/ChatInfo/ChatInfoActions.js.map +1 -1
- package/lib/module/screens/ChatInfo/ChatInfoDescriptionRow.js +2 -1
- package/lib/module/screens/ChatInfo/ChatInfoDescriptionRow.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +17 -8
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetailHeader.js +4 -8
- package/lib/module/screens/chat-detail/ChatDetailHeader.js.map +1 -1
- package/lib/module/translation/resources/i18n.js +8 -1
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/typescript/src/components/GroupPermissionGate/GroupPermissionGate.d.ts +19 -0
- package/lib/typescript/src/components/GroupPermissionGate/GroupPermissionGate.d.ts.map +1 -0
- package/lib/typescript/src/components/GroupPermissionGate/index.d.ts +3 -0
- package/lib/typescript/src/components/GroupPermissionGate/index.d.ts.map +1 -0
- package/lib/typescript/src/context/ChatDetailContext.d.ts.map +1 -1
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/groups/useDismissGroup.d.ts +8 -0
- package/lib/typescript/src/hooks/groups/useDismissGroup.d.ts.map +1 -0
- package/lib/typescript/src/hooks/groups/useJoinGroup.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useGroupPermission.d.ts +6 -1
- package/lib/typescript/src/hooks/useGroupPermission.d.ts.map +1 -1
- package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts +2 -2
- package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts.map +1 -1
- package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts +3 -2
- package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts.map +1 -1
- package/lib/typescript/src/screens/ChatInfo/ChatInfoDescriptionRow.d.ts +1 -2
- package/lib/typescript/src/screens/ChatInfo/ChatInfoDescriptionRow.d.ts.map +1 -1
- package/lib/typescript/src/screens/ChatInfo/types.d.ts +1 -0
- package/lib/typescript/src/screens/ChatInfo/types.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetailHeader.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +4 -2
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/events.d.ts +2 -4
- package/lib/typescript/src/types/events.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/GroupPermissionGate/GroupPermissionGate.tsx +51 -0
- package/src/components/GroupPermissionGate/index.ts +5 -0
- package/src/context/ChatDetailContext.tsx +26 -11
- package/src/core/useChatListener.ts +13 -7
- package/src/hooks/groups/useDismissGroup.tsx +80 -0
- package/src/hooks/groups/useJoinGroup.ts +1 -3
- package/src/hooks/message/useSendMessage.ts +15 -12
- package/src/hooks/useGroupPermission.ts +49 -7
- package/src/screens/ChatInfo/ChatInfo.tsx +7 -11
- package/src/screens/ChatInfo/ChatInfoActions.tsx +79 -32
- package/src/screens/ChatInfo/ChatInfoDescriptionRow.tsx +3 -2
- package/src/screens/ChatInfo/types.ts +1 -0
- package/src/screens/chat-detail/ChatComposer.tsx +21 -25
- package/src/screens/chat-detail/ChatDetailHeader.tsx +4 -19
- package/src/translation/resources/i18n.ts +9 -0
- package/src/types/chat.ts +5 -2
- package/src/types/events.ts +2 -4
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import {
|
|
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 {
|
|
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 (
|
|
20
|
+
if (!isGroupConversation) return true;
|
|
17
21
|
return mode === 'every'
|
|
18
|
-
? required.every((p) =>
|
|
19
|
-
: required.some((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
|
-
}, [
|
|
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 {
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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: '
|
|
167
|
+
vectorName: 'minus-circle-o',
|
|
127
168
|
tintColor: KColors.danger.normal,
|
|
128
169
|
},
|
|
129
170
|
},
|
|
130
171
|
tintColor: KColors.danger.normal,
|
|
131
|
-
onPress:
|
|
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:
|
|
182
|
+
{trans('chat:dismiss_group')}
|
|
142
183
|
</KLabel.Text>
|
|
143
184
|
),
|
|
144
|
-
}
|
|
145
|
-
|
|
185
|
+
});
|
|
186
|
+
}
|
|
146
187
|
}
|
|
147
188
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
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
|
-
|
|
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
|
-
({
|
|
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(
|
|
@@ -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 {
|
|
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 =
|
|
111
|
-
|
|
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 =
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
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
|
-
|
|
222
|
+
userInfo?: SelfUserInfo;
|
|
223
|
+
groupInfo?: GroupItem | null;
|
|
221
224
|
}
|
|
222
225
|
|
|
223
226
|
export interface ChatDetailProviderProps extends PropsWithChildren {}
|
package/src/types/events.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
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
|
|
20
|
-
permissions: GroupPermission[];
|
|
21
|
-
}
|
|
19
|
+
export type GroupPermissionUpdatedPayload = Partial<SelfUserInfo>;
|
|
22
20
|
|
|
23
21
|
export interface GroupRemovedPayload {
|
|
24
22
|
groupID: string;
|