@droppii-org/chat-mobile 0.2.18 → 0.2.19
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/ThreadCard/AvatarSection.js.map +1 -1
- package/lib/module/components/ThreadCard/ThreadCard.js +17 -9
- package/lib/module/components/ThreadCard/ThreadCard.js.map +1 -1
- package/lib/module/components/flows/inputButtons/index.js +7 -3
- package/lib/module/components/flows/inputButtons/index.js.map +1 -1
- package/lib/module/context/ChatContext.js +27 -4
- package/lib/module/context/ChatContext.js.map +1 -1
- package/lib/module/context/ChatDetailContext.js.map +1 -1
- package/lib/module/core/useChatListener.js +2 -4
- package/lib/module/core/useChatListener.js.map +1 -1
- package/lib/module/core/useUserListener.js +0 -7
- package/lib/module/core/useUserListener.js.map +1 -1
- package/lib/module/hooks/flows/useFlow.js +14 -3
- package/lib/module/hooks/flows/useFlow.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +1 -1
- package/lib/module/hooks/message/useSendMessage.js.map +1 -1
- package/lib/module/hooks/useConversationList.js +3 -27
- package/lib/module/hooks/useConversationList.js.map +1 -1
- package/lib/module/hooks/useLinkPreview/useLinkPreview.js +1 -1
- package/lib/module/hooks/useLinkPreview/useLinkPreview.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +1 -6
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetailHeader.js +6 -6
- package/lib/module/screens/chat-detail/ChatDetailHeader.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatLinkPreview.js +3 -1
- package/lib/module/screens/chat-detail/ChatLinkPreview.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +2 -2
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/conversationHeader.utils.js +9 -0
- package/lib/module/screens/chat-detail/conversationHeader.utils.js.map +1 -1
- package/lib/module/screens/inbox/Inbox.js +5 -1
- package/lib/module/screens/inbox/Inbox.js.map +1 -1
- package/lib/module/services/apis.js +0 -20
- package/lib/module/services/apis.js.map +1 -1
- package/lib/module/store/conversation.js +1 -38
- package/lib/module/store/conversation.js.map +1 -1
- package/lib/module/types/auth.js.map +1 -1
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/utils/conversation.js +1 -28
- package/lib/module/utils/conversation.js.map +1 -1
- package/lib/module/utils/message.js.map +1 -1
- package/lib/module/utils/messageUtils.js +5 -3
- package/lib/module/utils/messageUtils.js.map +1 -1
- package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts +2 -2
- package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts.map +1 -1
- package/lib/typescript/src/components/ThreadCard/ThreadCard.d.ts.map +1 -1
- package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
- package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
- package/lib/typescript/src/core/useUserListener.d.ts.map +1 -1
- package/lib/typescript/src/hooks/flows/useFlow.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useConversationList.d.ts +2 -2
- package/lib/typescript/src/hooks/useConversationList.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useLinkPreview/useLinkPreview.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/ChatDetailHeader.d.ts +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatDetailHeader.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatLinkPreview.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/conversationHeader.utils.d.ts +7 -5
- package/lib/typescript/src/screens/chat-detail/conversationHeader.utils.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +6 -9
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/screens/inbox/Inbox.d.ts.map +1 -1
- package/lib/typescript/src/services/apis.d.ts +0 -4
- package/lib/typescript/src/services/apis.d.ts.map +1 -1
- package/lib/typescript/src/store/conversation.d.ts +5 -8
- package/lib/typescript/src/store/conversation.d.ts.map +1 -1
- package/lib/typescript/src/types/auth.d.ts +1 -0
- package/lib/typescript/src/types/auth.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +15 -13
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/utils/conversation.d.ts +2 -5
- package/lib/typescript/src/utils/conversation.d.ts.map +1 -1
- package/lib/typescript/src/utils/message.d.ts +3 -3
- package/lib/typescript/src/utils/message.d.ts.map +1 -1
- package/lib/typescript/src/utils/messageUtils.d.ts +2 -1
- package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/components/ThreadCard/AvatarSection.tsx +2 -3
- package/src/components/ThreadCard/ThreadCard.tsx +22 -15
- package/src/components/flows/inputButtons/index.tsx +4 -1
- package/src/context/ChatContext.tsx +35 -3
- package/src/context/ChatDetailContext.tsx +1 -1
- package/src/core/useChatListener.ts +2 -4
- package/src/core/useUserListener.ts +0 -8
- package/src/hooks/flows/useFlow.ts +12 -3
- package/src/hooks/message/useSendMessage.ts +1 -1
- package/src/hooks/useConversationList.ts +6 -40
- package/src/hooks/useLinkPreview/useLinkPreview.ts +6 -1
- package/src/screens/chat-detail/ChatDetail.tsx +1 -7
- package/src/screens/chat-detail/ChatDetailHeader.tsx +6 -7
- package/src/screens/chat-detail/ChatLinkPreview.tsx +16 -12
- package/src/screens/chat-detail/ChatListLegend.tsx +2 -6
- package/src/screens/chat-detail/conversationHeader.utils.ts +16 -6
- package/src/screens/chat-detail/types.ts +6 -13
- package/src/screens/inbox/Inbox.tsx +5 -1
- package/src/services/apis.ts +0 -38
- package/src/store/conversation.ts +6 -55
- package/src/types/auth.ts +1 -0
- package/src/types/chat.ts +16 -20
- package/src/utils/conversation.ts +2 -40
- package/src/utils/message.ts +3 -2
- package/src/utils/messageUtils.ts +11 -3
|
@@ -47,7 +47,7 @@ export const ChatDetailProvider = ({ children }: ChatDetailProviderProps) => {
|
|
|
47
47
|
return conversation?.peerType === PeerType.Bot;
|
|
48
48
|
}, [conversation]);
|
|
49
49
|
|
|
50
|
-
const setConverationFlowStep = useCallback((step
|
|
50
|
+
const setConverationFlowStep = useCallback((step?: IConversationFlowStep) => {
|
|
51
51
|
setConverationFlow(
|
|
52
52
|
(prev) =>
|
|
53
53
|
({
|
|
@@ -10,16 +10,14 @@ export const useChatListener = () => {
|
|
|
10
10
|
const onConversationChanged = useCallback(
|
|
11
11
|
(conversations: ConversationItem[]) => {
|
|
12
12
|
console.log('onConversationChanged', conversations);
|
|
13
|
-
useConversationStore.getState().
|
|
13
|
+
useConversationStore.getState().updateConversations(conversations);
|
|
14
14
|
},
|
|
15
15
|
[]
|
|
16
16
|
);
|
|
17
17
|
|
|
18
18
|
const onNewConversation = useCallback((conversations: ConversationItem[]) => {
|
|
19
19
|
console.log('onNewConversation', conversations);
|
|
20
|
-
|
|
21
|
-
// isn't in the store yet, which triggers a full refetch in useConversationList.
|
|
22
|
-
useConversationStore.getState().mergeOpenIMConversations(conversations);
|
|
20
|
+
useConversationStore.getState().updateConversations(conversations);
|
|
23
21
|
}, []);
|
|
24
22
|
|
|
25
23
|
const onGroupMemberAdded = useCallback((member: GroupMemberItem) => {
|
|
@@ -21,14 +21,6 @@ export const useUserListener = () => {
|
|
|
21
21
|
}
|
|
22
22
|
}, []);
|
|
23
23
|
|
|
24
|
-
useEffect(() => {
|
|
25
|
-
ChatAPI.getLoginStatus().then((value) => {
|
|
26
|
-
if (value) {
|
|
27
|
-
useUserStore.getState().updateConnectStatus(LoginStatus.Logged);
|
|
28
|
-
}
|
|
29
|
-
});
|
|
30
|
-
}, []);
|
|
31
|
-
|
|
32
24
|
useEffect(() => {
|
|
33
25
|
if (isLoggedIn) {
|
|
34
26
|
fetchAndUpdateUser();
|
|
@@ -11,14 +11,25 @@ import type {
|
|
|
11
11
|
} from '../../types/flows';
|
|
12
12
|
import { useSendMessage } from '../message/useSendMessage';
|
|
13
13
|
import { useChatDetailContext } from '../../context/ChatDetailContext';
|
|
14
|
+
import { trans } from '../../translation';
|
|
14
15
|
|
|
15
16
|
export const useResetFlow = () => {
|
|
16
17
|
const conversationId =
|
|
17
18
|
useConversationStore((state) => state.currentConversationId) || '';
|
|
18
19
|
const { mutate: runFlow } = useRunFlow();
|
|
20
|
+
const { sendMessage } = useSendMessage();
|
|
21
|
+
const conversationFlow = useChatDetailContext().conversationFlow;
|
|
19
22
|
return useMutation({
|
|
20
23
|
mutationKey: conversationQueryKeys.flow(conversationId),
|
|
21
24
|
mutationFn: async () => {
|
|
25
|
+
await sendMessage({
|
|
26
|
+
plainText: trans('restart'),
|
|
27
|
+
flow: {
|
|
28
|
+
groupId: conversationFlow?.flowCurrentStep?.id || '',
|
|
29
|
+
childId: null,
|
|
30
|
+
actionId: null,
|
|
31
|
+
},
|
|
32
|
+
});
|
|
22
33
|
const res = await apiInstance?.post<BaseResponse<IConversationFlow>>(
|
|
23
34
|
ENDPOINTS.chatService.resetConversationFlow(conversationId),
|
|
24
35
|
{}
|
|
@@ -55,9 +66,7 @@ export const useRunFlow = () => {
|
|
|
55
66
|
return res?.data?.data || undefined;
|
|
56
67
|
},
|
|
57
68
|
onSuccess: (data) => {
|
|
58
|
-
|
|
59
|
-
setConverationFlowStep(data?.flowNextStep);
|
|
60
|
-
}
|
|
69
|
+
setConverationFlowStep(data?.flowNextStep || undefined);
|
|
61
70
|
},
|
|
62
71
|
});
|
|
63
72
|
};
|
|
@@ -106,7 +106,7 @@ const generateOfflinePushInfo = (
|
|
|
106
106
|
desc,
|
|
107
107
|
ex: JSON.stringify({
|
|
108
108
|
icon: conversationData?.faceURL || '',
|
|
109
|
-
conversationId: conversationData?.
|
|
109
|
+
conversationId: conversationData?.conversationID || '',
|
|
110
110
|
title,
|
|
111
111
|
desc,
|
|
112
112
|
}),
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
import { useEffect } from 'react';
|
|
2
2
|
import { useQuery } from '@tanstack/react-query';
|
|
3
|
-
import OpenIMSDK
|
|
4
|
-
type ConversationItem,
|
|
5
|
-
} from '@droppii/openim-rn-client-sdk';
|
|
3
|
+
import OpenIMSDK from '@droppii/openim-rn-client-sdk';
|
|
6
4
|
import { conversationQueryKeys } from './query-keys';
|
|
7
5
|
import { useConversationStore } from '../store';
|
|
8
|
-
import type {
|
|
9
|
-
DChatApplicationType,
|
|
10
|
-
DConversationItem,
|
|
11
|
-
DMessageItem,
|
|
12
|
-
} from '../types/chat';
|
|
6
|
+
import type { DChatApplicationType } from '../types/chat';
|
|
13
7
|
|
|
14
8
|
type Params = {
|
|
15
9
|
applicationType: DChatApplicationType;
|
|
@@ -17,34 +11,6 @@ type Params = {
|
|
|
17
11
|
enabled?: boolean;
|
|
18
12
|
};
|
|
19
13
|
|
|
20
|
-
function toConversationItem(raw: ConversationItem): DConversationItem {
|
|
21
|
-
let lastMessage: DMessageItem | undefined;
|
|
22
|
-
if (raw.latestMsg) {
|
|
23
|
-
try {
|
|
24
|
-
lastMessage = JSON.parse(raw.latestMsg) as DMessageItem;
|
|
25
|
-
} catch {
|
|
26
|
-
// leave undefined
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
let applicationType: DChatApplicationType | undefined;
|
|
31
|
-
if (raw.ex) {
|
|
32
|
-
try {
|
|
33
|
-
applicationType = (
|
|
34
|
-
JSON.parse(raw.ex) as { applicationType?: DChatApplicationType }
|
|
35
|
-
).applicationType;
|
|
36
|
-
} catch {
|
|
37
|
-
// leave undefined
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
...(raw as DConversationItem),
|
|
43
|
-
lastMessage,
|
|
44
|
-
applicationType: applicationType as DChatApplicationType,
|
|
45
|
-
};
|
|
46
|
-
}
|
|
47
|
-
|
|
48
14
|
export function useConversationList({
|
|
49
15
|
applicationType,
|
|
50
16
|
page = 1,
|
|
@@ -58,13 +24,13 @@ export function useConversationList({
|
|
|
58
24
|
queryKey: [...conversationQueryKeys.list(applicationType), page],
|
|
59
25
|
enabled: enabled !== false,
|
|
60
26
|
queryFn: async () => {
|
|
61
|
-
const offset = (page - 1) *
|
|
62
|
-
const
|
|
27
|
+
const offset = (page - 1) * 500;
|
|
28
|
+
const conversations = await OpenIMSDK.getConversationListSplitApp({
|
|
63
29
|
offset,
|
|
64
|
-
count:
|
|
30
|
+
count: 500,
|
|
65
31
|
applicationType,
|
|
66
32
|
});
|
|
67
|
-
|
|
33
|
+
|
|
68
34
|
useConversationStore.getState().updateConversations(conversations);
|
|
69
35
|
return conversations;
|
|
70
36
|
},
|
|
@@ -27,5 +27,10 @@ export function useLinkPreview(value: string | undefined) {
|
|
|
27
27
|
|
|
28
28
|
const isVisible = !!detectedUrl && !isDismissed && (isLoading || !!metadata);
|
|
29
29
|
|
|
30
|
-
return {
|
|
30
|
+
return {
|
|
31
|
+
isVisible,
|
|
32
|
+
metadata: !isLoading ? metadata || undefined : undefined,
|
|
33
|
+
isLoading,
|
|
34
|
+
dismiss,
|
|
35
|
+
};
|
|
31
36
|
}
|
|
@@ -43,8 +43,6 @@ const ChatDetail = memo(
|
|
|
43
43
|
subtitle,
|
|
44
44
|
avatarUri,
|
|
45
45
|
avatarFullName,
|
|
46
|
-
peerType,
|
|
47
|
-
applicationType,
|
|
48
46
|
showAddMember,
|
|
49
47
|
getSubtitle,
|
|
50
48
|
onBack,
|
|
@@ -139,9 +137,6 @@ const ChatDetail = memo(
|
|
|
139
137
|
const resolvedAvatarUri =
|
|
140
138
|
avatarUri ?? getConversationAvatarUri(conversation);
|
|
141
139
|
const resolvedAvatarFullName = avatarFullName ?? resolvedTitle;
|
|
142
|
-
const resolvedPeerType = peerType;
|
|
143
|
-
const resolvedApplicationType =
|
|
144
|
-
applicationType ?? conversation?.applicationType;
|
|
145
140
|
const resolvedShowAddMember =
|
|
146
141
|
showAddMember ?? shouldShowAddMember(conversation);
|
|
147
142
|
const resolvedSubtitle = useMemo(() => {
|
|
@@ -234,12 +229,11 @@ const ChatDetail = memo(
|
|
|
234
229
|
<ChatDetailProvider>
|
|
235
230
|
<KContainer.Page flex edges={['bottom']}>
|
|
236
231
|
<ChatDetailHeader
|
|
232
|
+
conversationId={conversationId}
|
|
237
233
|
title={resolvedTitle}
|
|
238
234
|
subtitle={resolvedSubtitle}
|
|
239
235
|
avatarUri={resolvedAvatarUri}
|
|
240
236
|
avatarFullName={resolvedAvatarFullName}
|
|
241
|
-
peerType={resolvedPeerType}
|
|
242
|
-
applicationType={resolvedApplicationType}
|
|
243
237
|
showAddMember={resolvedShowAddMember}
|
|
244
238
|
onBack={onBack ?? handleBackDefault}
|
|
245
239
|
onPressSearch={
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
import { AvatarSection } from '../../components/ThreadCard/AvatarSection';
|
|
10
10
|
import { NamePrefixIcon } from '../../components/ThreadCard/NamePrefixIcon';
|
|
11
11
|
import type { ChatDetailHeaderProps } from './types';
|
|
12
|
+
import { useConversation } from '../../store';
|
|
12
13
|
|
|
13
14
|
const ChatDetailHeader = memo(
|
|
14
15
|
({
|
|
@@ -16,15 +17,15 @@ const ChatDetailHeader = memo(
|
|
|
16
17
|
subtitle,
|
|
17
18
|
avatarUri,
|
|
18
19
|
avatarFullName,
|
|
19
|
-
peerType,
|
|
20
|
-
applicationType,
|
|
21
20
|
showAddMember = false,
|
|
21
|
+
conversationId,
|
|
22
22
|
onBack,
|
|
23
23
|
onPressSearch,
|
|
24
24
|
onPressAddMember,
|
|
25
25
|
onPressMenu,
|
|
26
26
|
onPressAvatar,
|
|
27
27
|
}: ChatDetailHeaderProps) => {
|
|
28
|
+
const conversation = useConversation(conversationId);
|
|
28
29
|
const rightButtons = useMemo(() => {
|
|
29
30
|
const buttons = [
|
|
30
31
|
{
|
|
@@ -80,13 +81,12 @@ const ChatDetailHeader = memo(
|
|
|
80
81
|
<AvatarSection
|
|
81
82
|
avatar={avatarUri ?? null}
|
|
82
83
|
fullName={avatarFullName ?? title}
|
|
83
|
-
peerType={peerType}
|
|
84
|
-
applicationType={applicationType}
|
|
84
|
+
peerType={conversation?.peerType}
|
|
85
85
|
/>
|
|
86
86
|
|
|
87
87
|
<KContainer.View flex marginL="0.5rem">
|
|
88
88
|
<KContainer.View row alignItems>
|
|
89
|
-
<NamePrefixIcon peerType={peerType} />
|
|
89
|
+
<NamePrefixIcon peerType={conversation?.peerType} />
|
|
90
90
|
<KLabel.Text
|
|
91
91
|
typo="TextLgBold"
|
|
92
92
|
color={KColors.gray.dark}
|
|
@@ -112,12 +112,11 @@ const ChatDetailHeader = memo(
|
|
|
112
112
|
[
|
|
113
113
|
avatarFullName,
|
|
114
114
|
avatarUri,
|
|
115
|
-
peerType,
|
|
116
|
-
applicationType,
|
|
117
115
|
onBack,
|
|
118
116
|
onPressAvatar,
|
|
119
117
|
subtitle,
|
|
120
118
|
title,
|
|
119
|
+
conversation?.peerType,
|
|
121
120
|
]
|
|
122
121
|
);
|
|
123
122
|
|
|
@@ -34,18 +34,22 @@ export const ChatLinkPreview = memo(
|
|
|
34
34
|
/>
|
|
35
35
|
)}
|
|
36
36
|
</KContainer.View>
|
|
37
|
-
|
|
38
|
-
<
|
|
39
|
-
{
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
{metadata ? (
|
|
38
|
+
<KContainer.View style={styles.center}>
|
|
39
|
+
<KLabel.Text typo="TextNmMedium" numberOfLines={1}>
|
|
40
|
+
{metadata?.title}
|
|
41
|
+
</KLabel.Text>
|
|
42
|
+
<KLabel.Text
|
|
43
|
+
typo="TextSmNormal"
|
|
44
|
+
color={KColors.gray.light}
|
|
45
|
+
numberOfLines={1}
|
|
46
|
+
>
|
|
47
|
+
{metadata?.description}
|
|
48
|
+
</KLabel.Text>
|
|
49
|
+
</KContainer.View>
|
|
50
|
+
) : (
|
|
51
|
+
<KContainer.View flex />
|
|
52
|
+
)}
|
|
49
53
|
<KContainer.Touchable onPress={onDismiss} style={styles.right}>
|
|
50
54
|
<KImage.VectorIcons name="close-o" size={16} />
|
|
51
55
|
</KContainer.Touchable>
|
|
@@ -349,12 +349,8 @@ export const ChatListLegend = memo(
|
|
|
349
349
|
renderItem={renderItem}
|
|
350
350
|
estimatedItemSize={avgItemHeightRef.current}
|
|
351
351
|
keyExtractor={(item) => String(item.clientMsgID || item.serverMsgID)}
|
|
352
|
-
recycleItems={
|
|
353
|
-
extraData={
|
|
354
|
-
!isBotConversation
|
|
355
|
-
? `${conversationFlow?.flowCurrentStep?.id ?? ''}-${lastMessageId ?? ''}`
|
|
356
|
-
: undefined
|
|
357
|
-
}
|
|
352
|
+
recycleItems={false}
|
|
353
|
+
extraData={`${conversationFlow?.flowCurrentStep?.id ?? ''}-${lastMessageId ?? ''}`}
|
|
358
354
|
alignItemsAtEnd
|
|
359
355
|
maintainVisibleContentPosition={maintainVisiblePositionConfig}
|
|
360
356
|
maintainScrollAtEnd={maintainScrollConfig}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PeerType } from '@droppii/openim-rn-client-sdk';
|
|
2
|
-
import {
|
|
1
|
+
import { PeerType, type ConversationItem } from '@droppii/openim-rn-client-sdk';
|
|
2
|
+
import type { IConversationItemEx } from '../../types/chat';
|
|
3
3
|
|
|
4
4
|
export const getConversationTitle = (
|
|
5
|
-
conversation?:
|
|
5
|
+
conversation?: ConversationItem
|
|
6
6
|
): string => {
|
|
7
7
|
if (!conversation) {
|
|
8
8
|
return 'Tin nhắn';
|
|
@@ -12,13 +12,13 @@ export const getConversationTitle = (
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
export const getConversationAvatarUri = (
|
|
15
|
-
conversation?:
|
|
15
|
+
conversation?: ConversationItem
|
|
16
16
|
): string | null => {
|
|
17
17
|
return conversation?.faceURL ?? null;
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
export const getConversationSubtitle = (
|
|
21
|
-
conversation?:
|
|
21
|
+
conversation?: ConversationItem
|
|
22
22
|
): string | undefined => {
|
|
23
23
|
if (!conversation) {
|
|
24
24
|
return undefined;
|
|
@@ -40,7 +40,17 @@ export const getConversationSubtitle = (
|
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
export const shouldShowAddMember = (
|
|
43
|
-
conversation?:
|
|
43
|
+
conversation?: ConversationItem
|
|
44
44
|
): boolean => {
|
|
45
45
|
return conversation?.peerType === PeerType.Group;
|
|
46
46
|
};
|
|
47
|
+
|
|
48
|
+
export const getConversationEx = (ex?: string): IConversationItemEx | {} => {
|
|
49
|
+
let result: IConversationItemEx | {} = {};
|
|
50
|
+
try {
|
|
51
|
+
result = JSON.parse(ex || '{}');
|
|
52
|
+
} catch {
|
|
53
|
+
///
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
};
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
2
|
|
|
3
3
|
import type { MediaItem } from '../../hooks/useMediaViewer';
|
|
4
|
-
import type {
|
|
5
|
-
DChatApplicationType,
|
|
6
|
-
DConversationItem,
|
|
7
|
-
DMessageItem,
|
|
8
|
-
} from '../../types/chat';
|
|
4
|
+
import type { DMessageItem } from '../../types/chat';
|
|
9
5
|
import type { IUrlMetadata } from '../../types/common';
|
|
10
|
-
import type {
|
|
6
|
+
import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
|
|
11
7
|
|
|
12
8
|
export type DChatActionIconProvider = 'MaterialCommunityIcons' | 'DroppiiNew';
|
|
13
9
|
|
|
@@ -29,14 +25,13 @@ export interface ChatDetailHeaderProps {
|
|
|
29
25
|
subtitle?: string;
|
|
30
26
|
avatarUri?: string | null;
|
|
31
27
|
avatarFullName?: string;
|
|
32
|
-
peerType?: PeerType;
|
|
33
|
-
applicationType?: DConversationItem['applicationType'];
|
|
34
28
|
showAddMember?: boolean;
|
|
35
29
|
onBack?: () => void;
|
|
36
30
|
onPressSearch?: () => void;
|
|
37
31
|
onPressAddMember?: () => void;
|
|
38
32
|
onPressMenu?: () => void;
|
|
39
33
|
onPressAvatar?: () => void;
|
|
34
|
+
conversationId: string;
|
|
40
35
|
}
|
|
41
36
|
|
|
42
37
|
export interface ChatQuickActionsRenderParams {
|
|
@@ -103,9 +98,9 @@ export interface ChatDetailProps extends Omit<
|
|
|
103
98
|
| 'subtitle'
|
|
104
99
|
| 'avatarUri'
|
|
105
100
|
| 'avatarFullName'
|
|
106
|
-
| 'peerType'
|
|
107
101
|
| 'applicationType'
|
|
108
102
|
| 'showAddMember'
|
|
103
|
+
| 'conversationId'
|
|
109
104
|
> {
|
|
110
105
|
conversationId: string;
|
|
111
106
|
enabled?: boolean;
|
|
@@ -113,16 +108,14 @@ export interface ChatDetailProps extends Omit<
|
|
|
113
108
|
subtitle?: string;
|
|
114
109
|
avatarUri?: string | null;
|
|
115
110
|
avatarFullName?: string;
|
|
116
|
-
peerType?: PeerType;
|
|
117
|
-
applicationType?: DChatApplicationType;
|
|
118
111
|
showAddMember?: boolean;
|
|
119
|
-
getSubtitle?: (conversation:
|
|
112
|
+
getSubtitle?: (conversation: ConversationItem) => string | undefined;
|
|
120
113
|
renderChat?: (item: DMessageItem) => ReactNode;
|
|
121
114
|
showQuickActions?: boolean;
|
|
122
115
|
showAttachmentActions?: boolean;
|
|
123
116
|
quickActions?: DChatQuickAction[];
|
|
124
117
|
getQuickActions?: (
|
|
125
|
-
conversation:
|
|
118
|
+
conversation: ConversationItem
|
|
126
119
|
) => DChatQuickAction[] | undefined;
|
|
127
120
|
attachmentActions?: DChatAttachmentAction[];
|
|
128
121
|
inputPlaceholder?: string;
|
|
@@ -3,6 +3,8 @@ import { StyleSheet } from 'react-native';
|
|
|
3
3
|
import { TabView } from 'react-native-tab-view';
|
|
4
4
|
import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
|
|
5
5
|
import { MessagesTab } from './MessagesTab';
|
|
6
|
+
import { useUserStore } from '../../store';
|
|
7
|
+
import { LoginStatus } from '@droppii/openim-rn-client-sdk';
|
|
6
8
|
|
|
7
9
|
interface InboxProps {
|
|
8
10
|
onPressThread?: (item: string) => void;
|
|
@@ -15,6 +17,7 @@ type TabRoute = { key: string; title: string };
|
|
|
15
17
|
|
|
16
18
|
const Inbox = memo(
|
|
17
19
|
({ onPressThread, onPressSearch, onPressEdit, onPressGroup }: InboxProps) => {
|
|
20
|
+
const connectStatus = useUserStore((state) => state.connectStatus);
|
|
18
21
|
const [index, setIndex] = useState(0);
|
|
19
22
|
const [routes] = useState<TabRoute[]>([
|
|
20
23
|
{ key: 'messages', title: 'Tin nhắn' },
|
|
@@ -22,12 +25,13 @@ const Inbox = memo(
|
|
|
22
25
|
|
|
23
26
|
const renderScene = useCallback(
|
|
24
27
|
({ route }: { route: TabRoute }) => {
|
|
28
|
+
if (connectStatus !== LoginStatus.Logged) return null;
|
|
25
29
|
if (route.key === 'messages') {
|
|
26
30
|
return <MessagesTab onPressThread={onPressThread} />;
|
|
27
31
|
}
|
|
28
32
|
return null;
|
|
29
33
|
},
|
|
30
|
-
[onPressThread]
|
|
34
|
+
[onPressThread, connectStatus]
|
|
31
35
|
);
|
|
32
36
|
|
|
33
37
|
const renderTabBar = useCallback(
|
package/src/services/apis.ts
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
import { type AxiosInstance } from 'axios';
|
|
2
|
-
import type {
|
|
3
|
-
DConversationItem,
|
|
4
|
-
DConversationQueryParams,
|
|
5
|
-
} from '../types/chat';
|
|
6
2
|
import OpenIMSDK, { LoginStatus } from '@droppii/openim-rn-client-sdk';
|
|
7
|
-
import type { BaseResponse, GetOpenIMTokenResponse } from '../types/auth';
|
|
8
|
-
import { Platform } from 'react-native';
|
|
9
3
|
import { useConversationStore } from '../store';
|
|
10
4
|
|
|
11
5
|
export let apiInstance: AxiosInstance | null = null;
|
|
@@ -19,25 +13,6 @@ export namespace ChatAPI {
|
|
|
19
13
|
return (await OpenIMSDK.getLoginStatus(operationID)) === LoginStatus.Logged;
|
|
20
14
|
};
|
|
21
15
|
|
|
22
|
-
export const login = async (
|
|
23
|
-
instance: AxiosInstance,
|
|
24
|
-
operationID?: string
|
|
25
|
-
) => {
|
|
26
|
-
const isLoggedIn = await getLoginStatus(operationID);
|
|
27
|
-
|
|
28
|
-
if (isLoggedIn) return;
|
|
29
|
-
|
|
30
|
-
const response = await instance.post<BaseResponse<GetOpenIMTokenResponse>>(
|
|
31
|
-
`/chat-service/v1/auth/token?platform=${Platform.OS.toUpperCase()}`
|
|
32
|
-
);
|
|
33
|
-
|
|
34
|
-
const token = response?.data?.data;
|
|
35
|
-
|
|
36
|
-
if (token == null) return;
|
|
37
|
-
|
|
38
|
-
return OpenIMSDK.login({ userID: token.id, token: token.token });
|
|
39
|
-
};
|
|
40
|
-
|
|
41
16
|
export const logout = async (operationID?: string) => {
|
|
42
17
|
useConversationStore.getState().reset();
|
|
43
18
|
return OpenIMSDK.logout(operationID);
|
|
@@ -46,17 +21,4 @@ export namespace ChatAPI {
|
|
|
46
21
|
export const getUser = async (operationID?: string | undefined) => {
|
|
47
22
|
return OpenIMSDK.getSelfUserInfo(operationID);
|
|
48
23
|
};
|
|
49
|
-
|
|
50
|
-
export async function queryConversations(params: DConversationQueryParams) {
|
|
51
|
-
if (!apiInstance) {
|
|
52
|
-
throw new Error(
|
|
53
|
-
'apiInstance is not initialized. Call initApiInstance() first.'
|
|
54
|
-
);
|
|
55
|
-
}
|
|
56
|
-
const response = await apiInstance.post<BaseResponse<DConversationItem[]>>(
|
|
57
|
-
'/chat-service/v1/app/conversations/query',
|
|
58
|
-
params
|
|
59
|
-
);
|
|
60
|
-
return response.data;
|
|
61
|
-
}
|
|
62
24
|
}
|
|
@@ -1,32 +1,23 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
mergeOpenIMIntoConversation,
|
|
5
|
-
} from '../utils/conversation';
|
|
6
|
-
import type { DConversationItem } from '../types/chat';
|
|
7
|
-
import type {
|
|
8
|
-
ConversationItem,
|
|
9
|
-
MessageItem,
|
|
10
|
-
} from '@droppii/openim-rn-client-sdk';
|
|
2
|
+
import { sortConversation } from '../utils/conversation';
|
|
3
|
+
import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
|
|
11
4
|
|
|
12
5
|
type ConversationID = string;
|
|
13
6
|
|
|
14
7
|
export interface ConversationStore {
|
|
15
8
|
currentConversationId?: ConversationID;
|
|
16
9
|
setCurrentConversation(id: ConversationID): void;
|
|
17
|
-
getCurrentConversation():
|
|
10
|
+
getCurrentConversation(): ConversationItem | undefined;
|
|
18
11
|
list: ConversationID[];
|
|
19
|
-
map: Record<ConversationID,
|
|
12
|
+
map: Record<ConversationID, ConversationItem>;
|
|
20
13
|
/** Signal incremented when a truly new conversation arrives and a full refetch is needed. */
|
|
21
14
|
newConversationSignal: number;
|
|
22
|
-
updateConversations(conversations:
|
|
15
|
+
updateConversations(conversations: ConversationItem[]): void;
|
|
23
16
|
/**
|
|
24
17
|
* Patches existing conversations with real-time data from OpenIM events.
|
|
25
18
|
* Returns true if any conversation was not found in the store (triggers refetch).
|
|
26
19
|
*/
|
|
27
|
-
mergeOpenIMConversations(conversations: ConversationItem[]): boolean;
|
|
28
20
|
removeConversation(id: ConversationID): void;
|
|
29
|
-
updateLastMessage(id: ConversationID, message: MessageItem): void;
|
|
30
21
|
reset(): void;
|
|
31
22
|
}
|
|
32
23
|
|
|
@@ -56,35 +47,6 @@ export const useConversationStore = create<ConversationStore>()((set, get) => ({
|
|
|
56
47
|
)
|
|
57
48
|
);
|
|
58
49
|
},
|
|
59
|
-
mergeOpenIMConversations(conversations) {
|
|
60
|
-
const currentMap = get().map;
|
|
61
|
-
let hasUnknown = false;
|
|
62
|
-
let changed = false;
|
|
63
|
-
|
|
64
|
-
const nextMap = { ...currentMap };
|
|
65
|
-
for (const openim of conversations) {
|
|
66
|
-
const existing = currentMap[openim.conversationID];
|
|
67
|
-
if (existing == null) {
|
|
68
|
-
hasUnknown = true;
|
|
69
|
-
continue;
|
|
70
|
-
}
|
|
71
|
-
nextMap[openim.conversationID] = mergeOpenIMIntoConversation(
|
|
72
|
-
existing,
|
|
73
|
-
openim
|
|
74
|
-
);
|
|
75
|
-
changed = true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (changed) {
|
|
79
|
-
set(sortConversation(nextMap));
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (hasUnknown) {
|
|
83
|
-
set((s) => ({ newConversationSignal: s.newConversationSignal + 1 }));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
return hasUnknown;
|
|
87
|
-
},
|
|
88
50
|
removeConversation(id) {
|
|
89
51
|
const newMap = { ...get().map };
|
|
90
52
|
delete newMap[id];
|
|
@@ -94,17 +56,6 @@ export const useConversationStore = create<ConversationStore>()((set, get) => ({
|
|
|
94
56
|
list: get().list.filter((item) => item !== id),
|
|
95
57
|
});
|
|
96
58
|
},
|
|
97
|
-
updateLastMessage(id, message) {
|
|
98
|
-
const conversation = get().map[id];
|
|
99
|
-
if (conversation == null) return;
|
|
100
|
-
|
|
101
|
-
set(
|
|
102
|
-
sortConversation({
|
|
103
|
-
[id]: { ...conversation, lastMessage: message },
|
|
104
|
-
...get().map,
|
|
105
|
-
})
|
|
106
|
-
);
|
|
107
|
-
},
|
|
108
59
|
reset() {
|
|
109
60
|
set({
|
|
110
61
|
currentConversationId: undefined,
|
|
@@ -115,6 +66,6 @@ export const useConversationStore = create<ConversationStore>()((set, get) => ({
|
|
|
115
66
|
},
|
|
116
67
|
}));
|
|
117
68
|
|
|
118
|
-
export const useConversation = (id: string):
|
|
69
|
+
export const useConversation = (id: string): ConversationItem | undefined => {
|
|
119
70
|
return useConversationStore((state) => state.map[id]);
|
|
120
71
|
};
|