@droppii-org/chat-mobile 0.2.68 → 0.2.69
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/GroupItem/index.js +154 -0
- package/lib/module/components/GroupItem/index.js.map +1 -0
- package/lib/module/core/useChatListener.js +33 -2
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/hooks/groups/useFetchPublicGroup.js +39 -0
- package/lib/module/hooks/groups/useFetchPublicGroup.js.map +1 -0
- package/lib/module/hooks/groups/useJoinGroup.js +42 -0
- package/lib/module/hooks/groups/useJoinGroup.js.map +1 -0
- package/lib/module/hooks/query-keys.js +6 -0
- package/lib/module/hooks/query-keys.js.map +1 -1
- package/lib/module/index.js +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/screens/SearchConversation/TabResult.js +1 -1
- package/lib/module/screens/SearchConversation/TabResult.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +29 -1
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +20 -2
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/types.js.map +1 -1
- package/lib/module/screens/inbox/CommunityTab.js +55 -0
- package/lib/module/screens/inbox/CommunityTab.js.map +1 -0
- package/lib/module/screens/inbox/Inbox.js +51 -40
- package/lib/module/screens/inbox/Inbox.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/typescript/src/components/GroupItem/index.d.ts +8 -0
- package/lib/typescript/src/components/GroupItem/index.d.ts.map +1 -0
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/groups/useFetchPublicGroup.d.ts +213 -0
- package/lib/typescript/src/hooks/groups/useFetchPublicGroup.d.ts.map +1 -0
- package/lib/typescript/src/hooks/groups/useJoinGroup.d.ts +5 -0
- package/lib/typescript/src/hooks/groups/useJoinGroup.d.ts.map +1 -0
- package/lib/typescript/src/hooks/query-keys.d.ts +6 -0
- package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +1 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts +3 -1
- package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +2 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/screens/inbox/CommunityTab.d.ts +6 -0
- package/lib/typescript/src/screens/inbox/CommunityTab.d.ts.map +1 -0
- package/lib/typescript/src/screens/inbox/Inbox.d.ts +2 -1
- package/lib/typescript/src/screens/inbox/Inbox.d.ts.map +1 -1
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/GroupItem/index.tsx +170 -0
- package/src/core/useChatListener.ts +53 -1
- package/src/hooks/groups/useFetchPublicGroup.ts +43 -0
- package/src/hooks/groups/useJoinGroup.ts +46 -0
- package/src/hooks/query-keys.ts +8 -0
- package/src/index.tsx +5 -1
- package/src/screens/SearchConversation/TabResult.tsx +1 -1
- package/src/screens/chat-detail/ChatComposer.tsx +35 -0
- package/src/screens/chat-detail/ChatDetail.tsx +25 -1
- package/src/screens/chat-detail/types.ts +5 -1
- package/src/screens/inbox/CommunityTab.tsx +65 -0
- package/src/screens/inbox/Inbox.tsx +51 -39
- package/src/translation/resources/i18n.ts +7 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { useInfiniteQuery } from '@tanstack/react-query';
|
|
2
|
+
import { useMemo } from 'react';
|
|
3
|
+
import OpenIMSDK, {
|
|
4
|
+
PublicGroupJoinStatus,
|
|
5
|
+
type SearchPublicGroupInfo,
|
|
6
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
7
|
+
import { PAGE_SIZE } from '../../constants';
|
|
8
|
+
import { groupQueryKeys } from '../query-keys';
|
|
9
|
+
|
|
10
|
+
export const useFetchPublicGroup = (keyword: string) => {
|
|
11
|
+
const { data, ...rest } = useInfiniteQuery({
|
|
12
|
+
queryKey: groupQueryKeys.publicSearch(keyword),
|
|
13
|
+
queryFn: ({ pageParam = 0 }) => {
|
|
14
|
+
return OpenIMSDK.searchPublicGroups(
|
|
15
|
+
keyword,
|
|
16
|
+
PublicGroupJoinStatus.All,
|
|
17
|
+
pageParam,
|
|
18
|
+
PAGE_SIZE
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
getNextPageParam: (lastPage, allPages) => {
|
|
22
|
+
const fetched = allPages.reduce((sum, p) => sum + p.groups.length, 0);
|
|
23
|
+
return fetched < lastPage.total ? fetched : undefined;
|
|
24
|
+
},
|
|
25
|
+
initialPageParam: 0,
|
|
26
|
+
maxPages: 1,
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const dataFlatten: SearchPublicGroupInfo[] = useMemo(() => {
|
|
30
|
+
const seen = new Set<string>();
|
|
31
|
+
return (
|
|
32
|
+
data?.pages.flatMap((page) =>
|
|
33
|
+
page.groups.filter((g) => {
|
|
34
|
+
if (seen.has(g.groupID)) return false;
|
|
35
|
+
seen.add(g.groupID);
|
|
36
|
+
return true;
|
|
37
|
+
})
|
|
38
|
+
) ?? []
|
|
39
|
+
);
|
|
40
|
+
}, [data]);
|
|
41
|
+
|
|
42
|
+
return { dataFlatten, ...rest };
|
|
43
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import OpenIMSDK, { type JoinGroupParams } from '@droppii/openim-rn-client-sdk';
|
|
2
|
+
import { useQueryClient } from '@tanstack/react-query';
|
|
3
|
+
import { useMutation } from '@tanstack/react-query';
|
|
4
|
+
import { conversationQueryKeys, groupQueryKeys } from '../query-keys';
|
|
5
|
+
import { UIUtils } from '../../utils/UIUtils';
|
|
6
|
+
import { trans } from '../../translation';
|
|
7
|
+
|
|
8
|
+
export const useJoinGroup = () => {
|
|
9
|
+
const queryClient = useQueryClient();
|
|
10
|
+
|
|
11
|
+
return useMutation({
|
|
12
|
+
mutationKey: groupQueryKeys.join(),
|
|
13
|
+
mutationFn: (params: JoinGroupParams & { groupName: string }) =>
|
|
14
|
+
OpenIMSDK.joinGroup(params),
|
|
15
|
+
onSuccess: (_data, params) => {
|
|
16
|
+
queryClient.invalidateQueries({
|
|
17
|
+
queryKey: conversationQueryKeys.joinedGroup(params.groupID),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
queryClient.setQueriesData<{
|
|
21
|
+
pages: {
|
|
22
|
+
total: number;
|
|
23
|
+
groups: { groupID: string; isJoined: boolean }[];
|
|
24
|
+
}[];
|
|
25
|
+
pageParams: unknown[];
|
|
26
|
+
}>({ queryKey: groupQueryKeys.public(), exact: false }, (old) => {
|
|
27
|
+
if (!old) return old;
|
|
28
|
+
return {
|
|
29
|
+
...old,
|
|
30
|
+
pages: old.pages.map((page) => ({
|
|
31
|
+
...page,
|
|
32
|
+
groups: page.groups.map((g) =>
|
|
33
|
+
g.groupID === params.groupID ? { ...g, isJoined: true } : g
|
|
34
|
+
),
|
|
35
|
+
})),
|
|
36
|
+
};
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
UIUtils.toast.open({
|
|
40
|
+
title: trans('group:joined_group', {
|
|
41
|
+
groupName: params?.groupName || '',
|
|
42
|
+
}),
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
};
|
package/src/hooks/query-keys.ts
CHANGED
|
@@ -61,3 +61,11 @@ export const messageQueryKeys = {
|
|
|
61
61
|
search: (query: string, conversationId?: string) =>
|
|
62
62
|
[...messageQueryKeys.all, 'search', query, conversationId] as const,
|
|
63
63
|
};
|
|
64
|
+
|
|
65
|
+
export const groupQueryKeys = {
|
|
66
|
+
all: ['groups'] as const,
|
|
67
|
+
public: () => [...groupQueryKeys.all, 'public'] as const,
|
|
68
|
+
publicSearch: (keyword: string) =>
|
|
69
|
+
[...groupQueryKeys.public(), keyword] as const,
|
|
70
|
+
join: () => [...groupQueryKeys.all, 'join'] as const,
|
|
71
|
+
};
|
package/src/index.tsx
CHANGED
|
@@ -40,7 +40,11 @@ export type {
|
|
|
40
40
|
MessageItem,
|
|
41
41
|
ConversationItem,
|
|
42
42
|
} from '@droppii/openim-rn-client-sdk';
|
|
43
|
-
export {
|
|
43
|
+
export {
|
|
44
|
+
LoginStatus,
|
|
45
|
+
MessageType,
|
|
46
|
+
GroupJoinSource,
|
|
47
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
44
48
|
export * from './screens/chat-detail';
|
|
45
49
|
export type {
|
|
46
50
|
DChatActionItem,
|
|
@@ -122,7 +122,7 @@ const styles = StyleSheet.create({
|
|
|
122
122
|
tabRow: {
|
|
123
123
|
flexDirection: 'row',
|
|
124
124
|
borderBottomWidth: 1,
|
|
125
|
-
borderBottomColor: KColors.border.
|
|
125
|
+
borderBottomColor: KColors.border.light,
|
|
126
126
|
},
|
|
127
127
|
tabItem: {
|
|
128
128
|
paddingVertical: KSpacingValue['0.5rem'],
|
|
@@ -65,6 +65,7 @@ import { openBotMenuSheet } from './BotMenuSheet';
|
|
|
65
65
|
import { UIUtils } from '../../utils/UIUtils';
|
|
66
66
|
import { GroupPermission, PeerType } from '@droppii/openim-rn-client-sdk';
|
|
67
67
|
import { useGuardedAction } from '../../hooks/useGroupPermission';
|
|
68
|
+
import { useIsJoinedGroup } from '../../hooks/useIsJoinedGroup';
|
|
68
69
|
|
|
69
70
|
interface ChatComposerInternalProps {
|
|
70
71
|
isEmptyMessage?: boolean;
|
|
@@ -72,6 +73,8 @@ interface ChatComposerInternalProps {
|
|
|
72
73
|
isComposeDisabled?: boolean;
|
|
73
74
|
composerRef?: RefObject<View | null>;
|
|
74
75
|
onComposerLayout?: (event: LayoutChangeEvent) => void;
|
|
76
|
+
onPressJoinGroup?: () => void;
|
|
77
|
+
isJoiningGroup?: boolean;
|
|
75
78
|
}
|
|
76
79
|
|
|
77
80
|
export const ChatComposer = memo(
|
|
@@ -81,6 +84,8 @@ export const ChatComposer = memo(
|
|
|
81
84
|
isComposeDisabled = false,
|
|
82
85
|
composerRef,
|
|
83
86
|
onComposerLayout,
|
|
87
|
+
onPressJoinGroup,
|
|
88
|
+
isJoiningGroup = false,
|
|
84
89
|
}: ChatComposerInternalProps) => {
|
|
85
90
|
const insets = useSafeAreaInsets();
|
|
86
91
|
const isDisableCompose = isComposeDisabled;
|
|
@@ -100,6 +105,12 @@ export const ChatComposer = memo(
|
|
|
100
105
|
const { sendMessage } = useSendMessage();
|
|
101
106
|
const compose = useChatCompose();
|
|
102
107
|
|
|
108
|
+
const { data: isJoinedGroup } = useIsJoinedGroup(conversation?.groupID);
|
|
109
|
+
|
|
110
|
+
const isNotInGroup = useMemo(() => {
|
|
111
|
+
return conversation?.groupID ? !isJoinedGroup : false;
|
|
112
|
+
}, [conversation?.groupID, isJoinedGroup]);
|
|
113
|
+
|
|
103
114
|
const {
|
|
104
115
|
activePanelType,
|
|
105
116
|
setActivePanelType,
|
|
@@ -431,6 +442,30 @@ export const ChatComposer = memo(
|
|
|
431
442
|
/>
|
|
432
443
|
</KContainer.View>
|
|
433
444
|
);
|
|
445
|
+
} else if (isNotInGroup) {
|
|
446
|
+
content = (
|
|
447
|
+
<KContainer.View
|
|
448
|
+
paddingH="0.75rem"
|
|
449
|
+
justifyContent="center"
|
|
450
|
+
brTW={1}
|
|
451
|
+
brTC={KColors.border.light}
|
|
452
|
+
>
|
|
453
|
+
<KLabel.Text
|
|
454
|
+
typo="TextSmNormal"
|
|
455
|
+
textAlign="center"
|
|
456
|
+
paddingV={'0.75rem'}
|
|
457
|
+
>
|
|
458
|
+
{trans('group:not_in_group')}
|
|
459
|
+
</KLabel.Text>
|
|
460
|
+
<KButton.Solid
|
|
461
|
+
size="md"
|
|
462
|
+
label={trans('group:join')}
|
|
463
|
+
stretch
|
|
464
|
+
loading={isJoiningGroup}
|
|
465
|
+
onPress={onPressJoinGroup}
|
|
466
|
+
/>
|
|
467
|
+
</KContainer.View>
|
|
468
|
+
);
|
|
434
469
|
} else {
|
|
435
470
|
content = (
|
|
436
471
|
<KContainer.View background={'#F9F9FA'}>
|
|
@@ -30,10 +30,14 @@ import {
|
|
|
30
30
|
useGetConversationDetail,
|
|
31
31
|
useGetConversationTarget,
|
|
32
32
|
} from '../../hooks/conversation/useGetConversationDetail';
|
|
33
|
-
import
|
|
33
|
+
import {
|
|
34
|
+
GroupJoinSource,
|
|
35
|
+
type MessageItem,
|
|
36
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
34
37
|
import { useMessages } from '../../hooks/message/useMessages';
|
|
35
38
|
import { ChatEvent, type GroupRemovedPayload } from '../../types/events';
|
|
36
39
|
import { useSetIsShowFLashMessage } from '../../context/global';
|
|
40
|
+
import { useJoinGroup } from '../../hooks/groups/useJoinGroup';
|
|
37
41
|
|
|
38
42
|
const ChatDetail = memo(
|
|
39
43
|
({
|
|
@@ -50,6 +54,7 @@ const ChatDetail = memo(
|
|
|
50
54
|
onPressUrl,
|
|
51
55
|
customMessageItemFactory,
|
|
52
56
|
pannelActions,
|
|
57
|
+
groupJoinSource,
|
|
53
58
|
}: ChatDetailProps) => {
|
|
54
59
|
const navigation = useNavigation();
|
|
55
60
|
const mediaViewerRef = useRef<MediaViewerModalHandle>(null);
|
|
@@ -94,6 +99,8 @@ const ChatDetail = memo(
|
|
|
94
99
|
hasMoreNew,
|
|
95
100
|
} = useMessages({ conversationId, startClientMsgId: targetMessageId });
|
|
96
101
|
|
|
102
|
+
const { mutate: joinGroup, isPending: isJoiningGroup } = useJoinGroup();
|
|
103
|
+
|
|
97
104
|
const setShowFLashMessage = useSetIsShowFLashMessage();
|
|
98
105
|
|
|
99
106
|
const { pinnedMessages, pinMessage, unpinMessage } =
|
|
@@ -164,6 +171,21 @@ const ChatDetail = memo(
|
|
|
164
171
|
onPressMenu?.(conversationId);
|
|
165
172
|
}, [conversationId, onPressMenu]);
|
|
166
173
|
|
|
174
|
+
const handlePressJoinGroup = useCallback(() => {
|
|
175
|
+
if (!conversation?.groupID) return;
|
|
176
|
+
joinGroup({
|
|
177
|
+
groupID: conversation?.groupID,
|
|
178
|
+
reqMsg: '',
|
|
179
|
+
joinSource: groupJoinSource || GroupJoinSource.Search,
|
|
180
|
+
groupName: conversation?.showName || '',
|
|
181
|
+
});
|
|
182
|
+
}, [
|
|
183
|
+
groupJoinSource,
|
|
184
|
+
conversation?.groupID,
|
|
185
|
+
joinGroup,
|
|
186
|
+
conversation?.showName,
|
|
187
|
+
]);
|
|
188
|
+
|
|
167
189
|
return (
|
|
168
190
|
<KContainer.Page flex edges={['bottom']}>
|
|
169
191
|
<ChatDetailHeader
|
|
@@ -207,6 +229,8 @@ const ChatDetail = memo(
|
|
|
207
229
|
isEmptyMessage={messages?.length === 0}
|
|
208
230
|
pannelActions={pannelActions}
|
|
209
231
|
isComposeDisabled={isComposeDisabled}
|
|
232
|
+
onPressJoinGroup={handlePressJoinGroup}
|
|
233
|
+
isJoiningGroup={isJoiningGroup}
|
|
210
234
|
/>
|
|
211
235
|
|
|
212
236
|
<MediaViewerModal ref={mediaViewerRef} />
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
import type { MediaItem } from '../../hooks/useMediaViewer';
|
|
3
3
|
import type { MeasuredRect } from './messageToolbox/types';
|
|
4
|
-
import type {
|
|
4
|
+
import type {
|
|
5
|
+
GroupJoinSource,
|
|
6
|
+
MessageItem,
|
|
7
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
5
8
|
|
|
6
9
|
export type DChatActionIconProvider = 'MaterialCommunityIcons' | 'DroppiiNew';
|
|
7
10
|
|
|
@@ -100,4 +103,5 @@ export interface ChatDetailProps extends Omit<
|
|
|
100
103
|
onPressUrl?: (url: string) => void;
|
|
101
104
|
customMessageItemFactory?: (item: MessageItem) => ReactNode;
|
|
102
105
|
pannelActions?: DChatPannelAction[];
|
|
106
|
+
groupJoinSource?: GroupJoinSource;
|
|
103
107
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { KContainer, KSpacingValue } from '@droppii/libs';
|
|
2
|
+
import { memo, useCallback } from 'react';
|
|
3
|
+
import { ActivityIndicator, StyleSheet } from 'react-native';
|
|
4
|
+
import type { SearchPublicGroupInfo } from '@droppii/openim-rn-client-sdk';
|
|
5
|
+
import { useFetchPublicGroup } from '../../hooks/groups/useFetchPublicGroup';
|
|
6
|
+
import { GroupItem } from '../../components/GroupItem';
|
|
7
|
+
|
|
8
|
+
interface CommunityTabProps {
|
|
9
|
+
onPressGroup?: (groupId: string) => void;
|
|
10
|
+
}
|
|
11
|
+
export const CommunityTab = memo(({ onPressGroup }: CommunityTabProps) => {
|
|
12
|
+
const {
|
|
13
|
+
dataFlatten,
|
|
14
|
+
isFetching,
|
|
15
|
+
hasNextPage,
|
|
16
|
+
fetchNextPage,
|
|
17
|
+
isFetchingNextPage,
|
|
18
|
+
isRefetching,
|
|
19
|
+
refetch,
|
|
20
|
+
} = useFetchPublicGroup('');
|
|
21
|
+
|
|
22
|
+
const renderItem = useCallback(
|
|
23
|
+
({ item }: { item: SearchPublicGroupInfo }) => (
|
|
24
|
+
<GroupItem item={item} onPress={onPressGroup} />
|
|
25
|
+
),
|
|
26
|
+
[onPressGroup]
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const keyExtractor = useCallback(
|
|
30
|
+
(item: SearchPublicGroupInfo) => item.groupID,
|
|
31
|
+
[]
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const onEndReached = useCallback(() => {
|
|
35
|
+
if (hasNextPage && !isFetchingNextPage) {
|
|
36
|
+
fetchNextPage();
|
|
37
|
+
}
|
|
38
|
+
}, [hasNextPage, isFetchingNextPage, fetchNextPage]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<KContainer.Page flex>
|
|
42
|
+
{isFetching && !isFetchingNextPage && !isRefetching ? (
|
|
43
|
+
<KContainer.View flex center>
|
|
44
|
+
<ActivityIndicator />
|
|
45
|
+
</KContainer.View>
|
|
46
|
+
) : (
|
|
47
|
+
<KContainer.FlatList
|
|
48
|
+
data={dataFlatten}
|
|
49
|
+
renderItem={renderItem}
|
|
50
|
+
keyExtractor={keyExtractor}
|
|
51
|
+
onEndReached={onEndReached}
|
|
52
|
+
refreshing={isRefetching}
|
|
53
|
+
onRefresh={refetch}
|
|
54
|
+
contentContainerStyle={styles.contentContainer}
|
|
55
|
+
/>
|
|
56
|
+
)}
|
|
57
|
+
</KContainer.Page>
|
|
58
|
+
);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const styles = StyleSheet.create({
|
|
62
|
+
contentContainer: {
|
|
63
|
+
paddingHorizontal: KSpacingValue['0.75rem'],
|
|
64
|
+
},
|
|
65
|
+
});
|
|
@@ -1,38 +1,56 @@
|
|
|
1
1
|
import { memo, useCallback, useState } from 'react';
|
|
2
2
|
import { StyleSheet } from 'react-native';
|
|
3
3
|
import { TabView } from 'react-native-tab-view';
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
KContainer,
|
|
6
|
+
KImage,
|
|
7
|
+
KLabel,
|
|
8
|
+
KColors,
|
|
9
|
+
KRadiusValue,
|
|
10
|
+
KSpacingValue,
|
|
11
|
+
} from '@droppii/libs';
|
|
5
12
|
import { MessagesTab } from './MessagesTab';
|
|
13
|
+
import { trans } from '../../translation';
|
|
14
|
+
import { CommunityTab } from './CommunityTab';
|
|
6
15
|
|
|
7
16
|
interface InboxProps {
|
|
8
17
|
onPressThread?: (item: string) => void;
|
|
9
18
|
onPressSearch?: () => void;
|
|
10
19
|
onPressEdit?: () => void;
|
|
11
20
|
onPressContact?: () => void;
|
|
21
|
+
onPressGroup?: (groupId: string) => void;
|
|
12
22
|
}
|
|
13
23
|
|
|
14
24
|
type TabRoute = { key: string; title: string };
|
|
15
25
|
|
|
26
|
+
const TabRoutes: TabRoute[] = [
|
|
27
|
+
{ key: 'messages', title: trans('messages') },
|
|
28
|
+
{ key: 'community', title: trans('community') },
|
|
29
|
+
];
|
|
30
|
+
|
|
16
31
|
const Inbox = memo(
|
|
17
32
|
({
|
|
18
33
|
onPressThread,
|
|
19
34
|
onPressSearch,
|
|
20
35
|
onPressEdit,
|
|
21
36
|
onPressContact,
|
|
37
|
+
onPressGroup,
|
|
22
38
|
}: InboxProps) => {
|
|
23
39
|
const [index, setIndex] = useState(0);
|
|
24
|
-
const [routes] = useState<TabRoute[]>(
|
|
25
|
-
{ key: 'messages', title: 'Tin nhắn' },
|
|
26
|
-
]);
|
|
40
|
+
const [routes] = useState<TabRoute[]>(TabRoutes);
|
|
27
41
|
|
|
28
42
|
const renderScene = useCallback(
|
|
29
43
|
({ route }: { route: TabRoute }) => {
|
|
30
|
-
|
|
31
|
-
|
|
44
|
+
switch (route.key) {
|
|
45
|
+
case 'messages':
|
|
46
|
+
return <MessagesTab onPressThread={onPressThread} />;
|
|
47
|
+
case 'community':
|
|
48
|
+
return <CommunityTab onPressGroup={onPressGroup} />;
|
|
49
|
+
default:
|
|
50
|
+
return null;
|
|
32
51
|
}
|
|
33
|
-
return null;
|
|
34
52
|
},
|
|
35
|
-
[onPressThread]
|
|
53
|
+
[onPressThread, onPressGroup]
|
|
36
54
|
);
|
|
37
55
|
|
|
38
56
|
const renderTabBar = useCallback(
|
|
@@ -46,24 +64,18 @@ const Inbox = memo(
|
|
|
46
64
|
<KContainer.Touchable
|
|
47
65
|
key={route.key}
|
|
48
66
|
onPress={() => setIndex(i)}
|
|
49
|
-
paddingV="0.75rem"
|
|
50
|
-
marginR="1rem"
|
|
51
67
|
style={styles.tabItem}
|
|
52
68
|
activeOpacity={0.7}
|
|
53
69
|
>
|
|
54
70
|
<KLabel.Text
|
|
55
71
|
typo="TextNmBold"
|
|
56
72
|
color={
|
|
57
|
-
isActive
|
|
58
|
-
? KColors.palette.primary.w400
|
|
59
|
-
: KColors.palette.gray.w500
|
|
73
|
+
isActive ? KColors.primary.normal : KColors.gray.light
|
|
60
74
|
}
|
|
61
75
|
>
|
|
62
76
|
{route.title}
|
|
63
77
|
</KLabel.Text>
|
|
64
|
-
{isActive &&
|
|
65
|
-
<KContainer.View style={styles.activeIndicator} />
|
|
66
|
-
)}
|
|
78
|
+
{isActive && <KContainer.View style={styles.indicator} />}
|
|
67
79
|
</KContainer.Touchable>
|
|
68
80
|
);
|
|
69
81
|
})}
|
|
@@ -77,10 +89,9 @@ const Inbox = memo(
|
|
|
77
89
|
activeOpacity={0.7}
|
|
78
90
|
>
|
|
79
91
|
<KImage.VectorIcons
|
|
80
|
-
name="
|
|
81
|
-
provider="MaterialCommunityIcons"
|
|
92
|
+
name="search-o"
|
|
82
93
|
size={24}
|
|
83
|
-
color={KColors.
|
|
94
|
+
color={KColors.primary.normal}
|
|
84
95
|
/>
|
|
85
96
|
</KContainer.Touchable>
|
|
86
97
|
<KContainer.Touchable
|
|
@@ -89,10 +100,9 @@ const Inbox = memo(
|
|
|
89
100
|
activeOpacity={0.7}
|
|
90
101
|
>
|
|
91
102
|
<KImage.VectorIcons
|
|
92
|
-
name="
|
|
93
|
-
provider="MaterialCommunityIcons"
|
|
103
|
+
name="plus-circle-o"
|
|
94
104
|
size={24}
|
|
95
|
-
color={KColors.
|
|
105
|
+
color={KColors.primary.normal}
|
|
96
106
|
/>
|
|
97
107
|
</KContainer.Touchable>
|
|
98
108
|
<KContainer.Touchable
|
|
@@ -101,10 +111,9 @@ const Inbox = memo(
|
|
|
101
111
|
activeOpacity={0.7}
|
|
102
112
|
>
|
|
103
113
|
<KImage.VectorIcons
|
|
104
|
-
name="
|
|
105
|
-
provider="MaterialCommunityIcons"
|
|
114
|
+
name="user-three-o"
|
|
106
115
|
size={24}
|
|
107
|
-
color={KColors.
|
|
116
|
+
color={KColors.primary.normal}
|
|
108
117
|
/>
|
|
109
118
|
</KContainer.Touchable>
|
|
110
119
|
</KContainer.View>
|
|
@@ -114,13 +123,13 @@ const Inbox = memo(
|
|
|
114
123
|
);
|
|
115
124
|
|
|
116
125
|
return (
|
|
117
|
-
<KContainer.Page flex edges={['top'
|
|
126
|
+
<KContainer.Page flex edges={['top']}>
|
|
118
127
|
<TabView
|
|
119
128
|
navigationState={{ index, routes }}
|
|
120
129
|
renderScene={renderScene}
|
|
121
130
|
renderTabBar={renderTabBar}
|
|
122
131
|
onIndexChange={setIndex}
|
|
123
|
-
|
|
132
|
+
lazy
|
|
124
133
|
/>
|
|
125
134
|
</KContainer.Page>
|
|
126
135
|
);
|
|
@@ -133,25 +142,28 @@ export default Inbox;
|
|
|
133
142
|
|
|
134
143
|
const styles = StyleSheet.create({
|
|
135
144
|
tabBar: {
|
|
136
|
-
borderBottomWidth:
|
|
137
|
-
borderBottomColor: KColors.
|
|
138
|
-
|
|
145
|
+
borderBottomWidth: 1,
|
|
146
|
+
borderBottomColor: KColors.border.light,
|
|
147
|
+
paddingTop: 2,
|
|
139
148
|
},
|
|
140
149
|
tabItem: {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
height: 40,
|
|
151
|
+
marginHorizontal: KSpacingValue['0.75rem'],
|
|
152
|
+
justifyContent: 'center',
|
|
153
|
+
alignItems: 'center',
|
|
144
154
|
},
|
|
145
|
-
|
|
155
|
+
indicator: {
|
|
156
|
+
height: 3,
|
|
157
|
+
backgroundColor: KColors.primary.normal,
|
|
158
|
+
width: '100%',
|
|
159
|
+
borderRadius: KRadiusValue.x,
|
|
146
160
|
position: 'absolute',
|
|
147
|
-
bottom:
|
|
161
|
+
bottom: -1,
|
|
148
162
|
left: 0,
|
|
149
163
|
right: 0,
|
|
150
|
-
height: 3,
|
|
151
|
-
borderRadius: 4,
|
|
152
|
-
backgroundColor: KColors.palette.primary.w400,
|
|
153
164
|
},
|
|
154
165
|
actionGroup: {
|
|
155
|
-
gap:
|
|
166
|
+
gap: KSpacingValue['0.25rem'],
|
|
167
|
+
paddingRight: KSpacingValue['0.5rem'],
|
|
156
168
|
},
|
|
157
169
|
});
|
|
@@ -165,6 +165,13 @@ const i18nKey: Record<string, string> = {
|
|
|
165
165
|
'search_message:revoked_message': 'Tin nhắn đã được thu hồi',
|
|
166
166
|
'chat:no_permission': 'Bạn không có quyền này',
|
|
167
167
|
'chat:no_send_permission': 'Bạn không có quyền gửi tin nhắn',
|
|
168
|
+
'community': 'Cộng đồng',
|
|
169
|
+
'group:member_count': '{{count}} thành viên',
|
|
170
|
+
'group:access': 'Truy cập',
|
|
171
|
+
'group:join': 'Tham gia',
|
|
172
|
+
'group:not_in_group': 'Bạn cần tham gia nhóm để gửi tin nhắn',
|
|
173
|
+
'group:cannot_send_message': 'Bạn không thể gửi tin nhắn vào nhóm này',
|
|
174
|
+
'group:joined_group': 'Đã tham gia nhóm {{groupName}}',
|
|
168
175
|
};
|
|
169
176
|
|
|
170
177
|
export default {
|