@droppii-org/chat-mobile 0.2.6 → 0.2.7
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 +4 -4
- package/lib/module/components/ThreadCard/AvatarSection.js.map +1 -1
- package/lib/module/components/ThreadCard/NamePrefixIcon.js +13 -16
- package/lib/module/components/ThreadCard/NamePrefixIcon.js.map +1 -1
- package/lib/module/components/ThreadCard/ThreadCard.js +13 -33
- package/lib/module/components/ThreadCard/ThreadCard.js.map +1 -1
- package/lib/module/context/ChatContext.js +7 -6
- package/lib/module/context/ChatContext.js.map +1 -1
- package/lib/module/hooks/message/useSendMessage.js +101 -0
- package/lib/module/hooks/message/useSendMessage.js.map +1 -0
- package/lib/module/hooks/useChatMessages.js +37 -119
- package/lib/module/hooks/useChatMessages.js.map +1 -1
- package/lib/module/hooks/useConversationList.js +29 -17
- package/lib/module/hooks/useConversationList.js.map +1 -1
- package/lib/module/hooks/useLinkPreview/useLinkPreview.js +3 -2
- package/lib/module/hooks/useLinkPreview/useLinkPreview.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatComposer.js +2 -2
- package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetail.js +14 -10
- package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatDetailHeader.js +5 -8
- package/lib/module/screens/chat-detail/ChatDetailHeader.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatLinkPreview.js +1 -1
- package/lib/module/screens/chat-detail/ChatLinkPreview.js.map +1 -1
- package/lib/module/screens/chat-detail/ChatListLegend.js +0 -2
- package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
- package/lib/module/screens/chat-detail/conversationHeader.utils.js +7 -9
- package/lib/module/screens/chat-detail/conversationHeader.utils.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +10 -23
- package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
- package/lib/module/screens/chat-detail/legend/message-types.js +128 -6
- package/lib/module/screens/chat-detail/legend/message-types.js.map +1 -1
- package/lib/module/store/conversation.js +1 -1
- package/lib/module/store/conversation.js.map +1 -1
- package/lib/module/store/message.js +45 -0
- package/lib/module/store/message.js.map +1 -0
- package/lib/module/translation/resources/i18n.js +7 -1
- package/lib/module/translation/resources/i18n.js.map +1 -1
- package/lib/module/types/chat.js +2 -7
- package/lib/module/types/chat.js.map +1 -1
- package/lib/module/utils/conversation.js +34 -13
- package/lib/module/utils/conversation.js.map +1 -1
- package/lib/module/utils/legendListMessage.js +0 -3
- package/lib/module/utils/legendListMessage.js.map +1 -1
- package/lib/module/utils/message.js +5 -8
- package/lib/module/utils/message.js.map +1 -1
- package/lib/module/utils/url.js +3 -3
- package/lib/module/utils/url.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/NamePrefixIcon.d.ts +3 -4
- package/lib/typescript/src/components/ThreadCard/NamePrefixIcon.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 +1 -1
- package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts +12 -0
- package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useChatMessages.d.ts +0 -1
- package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useConversationList.d.ts +2 -1
- 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/ChatListLegend.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/conversationHeader.utils.d.ts +1 -1
- package/lib/typescript/src/screens/chat-detail/conversationHeader.utils.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +1 -3
- package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/legend/message-types.d.ts +1 -0
- package/lib/typescript/src/screens/chat-detail/legend/message-types.d.ts.map +1 -1
- package/lib/typescript/src/screens/chat-detail/types.d.ts +6 -7
- package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
- package/lib/typescript/src/store/message.d.ts +3 -0
- package/lib/typescript/src/store/message.d.ts.map +1 -0
- package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
- package/lib/typescript/src/types/chat.d.ts +28 -27
- package/lib/typescript/src/types/chat.d.ts.map +1 -1
- package/lib/typescript/src/types/common.d.ts +1 -0
- package/lib/typescript/src/types/common.d.ts.map +1 -1
- package/lib/typescript/src/utils/conversation.d.ts +3 -2
- package/lib/typescript/src/utils/conversation.d.ts.map +1 -1
- package/lib/typescript/src/utils/legendListMessage.d.ts +0 -2
- package/lib/typescript/src/utils/legendListMessage.d.ts.map +1 -1
- package/lib/typescript/src/utils/message.d.ts.map +1 -1
- package/lib/typescript/src/utils/url.d.ts +1 -1
- package/lib/typescript/src/utils/url.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/components/ThreadCard/AvatarSection.tsx +5 -8
- package/src/components/ThreadCard/NamePrefixIcon.tsx +27 -38
- package/src/components/ThreadCard/ThreadCard.tsx +16 -30
- package/src/context/ChatContext.tsx +12 -4
- package/src/hooks/message/useSendMessage.ts +136 -0
- package/src/hooks/useChatMessages.ts +70 -158
- package/src/hooks/useConversationList.ts +34 -16
- package/src/hooks/useLinkPreview/useLinkPreview.ts +3 -2
- package/src/screens/chat-detail/ChatComposer.tsx +2 -2
- package/src/screens/chat-detail/ChatDetail.tsx +29 -22
- package/src/screens/chat-detail/ChatDetailHeader.tsx +4 -10
- package/src/screens/chat-detail/ChatLinkPreview.tsx +1 -1
- package/src/screens/chat-detail/ChatListLegend.tsx +1 -2
- package/src/screens/chat-detail/conversationHeader.utils.ts +11 -14
- package/src/screens/chat-detail/legend/LegendChatMessage.tsx +15 -33
- package/src/screens/chat-detail/legend/message-types.tsx +167 -12
- package/src/screens/chat-detail/types.ts +6 -8
- package/src/store/conversation.ts +1 -1
- package/src/store/message.ts +44 -0
- package/src/translation/resources/i18n.ts +6 -0
- package/src/types/chat.ts +31 -30
- package/src/types/common.ts +1 -0
- package/src/utils/conversation.ts +44 -17
- package/src/utils/legendListMessage.ts +0 -5
- package/src/utils/message.ts +10 -12
- package/src/utils/url.ts +3 -3
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { memo } from 'react';
|
|
2
2
|
import { Image, StyleSheet } from 'react-native';
|
|
3
3
|
import { KContainer, KImage, KColors } from '@droppii/libs';
|
|
4
|
-
import { DChatCategory, DChatType } from '../../types/chat';
|
|
5
4
|
import Images from '../../assets/images';
|
|
5
|
+
import { PeerType } from '@droppii/openim-rn-client-sdk';
|
|
6
6
|
|
|
7
7
|
const styles = StyleSheet.create({
|
|
8
8
|
icon: {
|
|
@@ -12,46 +12,35 @@ const styles = StyleSheet.create({
|
|
|
12
12
|
});
|
|
13
13
|
|
|
14
14
|
interface NamePrefixIconProps {
|
|
15
|
-
|
|
16
|
-
chatType?: DChatType;
|
|
15
|
+
peerType?: PeerType | string;
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
export const NamePrefixIcon = memo(
|
|
20
|
-
(
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
if (chatCategory === DChatCategory.BIZ_BOT_PDP) {
|
|
29
|
-
return (
|
|
30
|
-
<KContainer.View marginR="0.25rem">
|
|
31
|
-
<KImage.VectorIcons
|
|
32
|
-
name="robot-outline"
|
|
33
|
-
provider="MaterialCommunityIcons"
|
|
34
|
-
size={14}
|
|
35
|
-
color={KColors.palette.primary.w400}
|
|
36
|
-
/>
|
|
37
|
-
</KContainer.View>
|
|
38
|
-
);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
if (chatType === DChatType.GROUP) {
|
|
42
|
-
return (
|
|
43
|
-
<KContainer.View marginR="0.25rem">
|
|
44
|
-
<KImage.VectorIcons
|
|
45
|
-
name="user-two-b"
|
|
46
|
-
size={14}
|
|
47
|
-
color={KColors.black}
|
|
48
|
-
/>
|
|
49
|
-
</KContainer.View>
|
|
50
|
-
);
|
|
51
|
-
}
|
|
18
|
+
export const NamePrefixIcon = memo(({ peerType }: NamePrefixIconProps) => {
|
|
19
|
+
if (peerType === PeerType.Bot) {
|
|
20
|
+
return (
|
|
21
|
+
<KContainer.View marginR="0.25rem">
|
|
22
|
+
<Image source={Images.ICON_DROPPII} style={styles.icon} />
|
|
23
|
+
</KContainer.View>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
52
26
|
|
|
53
|
-
|
|
27
|
+
if (peerType === PeerType.Group) {
|
|
28
|
+
return (
|
|
29
|
+
<KContainer.View marginR="0.25rem">
|
|
30
|
+
<KImage.VectorIcons name="user-two-b" size={14} color={KColors.black} />
|
|
31
|
+
</KContainer.View>
|
|
32
|
+
);
|
|
54
33
|
}
|
|
55
|
-
|
|
34
|
+
|
|
35
|
+
// if (peerType === DChatPeerType.CUSTOMER) {
|
|
36
|
+
// return (
|
|
37
|
+
// <KContainer.View marginR="0.25rem">
|
|
38
|
+
// <Image source={Images.ICON_DROPPII} style={styles.icon} />
|
|
39
|
+
// </KContainer.View>
|
|
40
|
+
// );
|
|
41
|
+
// }
|
|
42
|
+
|
|
43
|
+
return null;
|
|
44
|
+
});
|
|
56
45
|
|
|
57
46
|
NamePrefixIcon.displayName = 'NamePrefixIcon';
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { memo, useCallback } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { type GestureResponderEvent } from 'react-native';
|
|
3
3
|
import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
|
|
4
|
-
import { DChatCategory } from '../../types/chat';
|
|
5
4
|
import { AvatarSection } from './AvatarSection';
|
|
6
5
|
import { NamePrefixIcon } from './NamePrefixIcon';
|
|
7
6
|
import { UnreadBadge } from './UnreadBadge';
|
|
8
7
|
import { formatTimestamp, getLastMessageText } from './thread-card.utils';
|
|
9
|
-
import Images from '../../assets/images';
|
|
10
8
|
import { useConversation, useUserStore } from '../../store';
|
|
11
9
|
|
|
12
10
|
interface ThreadCardProps {
|
|
@@ -16,19 +14,20 @@ interface ThreadCardProps {
|
|
|
16
14
|
|
|
17
15
|
const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
18
16
|
const {
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
peerType,
|
|
18
|
+
showName,
|
|
19
|
+
faceURL,
|
|
21
20
|
lastMessage,
|
|
22
21
|
unreadCount = 0,
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
recvMsgOpt,
|
|
23
|
+
isPinned,
|
|
25
24
|
applicationType,
|
|
26
|
-
chatType,
|
|
27
25
|
latestMsgSendTime,
|
|
28
26
|
} = useConversation(item) ?? {};
|
|
29
27
|
|
|
30
|
-
const fullName =
|
|
28
|
+
const fullName = showName ?? '';
|
|
31
29
|
const hasUnread = unreadCount > 0;
|
|
30
|
+
const isMuted = (recvMsgOpt ?? 0) !== 0;
|
|
32
31
|
const timestamp = formatTimestamp(
|
|
33
32
|
latestMsgSendTime ?? lastMessage?.sendTime ?? null
|
|
34
33
|
);
|
|
@@ -52,30 +51,25 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
52
51
|
activeOpacity={0.7}
|
|
53
52
|
>
|
|
54
53
|
<AvatarSection
|
|
55
|
-
avatar={
|
|
54
|
+
avatar={faceURL ?? null}
|
|
56
55
|
fullName={fullName}
|
|
57
|
-
|
|
56
|
+
peerType={peerType}
|
|
58
57
|
applicationType={applicationType}
|
|
59
|
-
chatType={chatType}
|
|
60
58
|
/>
|
|
61
59
|
|
|
62
60
|
{/* Chat-Content */}
|
|
63
61
|
<KContainer.View flex marginL="0.5rem" paddingB={2}>
|
|
64
62
|
{/* Row-Title */}
|
|
65
63
|
<KContainer.View row alignItems="center">
|
|
66
|
-
<NamePrefixIcon
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// chatCategory === DChatCategory.BIZ_BOT_CRM ||
|
|
70
|
-
chatCategory === DChatCategory.BIZ_BOT_PDP
|
|
71
|
-
}
|
|
72
|
-
>
|
|
64
|
+
<NamePrefixIcon peerType={peerType} />
|
|
65
|
+
{/* For verified PDP (configuration details to be defined later) */}
|
|
66
|
+
{/* <KContainer.VisibleView visible={peerType === DChatPeerType.BOT}>
|
|
73
67
|
<KImage.Base
|
|
74
68
|
uri={Images.ICON_BOT}
|
|
75
69
|
size={14}
|
|
76
70
|
style={styles.botIcon}
|
|
77
71
|
/>
|
|
78
|
-
</KContainer.VisibleView>
|
|
72
|
+
</KContainer.VisibleView> */}
|
|
79
73
|
<KLabel.Text
|
|
80
74
|
typo={hasUnread ? 'TextMdBold' : 'TextMdNormal'}
|
|
81
75
|
numberOfLines={1}
|
|
@@ -84,7 +78,7 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
84
78
|
>
|
|
85
79
|
{fullName}
|
|
86
80
|
</KLabel.Text>
|
|
87
|
-
<KContainer.VisibleView visible={
|
|
81
|
+
<KContainer.VisibleView visible={isMuted}>
|
|
88
82
|
<KContainer.View marginL="0.25rem">
|
|
89
83
|
<KImage.VectorIcons
|
|
90
84
|
name="bell-off"
|
|
@@ -115,7 +109,7 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
115
109
|
>
|
|
116
110
|
{lastMessageText}
|
|
117
111
|
</KLabel.Text>
|
|
118
|
-
<KContainer.VisibleView visible={Boolean(
|
|
112
|
+
<KContainer.VisibleView visible={Boolean(isPinned)}>
|
|
119
113
|
<KContainer.View marginL="0.5rem">
|
|
120
114
|
<KImage.VectorIcons
|
|
121
115
|
name="pin-outline"
|
|
@@ -135,11 +129,3 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
|
|
|
135
129
|
ThreadCard.displayName = 'ThreadCard';
|
|
136
130
|
|
|
137
131
|
export default ThreadCard;
|
|
138
|
-
|
|
139
|
-
const styles = StyleSheet.create({
|
|
140
|
-
botIcon: {
|
|
141
|
-
width: 16,
|
|
142
|
-
height: 16,
|
|
143
|
-
marginRight: 4,
|
|
144
|
-
},
|
|
145
|
-
});
|
|
@@ -13,11 +13,19 @@ export const useChatContext = (): ChatContextType => {
|
|
|
13
13
|
return context;
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
const ChatProviderInner = ({
|
|
17
|
-
|
|
16
|
+
const ChatProviderInner = ({
|
|
17
|
+
logGA,
|
|
18
|
+
children,
|
|
19
|
+
applicationType,
|
|
20
|
+
}: ChatProviderProps) => {
|
|
21
|
+
const value = useMemo(
|
|
22
|
+
() => ({ logGA, applicationType }),
|
|
23
|
+
[logGA, applicationType]
|
|
24
|
+
);
|
|
18
25
|
|
|
19
26
|
return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
|
|
20
27
|
};
|
|
21
28
|
|
|
22
|
-
export const ChatProvider = ({
|
|
23
|
-
|
|
29
|
+
export const ChatProvider = ({ ...props }: ChatProviderProps) => (
|
|
30
|
+
<ChatProviderInner {...props} />
|
|
31
|
+
);
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useCallback } from 'react';
|
|
2
|
+
import type { UploadFileItem } from 'react-native-fs';
|
|
3
|
+
import { useConversationStore } from '../../store';
|
|
4
|
+
import type {
|
|
5
|
+
MessageItem,
|
|
6
|
+
MessageType,
|
|
7
|
+
OfflinePush,
|
|
8
|
+
} from '@droppii/openim-rn-client-sdk';
|
|
9
|
+
import { extractUrls } from '../../utils/url';
|
|
10
|
+
import OpenIMSDK from '@droppii/openim-rn-client-sdk';
|
|
11
|
+
import type { IMessageItemEx } from '../../types/chat';
|
|
12
|
+
import { useChatContext } from '../../context';
|
|
13
|
+
import { generateContentBasedOnMessageType } from '../../utils/conversation';
|
|
14
|
+
import { useMessageStore } from '../../store/message';
|
|
15
|
+
import type { IUrlMetadata } from '../../types/common';
|
|
16
|
+
|
|
17
|
+
export const useSendMessage = () => {
|
|
18
|
+
const applicationType = useChatContext().applicationType;
|
|
19
|
+
const pushNewMessage = useMessageStore((state) => state.pushNewMessage);
|
|
20
|
+
|
|
21
|
+
const sendMessage = useCallback(
|
|
22
|
+
async ({
|
|
23
|
+
plainText,
|
|
24
|
+
files,
|
|
25
|
+
urlMetadata,
|
|
26
|
+
}: {
|
|
27
|
+
plainText?: string;
|
|
28
|
+
files?: UploadFileItem[]; //TODO
|
|
29
|
+
urlMetadata?: IUrlMetadata;
|
|
30
|
+
}) => {
|
|
31
|
+
const { userID: recvID, groupID } =
|
|
32
|
+
useConversationStore.getState().getCurrentConversation() || {};
|
|
33
|
+
if (!recvID && !groupID) return;
|
|
34
|
+
|
|
35
|
+
const messageList: MessageItem[] = [];
|
|
36
|
+
|
|
37
|
+
for (const file of files || []) {
|
|
38
|
+
if (!file) continue;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!!plainText && plainText.trim() !== '') {
|
|
42
|
+
const urls = extractUrls(plainText);
|
|
43
|
+
const isUrlMessage = urls.length > 0;
|
|
44
|
+
let message: MessageItem | null = null;
|
|
45
|
+
if (isUrlMessage) {
|
|
46
|
+
message = await createUrlTextMessage(plainText, urls);
|
|
47
|
+
} else {
|
|
48
|
+
message = await createTextMessage(plainText);
|
|
49
|
+
}
|
|
50
|
+
if (!message) return;
|
|
51
|
+
messageList.push(message);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
for (const message of messageList) {
|
|
55
|
+
const extendMessageInfo: IMessageItemEx = {
|
|
56
|
+
applicationType,
|
|
57
|
+
urlMetadata,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const successMessage = await OpenIMSDK.sendMessage({
|
|
61
|
+
groupID: groupID || '',
|
|
62
|
+
recvID: recvID || '',
|
|
63
|
+
message: {
|
|
64
|
+
...message,
|
|
65
|
+
ex: JSON.stringify(extendMessageInfo) || '{}',
|
|
66
|
+
},
|
|
67
|
+
offlinePushInfo: generateOfflinePushInfo(
|
|
68
|
+
message.contentType,
|
|
69
|
+
plainText || ''
|
|
70
|
+
),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
pushNewMessage(successMessage);
|
|
74
|
+
}
|
|
75
|
+
},
|
|
76
|
+
[applicationType, pushNewMessage]
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
sendMessage,
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const generateOfflinePushInfo = (
|
|
85
|
+
contentType: MessageType,
|
|
86
|
+
plainText: string
|
|
87
|
+
) => {
|
|
88
|
+
const conversationData = useConversationStore
|
|
89
|
+
?.getState?.()
|
|
90
|
+
?.getCurrentConversation();
|
|
91
|
+
const title = conversationData?.showName || 'Droppii';
|
|
92
|
+
const desc = generateContentBasedOnMessageType(contentType, plainText);
|
|
93
|
+
return {
|
|
94
|
+
title,
|
|
95
|
+
desc,
|
|
96
|
+
ex: JSON.stringify({
|
|
97
|
+
icon: conversationData?.faceURL || '',
|
|
98
|
+
conversationId: conversationData?.conversationId || '',
|
|
99
|
+
title,
|
|
100
|
+
desc,
|
|
101
|
+
}),
|
|
102
|
+
iOSPushSound: 'default',
|
|
103
|
+
iOSBadgeCount: true,
|
|
104
|
+
} as OfflinePush;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const createTextMessage = async (text: string) => {
|
|
108
|
+
let textMessage = await OpenIMSDK.createTextMessage(
|
|
109
|
+
text,
|
|
110
|
+
new Date().getTime().toString()
|
|
111
|
+
)
|
|
112
|
+
.then((data) => {
|
|
113
|
+
return data;
|
|
114
|
+
})
|
|
115
|
+
.catch(({ errCode, errMsg }) => {
|
|
116
|
+
console.error('createTextMessage', errCode, errMsg);
|
|
117
|
+
return null;
|
|
118
|
+
});
|
|
119
|
+
return textMessage;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const createUrlTextMessage = async (text: string, urls: string[]) => {
|
|
123
|
+
let urlTextMessage = await OpenIMSDK.createUrlTextMessage(
|
|
124
|
+
text,
|
|
125
|
+
urls,
|
|
126
|
+
new Date().getTime().toString()
|
|
127
|
+
)
|
|
128
|
+
.then((data) => {
|
|
129
|
+
return data;
|
|
130
|
+
})
|
|
131
|
+
.catch(({ errCode, errMsg }) => {
|
|
132
|
+
console.error('createUrlTextMessage', errCode, errMsg);
|
|
133
|
+
return null;
|
|
134
|
+
});
|
|
135
|
+
return urlTextMessage;
|
|
136
|
+
};
|
|
@@ -7,11 +7,10 @@ import { ChatMessageAPI } from '../services/message';
|
|
|
7
7
|
import type { DMessageItem } from '../types/chat';
|
|
8
8
|
import {
|
|
9
9
|
belongsToConversation,
|
|
10
|
-
getHistoryPaginationAnchor,
|
|
11
10
|
hasNewHistoryMessages,
|
|
12
11
|
mergeMessages,
|
|
13
|
-
type HistoryPaginationAnchor,
|
|
14
12
|
} from '../utils/message';
|
|
13
|
+
import { useMessageStore } from '../store/message';
|
|
15
14
|
|
|
16
15
|
type UseChatMessagesOptions = {
|
|
17
16
|
conversationId: string;
|
|
@@ -24,44 +23,24 @@ export function useChatMessages({
|
|
|
24
23
|
enabled = true,
|
|
25
24
|
pageSize = 20,
|
|
26
25
|
}: UseChatMessagesOptions) {
|
|
27
|
-
const
|
|
26
|
+
const messages = useMessageStore((s) => s.messages);
|
|
27
|
+
const hasMoreEarlier = useMessageStore((s) => s.hasMoreEarlier);
|
|
28
|
+
const hasMoreNewer = useMessageStore((s) => s.hasMoreNewer);
|
|
29
|
+
const setMessages = useMessageStore((s) => s.setMessages);
|
|
30
|
+
const pushNewMessage = useMessageStore((s) => s.pushNewMessage);
|
|
31
|
+
const reset = useMessageStore((s) => s.reset);
|
|
32
|
+
|
|
28
33
|
const [currentUserId, setCurrentUserId] = useState<string>();
|
|
29
34
|
const [isLoading, setIsLoading] = useState(false);
|
|
30
35
|
const [isLoadingEarlier, setIsLoadingEarlier] = useState(false);
|
|
31
|
-
const [hasMoreEarlier, setHasMoreEarlier] = useState(false);
|
|
32
36
|
const [isLoadingNewer, setIsLoadingNewer] = useState(false);
|
|
33
|
-
const [hasMoreNewer, setHasMoreNewer] = useState(false);
|
|
34
37
|
const [error, setError] = useState<Error | null>(null);
|
|
35
38
|
|
|
36
39
|
const conversationIdRef = useRef(conversationId);
|
|
37
40
|
conversationIdRef.current = conversationId;
|
|
38
41
|
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
const messagesRef = useRef(messages);
|
|
42
|
-
const hasMoreEarlierRef = useRef(hasMoreEarlier);
|
|
43
|
-
const hasMoreNewerRef = useRef(hasMoreNewer);
|
|
44
|
-
const historyAnchorRef = useRef<HistoryPaginationAnchor | null>(null);
|
|
45
|
-
const newestAnchorRef = useRef<HistoryPaginationAnchor | null>(null);
|
|
46
|
-
messagesRef.current = messages;
|
|
47
|
-
hasMoreEarlierRef.current = hasMoreEarlier;
|
|
48
|
-
hasMoreNewerRef.current = hasMoreNewer;
|
|
49
|
-
|
|
50
|
-
const resetState = useCallback(() => {
|
|
51
|
-
setMessages([]);
|
|
52
|
-
setHasMoreEarlier(false);
|
|
53
|
-
setHasMoreNewer(false);
|
|
54
|
-
setError(null);
|
|
55
|
-
isLoadingEarlierRef.current = false;
|
|
56
|
-
isLoadingNewerRef.current = false;
|
|
57
|
-
historyAnchorRef.current = null;
|
|
58
|
-
newestAnchorRef.current = null;
|
|
59
|
-
}, []);
|
|
60
|
-
|
|
61
|
-
const loadInitialMessages = useCallback(async () => {
|
|
62
|
-
if (!conversationId) {
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
42
|
+
const fetchInitial = useCallback(async () => {
|
|
43
|
+
if (!conversationId) return;
|
|
65
44
|
|
|
66
45
|
setIsLoading(true);
|
|
67
46
|
setError(null);
|
|
@@ -75,22 +54,9 @@ export function useChatMessages({
|
|
|
75
54
|
]);
|
|
76
55
|
|
|
77
56
|
const initialMessages = history.messageList as DMessageItem[];
|
|
78
|
-
const oldestAnchor = getHistoryPaginationAnchor(initialMessages);
|
|
79
57
|
|
|
80
58
|
setCurrentUserId(userId);
|
|
81
|
-
setMessages(mergeMessages([], initialMessages));
|
|
82
|
-
historyAnchorRef.current = oldestAnchor
|
|
83
|
-
? {
|
|
84
|
-
clientMsgID: oldestAnchor.clientMsgID,
|
|
85
|
-
// lastMinSeq: resolveHistoryLastMinSeq(
|
|
86
|
-
// history,
|
|
87
|
-
// initialMessages.find(
|
|
88
|
-
// (message) => message.clientMsgID === oldestAnchor.clientMsgID
|
|
89
|
-
// )
|
|
90
|
-
// ),
|
|
91
|
-
}
|
|
92
|
-
: null;
|
|
93
|
-
setHasMoreEarlier(!history.isEnd && !!oldestAnchor);
|
|
59
|
+
setMessages(mergeMessages([], initialMessages), !history.isEnd);
|
|
94
60
|
|
|
95
61
|
ChatMessageAPI.markConversationAsRead(conversationId).catch(
|
|
96
62
|
() => undefined
|
|
@@ -100,170 +66,117 @@ export function useChatMessages({
|
|
|
100
66
|
} finally {
|
|
101
67
|
setIsLoading(false);
|
|
102
68
|
}
|
|
103
|
-
}, [conversationId, pageSize]);
|
|
69
|
+
}, [conversationId, pageSize, setMessages]);
|
|
104
70
|
|
|
105
71
|
const onLoadEarlier = useCallback(async () => {
|
|
106
|
-
if (
|
|
107
|
-
!conversationId ||
|
|
108
|
-
isLoadingEarlierRef.current ||
|
|
109
|
-
!hasMoreEarlierRef.current ||
|
|
110
|
-
!messagesRef.current.length
|
|
111
|
-
) {
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
72
|
+
if (isLoadingEarlier || !hasMoreEarlier || !messages.length) return;
|
|
114
73
|
|
|
115
|
-
isLoadingEarlierRef.current = true;
|
|
116
74
|
setIsLoadingEarlier(true);
|
|
117
75
|
setError(null);
|
|
118
76
|
|
|
119
|
-
const anchor = historyAnchorRef.current;
|
|
120
|
-
if (!anchor?.clientMsgID) {
|
|
121
|
-
isLoadingEarlierRef.current = false;
|
|
122
|
-
setIsLoadingEarlier(false);
|
|
123
|
-
return;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
77
|
try {
|
|
127
78
|
const history = await ChatMessageAPI.fetchHistoryMessages(
|
|
128
79
|
conversationId,
|
|
129
80
|
{
|
|
130
81
|
count: pageSize,
|
|
131
|
-
startClientMsgID:
|
|
82
|
+
startClientMsgID: messages[0]!.clientMsgID,
|
|
132
83
|
}
|
|
133
84
|
);
|
|
134
|
-
const incoming = history.messageList as DMessageItem[];
|
|
135
|
-
const hasNewMessages = hasNewHistoryMessages(
|
|
136
|
-
messagesRef.current,
|
|
137
|
-
incoming
|
|
138
|
-
);
|
|
139
85
|
|
|
140
|
-
|
|
141
|
-
|
|
86
|
+
const incoming = history.messageList as DMessageItem[];
|
|
87
|
+
const hasNew = hasNewHistoryMessages(messages, incoming);
|
|
88
|
+
|
|
89
|
+
if (hasNew) {
|
|
90
|
+
setMessages(
|
|
91
|
+
mergeMessages(messages, incoming),
|
|
92
|
+
!history.isEnd && hasNew
|
|
93
|
+
);
|
|
94
|
+
} else {
|
|
95
|
+
setMessages(messages, false);
|
|
142
96
|
}
|
|
143
|
-
|
|
144
|
-
const nextAnchor = getHistoryPaginationAnchor(incoming);
|
|
145
|
-
historyAnchorRef.current = nextAnchor
|
|
146
|
-
? {
|
|
147
|
-
clientMsgID: nextAnchor.clientMsgID,
|
|
148
|
-
// lastMinSeq: resolveHistoryLastMinSeq(
|
|
149
|
-
// history,
|
|
150
|
-
// incoming.find(
|
|
151
|
-
// (message) => message.clientMsgID === nextAnchor.clientMsgID
|
|
152
|
-
// )
|
|
153
|
-
// ),
|
|
154
|
-
}
|
|
155
|
-
: null;
|
|
156
|
-
|
|
157
|
-
setHasMoreEarlier(!history.isEnd && hasNewMessages && !!nextAnchor);
|
|
158
97
|
} catch (err) {
|
|
159
98
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
160
99
|
} finally {
|
|
161
|
-
isLoadingEarlierRef.current = false;
|
|
162
100
|
setIsLoadingEarlier(false);
|
|
163
101
|
}
|
|
164
|
-
}, [
|
|
102
|
+
}, [
|
|
103
|
+
conversationId,
|
|
104
|
+
hasMoreEarlier,
|
|
105
|
+
isLoadingEarlier,
|
|
106
|
+
messages,
|
|
107
|
+
pageSize,
|
|
108
|
+
setMessages,
|
|
109
|
+
]);
|
|
165
110
|
|
|
166
111
|
const onLoadNewer = useCallback(async () => {
|
|
167
|
-
if (
|
|
168
|
-
!conversationId ||
|
|
169
|
-
isLoadingNewerRef.current ||
|
|
170
|
-
!hasMoreNewerRef.current ||
|
|
171
|
-
!messagesRef.current.length
|
|
172
|
-
) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
112
|
+
if (isLoadingNewer || !hasMoreNewer || !messages.length) return;
|
|
175
113
|
|
|
176
|
-
isLoadingNewerRef.current = true;
|
|
177
114
|
setIsLoadingNewer(true);
|
|
178
115
|
setError(null);
|
|
179
116
|
|
|
180
|
-
const anchor = newestAnchorRef.current;
|
|
181
|
-
if (!anchor?.clientMsgID && messagesRef.current.length === 0) {
|
|
182
|
-
isLoadingNewerRef.current = false;
|
|
183
|
-
setIsLoadingNewer(false);
|
|
184
|
-
return;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
117
|
try {
|
|
188
|
-
// Get the newest message ID to load from
|
|
189
|
-
const newestMessage = messagesRef.current[messagesRef.current.length - 1];
|
|
190
118
|
const history = await ChatMessageAPI.fetchHistoryMessages(
|
|
191
119
|
conversationId,
|
|
192
120
|
{
|
|
193
121
|
count: pageSize,
|
|
194
|
-
startClientMsgID:
|
|
122
|
+
startClientMsgID: messages[messages.length - 1]!.clientMsgID,
|
|
195
123
|
}
|
|
196
124
|
);
|
|
197
125
|
|
|
198
126
|
const incoming = history.messageList as DMessageItem[];
|
|
199
|
-
const
|
|
127
|
+
const hasNew = incoming.length > 0;
|
|
200
128
|
|
|
201
|
-
if (
|
|
202
|
-
setMessages(
|
|
129
|
+
if (hasNew) {
|
|
130
|
+
setMessages(
|
|
131
|
+
mergeMessages(messages, incoming),
|
|
132
|
+
!history.isEnd && hasNew
|
|
133
|
+
);
|
|
203
134
|
}
|
|
204
|
-
|
|
205
|
-
setHasMoreNewer(!history.isEnd && hasNewMessages);
|
|
206
135
|
} catch (err) {
|
|
207
136
|
setError(err instanceof Error ? err : new Error(String(err)));
|
|
208
137
|
} finally {
|
|
209
|
-
isLoadingNewerRef.current = false;
|
|
210
138
|
setIsLoadingNewer(false);
|
|
211
139
|
}
|
|
212
|
-
}, [
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
const appendIncomingMessages = useCallback((incoming: MessageItem[]) => {
|
|
228
|
-
const relevant = incoming.filter((message) =>
|
|
229
|
-
belongsToConversation(message, conversationIdRef.current)
|
|
230
|
-
);
|
|
231
|
-
|
|
232
|
-
if (!relevant.length) {
|
|
233
|
-
return;
|
|
234
|
-
}
|
|
140
|
+
}, [
|
|
141
|
+
conversationId,
|
|
142
|
+
hasMoreNewer,
|
|
143
|
+
isLoadingNewer,
|
|
144
|
+
messages,
|
|
145
|
+
pageSize,
|
|
146
|
+
setMessages,
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
const appendIncomingMessages = useCallback(
|
|
150
|
+
(incoming: MessageItem[]) => {
|
|
151
|
+
const relevant = incoming.filter((message) =>
|
|
152
|
+
belongsToConversation(message, conversationIdRef.current)
|
|
153
|
+
);
|
|
235
154
|
|
|
236
|
-
|
|
237
|
-
mergeMessages(current, relevant as DMessageItem[])
|
|
238
|
-
);
|
|
155
|
+
if (!relevant.length) return;
|
|
239
156
|
|
|
240
|
-
|
|
241
|
-
()
|
|
242
|
-
|
|
243
|
-
|
|
157
|
+
relevant.forEach((msg) => pushNewMessage(msg));
|
|
158
|
+
ChatMessageAPI.markConversationAsRead(conversationIdRef.current).catch(
|
|
159
|
+
() => undefined
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
[pushNewMessage]
|
|
163
|
+
);
|
|
244
164
|
|
|
245
165
|
useEffect(() => {
|
|
246
|
-
|
|
166
|
+
reset();
|
|
247
167
|
|
|
248
|
-
if (!enabled || !conversationId)
|
|
249
|
-
return;
|
|
250
|
-
}
|
|
168
|
+
if (!enabled || !conversationId) return;
|
|
251
169
|
|
|
252
|
-
|
|
253
|
-
}, [conversationId, enabled,
|
|
170
|
+
fetchInitial();
|
|
171
|
+
}, [conversationId, enabled, fetchInitial, reset]);
|
|
254
172
|
|
|
255
173
|
useEffect(() => {
|
|
256
|
-
if (!enabled || !conversationId)
|
|
257
|
-
return;
|
|
258
|
-
}
|
|
174
|
+
if (!enabled || !conversationId) return;
|
|
259
175
|
|
|
260
|
-
const handleNewMessages = (incoming: MessageItem[]) =>
|
|
176
|
+
const handleNewMessages = (incoming: MessageItem[]) =>
|
|
261
177
|
appendIncomingMessages(incoming);
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const handleNewMessage = (incoming: MessageItem) => {
|
|
178
|
+
const handleNewMessage = (incoming: MessageItem) =>
|
|
265
179
|
appendIncomingMessages([incoming]);
|
|
266
|
-
};
|
|
267
180
|
|
|
268
181
|
OpenIMSDK.on(OpenIMEvent.OnRecvNewMessages, handleNewMessages);
|
|
269
182
|
OpenIMSDK.on(OpenIMEvent.OnRecvNewMessage, handleNewMessage);
|
|
@@ -285,7 +198,6 @@ export function useChatMessages({
|
|
|
285
198
|
error,
|
|
286
199
|
onLoadEarlier,
|
|
287
200
|
onLoadNewer,
|
|
288
|
-
|
|
289
|
-
refresh: loadInitialMessages,
|
|
201
|
+
refresh: fetchInitial,
|
|
290
202
|
};
|
|
291
203
|
}
|