@sendbird/uikit-react-native 3.0.4 → 3.1.1
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/commonjs/components/ChannelInput/SendInput.js +151 -19
- package/lib/commonjs/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/commonjs/components/ChannelInput/index.js +5 -13
- package/lib/commonjs/components/ChannelInput/index.js.map +1 -1
- package/lib/commonjs/components/ChannelMessageList/index.js +34 -20
- package/lib/commonjs/components/ChannelMessageList/index.js.map +1 -1
- package/lib/commonjs/components/ChatFlatList/index.js +1 -1
- package/lib/commonjs/components/ChatFlatList/index.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +191 -0
- package/lib/commonjs/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js +12 -1
- package/lib/commonjs/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/commonjs/components/MessageSearchResultItem.js +2 -8
- package/lib/commonjs/components/MessageSearchResultItem.js.map +1 -1
- package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
- package/lib/commonjs/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js +3 -9
- package/lib/commonjs/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/commonjs/containers/SendbirdUIKitContainer.js +43 -9
- package/lib/commonjs/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/commonjs/contexts/SendbirdChatCtx.js +5 -0
- package/lib/commonjs/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js +5 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js +47 -10
- package/lib/commonjs/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js +38 -3
- package/lib/commonjs/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/commonjs/domain/groupChannel/types.js.map +1 -1
- package/lib/commonjs/domain/openChannel/types.js.map +1 -1
- package/lib/commonjs/fragments/createGroupChannelFragment.js +19 -0
- package/lib/commonjs/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/commonjs/hooks/useConnection.js +2 -1
- package/lib/commonjs/hooks/useConnection.js.map +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js +1 -1
- package/lib/commonjs/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/commonjs/hooks/useMentionTextInput.js +4 -3
- package/lib/commonjs/hooks/useMentionTextInput.js.map +1 -1
- package/lib/commonjs/libs/MentionManager.js.map +1 -1
- package/lib/commonjs/localization/StringSet.type.js.map +1 -1
- package/lib/commonjs/localization/createBaseStringSet.js +29 -0
- package/lib/commonjs/localization/createBaseStringSet.js.map +1 -1
- package/lib/commonjs/platform/createMediaService.native.js +1 -1
- package/lib/commonjs/platform/createMediaService.native.js.map +1 -1
- package/lib/commonjs/platform/types.js.map +1 -1
- package/lib/commonjs/utils/pubsub.js +3 -1
- package/lib/commonjs/utils/pubsub.js.map +1 -1
- package/lib/commonjs/version.js +1 -1
- package/lib/commonjs/version.js.map +1 -1
- package/lib/module/components/ChannelInput/SendInput.js +153 -21
- package/lib/module/components/ChannelInput/SendInput.js.map +1 -1
- package/lib/module/components/ChannelInput/index.js +6 -14
- package/lib/module/components/ChannelInput/index.js.map +1 -1
- package/lib/module/components/ChannelMessageList/index.js +34 -20
- package/lib/module/components/ChannelMessageList/index.js.map +1 -1
- package/lib/module/components/ChatFlatList/index.js +1 -1
- package/lib/module/components/ChatFlatList/index.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js +4 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.js.map +1 -1
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js +182 -0
- package/lib/module/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.js.map +1 -0
- package/lib/module/components/GroupChannelMessageRenderer/index.js +13 -2
- package/lib/module/components/GroupChannelMessageRenderer/index.js.map +1 -1
- package/lib/module/components/MessageSearchResultItem.js +3 -9
- package/lib/module/components/MessageSearchResultItem.js.map +1 -1
- package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js +8 -7
- package/lib/module/components/ReactionAddons/BottomSheetReactionAddon.js.map +1 -1
- package/lib/module/containers/GroupChannelPreviewContainer.js +4 -10
- package/lib/module/containers/GroupChannelPreviewContainer.js.map +1 -1
- package/lib/module/containers/SendbirdUIKitContainer.js +43 -9
- package/lib/module/containers/SendbirdUIKitContainer.js.map +1 -1
- package/lib/module/contexts/SendbirdChatCtx.js +6 -1
- package/lib/module/contexts/SendbirdChatCtx.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelInput.js +5 -1
- package/lib/module/domain/groupChannel/component/GroupChannelInput.js.map +1 -1
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js +50 -13
- package/lib/module/domain/groupChannel/component/GroupChannelMessageList.js.map +1 -1
- package/lib/module/domain/groupChannel/module/moduleContext.js +39 -4
- package/lib/module/domain/groupChannel/module/moduleContext.js.map +1 -1
- package/lib/module/domain/groupChannel/types.js.map +1 -1
- package/lib/module/domain/openChannel/types.js.map +1 -1
- package/lib/module/fragments/createGroupChannelFragment.js +19 -0
- package/lib/module/fragments/createGroupChannelFragment.js.map +1 -1
- package/lib/module/hooks/useConnection.js +2 -1
- package/lib/module/hooks/useConnection.js.map +1 -1
- package/lib/module/hooks/useMentionSuggestion.js +1 -1
- package/lib/module/hooks/useMentionSuggestion.js.map +1 -1
- package/lib/module/hooks/useMentionTextInput.js +4 -3
- package/lib/module/hooks/useMentionTextInput.js.map +1 -1
- package/lib/module/libs/MentionManager.js.map +1 -1
- package/lib/module/localization/StringSet.type.js.map +1 -1
- package/lib/module/localization/createBaseStringSet.js +30 -1
- package/lib/module/localization/createBaseStringSet.js.map +1 -1
- package/lib/module/platform/createMediaService.native.js +1 -1
- package/lib/module/platform/createMediaService.native.js.map +1 -1
- package/lib/module/platform/types.js.map +1 -1
- package/lib/module/utils/pubsub.js +3 -1
- package/lib/module/utils/pubsub.js.map +1 -1
- package/lib/module/version.js +1 -1
- package/lib/module/version.js.map +1 -1
- package/lib/typescript/src/components/ChannelInput/index.d.ts +2 -0
- package/lib/typescript/src/components/ChannelMessageList/index.d.ts +4 -1
- package/lib/typescript/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.d.ts +9 -0
- package/lib/typescript/src/components/GroupChannelMessageRenderer/index.d.ts +1 -0
- package/lib/typescript/src/components/OpenChannelMessageRenderer/index.d.ts +1 -0
- package/lib/typescript/src/containers/SendbirdUIKitContainer.d.ts +4 -2
- package/lib/typescript/src/domain/groupChannel/component/GroupChannelMessageList.d.ts +4 -0
- package/lib/typescript/src/domain/groupChannel/types.d.ts +6 -2
- package/lib/typescript/src/domain/openChannel/component/OpenChannelHeader.d.ts +1 -1
- package/lib/typescript/src/domain/openChannel/types.d.ts +1 -2
- package/lib/typescript/src/libs/MentionManager.d.ts +1 -4
- package/lib/typescript/src/localization/StringSet.type.d.ts +7 -1
- package/lib/typescript/src/platform/types.d.ts +10 -11
- package/lib/typescript/src/version.d.ts +1 -1
- package/package.json +6 -6
- package/src/components/ChannelInput/SendInput.tsx +184 -51
- package/src/components/ChannelInput/index.tsx +11 -15
- package/src/components/ChannelMessageList/index.tsx +45 -27
- package/src/components/ChatFlatList/index.tsx +1 -1
- package/src/components/GroupChannelMessageRenderer/GroupChannelMessageFocusAnimation.tsx +5 -1
- package/src/components/GroupChannelMessageRenderer/GroupChannelMessageParentMessage.tsx +177 -0
- package/src/components/GroupChannelMessageRenderer/index.tsx +16 -1
- package/src/components/MessageSearchResultItem.tsx +3 -5
- package/src/components/ReactionAddons/BottomSheetReactionAddon.tsx +6 -7
- package/src/containers/GroupChannelPreviewContainer.tsx +6 -7
- package/src/containers/SendbirdUIKitContainer.tsx +40 -10
- package/src/contexts/SendbirdChatCtx.tsx +7 -1
- package/src/domain/groupChannel/component/GroupChannelInput.tsx +5 -1
- package/src/domain/groupChannel/component/GroupChannelMessageList.tsx +46 -13
- package/src/domain/groupChannel/module/moduleContext.tsx +38 -3
- package/src/domain/groupChannel/types.ts +8 -2
- package/src/domain/openChannel/types.ts +1 -2
- package/src/fragments/createGroupChannelFragment.tsx +15 -0
- package/src/hooks/useConnection.ts +1 -1
- package/src/hooks/useMentionSuggestion.ts +2 -1
- package/src/hooks/useMentionTextInput.ts +2 -2
- package/src/libs/MentionManager.tsx +1 -8
- package/src/localization/StringSet.type.ts +11 -0
- package/src/localization/createBaseStringSet.ts +30 -0
- package/src/platform/createMediaService.native.tsx +1 -1
- package/src/platform/types.ts +9 -9
- package/src/utils/pubsub.ts +3 -1
- package/src/version.ts +1 -1
|
@@ -2,22 +2,26 @@ import React, { useContext, useEffect, useRef } from 'react';
|
|
|
2
2
|
import type { FlatList } from 'react-native';
|
|
3
3
|
|
|
4
4
|
import { useChannelHandler } from '@sendbird/uikit-chat-hooks';
|
|
5
|
+
import { useToast } from '@sendbird/uikit-react-native-foundation';
|
|
5
6
|
import type { SendbirdMessage } from '@sendbird/uikit-utils';
|
|
6
|
-
import { isDifferentChannel, useFreshCallback, useUniqHandlerId } from '@sendbird/uikit-utils';
|
|
7
|
+
import { isDifferentChannel, useFreshCallback, useIsFirstMount, useUniqHandlerId } from '@sendbird/uikit-utils';
|
|
7
8
|
|
|
8
9
|
import ChannelMessageList from '../../../components/ChannelMessageList';
|
|
9
|
-
import { MESSAGE_SEARCH_SAFE_SCROLL_DELAY } from '../../../constants';
|
|
10
|
-
import { useSendbirdChat } from '../../../hooks/useContext';
|
|
10
|
+
import { MESSAGE_FOCUS_ANIMATION_DELAY, MESSAGE_SEARCH_SAFE_SCROLL_DELAY } from '../../../constants';
|
|
11
|
+
import { useLocalization, useSendbirdChat } from '../../../hooks/useContext';
|
|
11
12
|
import { GroupChannelContexts } from '../module/moduleContext';
|
|
12
13
|
import type { GroupChannelProps } from '../types';
|
|
13
14
|
|
|
14
15
|
const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
16
|
+
const toast = useToast();
|
|
17
|
+
const { STRINGS } = useLocalization();
|
|
15
18
|
const { sdk } = useSendbirdChat();
|
|
16
|
-
const { setMessageToEdit } = useContext(GroupChannelContexts.Fragment);
|
|
19
|
+
const { setMessageToEdit, setMessageToReply } = useContext(GroupChannelContexts.Fragment);
|
|
17
20
|
const { subscribe } = useContext(GroupChannelContexts.PubSub);
|
|
18
21
|
|
|
19
22
|
const id = useUniqHandlerId('GroupChannelMessageList');
|
|
20
23
|
const ref = useRef<FlatList<SendbirdMessage>>(null);
|
|
24
|
+
const isFirstMount = useIsFirstMount();
|
|
21
25
|
|
|
22
26
|
// FIXME: Workaround, should run after data has been applied to UI.
|
|
23
27
|
const lazyScrollToBottom = (animated = false, timeout = 0) => {
|
|
@@ -33,22 +37,35 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
33
37
|
}, timeout);
|
|
34
38
|
};
|
|
35
39
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (
|
|
42
|
-
|
|
40
|
+
const scrollToMessage = useFreshCallback((createdAt: number, focusAnimated = false): boolean => {
|
|
41
|
+
const foundMessageIndex = props.messages.findIndex((it) => it.createdAt === createdAt);
|
|
42
|
+
const isIncludedInList = foundMessageIndex > -1;
|
|
43
|
+
|
|
44
|
+
if (isIncludedInList) {
|
|
45
|
+
if (focusAnimated) {
|
|
46
|
+
setTimeout(() => props.onUpdateSearchItem({ startingPoint: createdAt }), MESSAGE_FOCUS_ANIMATION_DELAY);
|
|
47
|
+
}
|
|
48
|
+
lazyScrollToIndex(foundMessageIndex, true, isFirstMount ? MESSAGE_SEARCH_SAFE_SCROLL_DELAY : 0);
|
|
49
|
+
} else {
|
|
50
|
+
if (props.channel.messageOffsetTimestamp <= createdAt) {
|
|
51
|
+
if (focusAnimated) props.onUpdateSearchItem({ startingPoint: createdAt });
|
|
52
|
+
props.onResetMessageListWithStartingPoint(createdAt);
|
|
53
|
+
} else {
|
|
54
|
+
return false;
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
|
-
|
|
57
|
+
|
|
58
|
+
return true;
|
|
59
|
+
});
|
|
46
60
|
|
|
47
61
|
const scrollToBottom = useFreshCallback((animated = false) => {
|
|
48
62
|
if (props.hasNext()) {
|
|
63
|
+
props.onUpdateSearchItem(undefined);
|
|
64
|
+
props.onScrolledAwayFromBottom(false);
|
|
65
|
+
|
|
49
66
|
props.onResetMessageList(() => {
|
|
50
|
-
lazyScrollToBottom(animated);
|
|
51
67
|
props.onScrolledAwayFromBottom(false);
|
|
68
|
+
lazyScrollToBottom(animated);
|
|
52
69
|
});
|
|
53
70
|
} else {
|
|
54
71
|
lazyScrollToBottom(animated);
|
|
@@ -85,11 +102,27 @@ const GroupChannelMessageList = (props: GroupChannelProps['MessageList']) => {
|
|
|
85
102
|
});
|
|
86
103
|
}, [props.scrolledAwayFromBottom]);
|
|
87
104
|
|
|
105
|
+
// Only trigger once when message list mount with initial props.searchItem
|
|
106
|
+
// - Search screen + searchItem > mount message list
|
|
107
|
+
// - Reset message list + searchItem > re-mount message list
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (isFirstMount && props.searchItem) {
|
|
110
|
+
scrollToMessage(props.searchItem.startingPoint);
|
|
111
|
+
}
|
|
112
|
+
}, [isFirstMount]);
|
|
113
|
+
|
|
114
|
+
const onPressParentMessage = useFreshCallback((message: SendbirdMessage) => {
|
|
115
|
+
const canScrollToParent = scrollToMessage(message.createdAt, true);
|
|
116
|
+
if (!canScrollToParent) toast.show(STRINGS.TOAST.FIND_PARENT_MSG_ERROR, 'error');
|
|
117
|
+
});
|
|
118
|
+
|
|
88
119
|
return (
|
|
89
120
|
<ChannelMessageList
|
|
90
121
|
{...props}
|
|
91
122
|
ref={ref}
|
|
123
|
+
onReplyMessage={setMessageToReply}
|
|
92
124
|
onEditMessage={setMessageToEdit}
|
|
125
|
+
onPressParentMessage={onPressParentMessage}
|
|
93
126
|
onPressNewMessagesButton={scrollToBottom}
|
|
94
127
|
onPressScrollToBottomButton={scrollToBottom}
|
|
95
128
|
/>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { createContext, useState } from 'react';
|
|
1
|
+
import React, { createContext, useCallback, useState } from 'react';
|
|
2
2
|
|
|
3
3
|
import { useChannelHandler } from '@sendbird/uikit-chat-hooks';
|
|
4
4
|
import {
|
|
@@ -21,6 +21,7 @@ export const GroupChannelContexts: GroupChannelContextsType = {
|
|
|
21
21
|
headerTitle: '',
|
|
22
22
|
channel: {} as SendbirdGroupChannel,
|
|
23
23
|
setMessageToEdit: NOOP,
|
|
24
|
+
setMessageToReply: NOOP,
|
|
24
25
|
}),
|
|
25
26
|
TypingIndicator: createContext({
|
|
26
27
|
typingUsers: [] as SendbirdUser[],
|
|
@@ -46,8 +47,40 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
|
|
|
46
47
|
|
|
47
48
|
const [typingUsers, setTypingUsers] = useState<SendbirdUser[]>([]);
|
|
48
49
|
const [messageToEdit, setMessageToEdit] = useState<SendbirdUserMessage | SendbirdFileMessage>();
|
|
50
|
+
const [messageToReply, setMessageToReply] = useState<SendbirdUserMessage | SendbirdFileMessage>();
|
|
51
|
+
|
|
52
|
+
const updateInputMode = (mode: 'send' | 'edit' | 'reply', message?: SendbirdUserMessage | SendbirdFileMessage) => {
|
|
53
|
+
if (mode === 'send' || !message) {
|
|
54
|
+
setMessageToEdit(undefined);
|
|
55
|
+
setMessageToReply(undefined);
|
|
56
|
+
return;
|
|
57
|
+
} else if (mode === 'edit') {
|
|
58
|
+
setMessageToEdit(message);
|
|
59
|
+
setMessageToReply(undefined);
|
|
60
|
+
return;
|
|
61
|
+
} else if (mode === 'reply') {
|
|
62
|
+
setMessageToEdit(undefined);
|
|
63
|
+
setMessageToReply(message);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
49
67
|
|
|
50
68
|
useChannelHandler(sdk, handlerId, {
|
|
69
|
+
onMessageDeleted(_, messageId) {
|
|
70
|
+
if (messageToReply?.messageId === messageId) {
|
|
71
|
+
setMessageToReply(undefined);
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
onChannelFrozen(frozenChannel) {
|
|
75
|
+
if (frozenChannel.url === channel.url) {
|
|
76
|
+
setMessageToReply(undefined);
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
onUserMuted(mutedChannel, user) {
|
|
80
|
+
if (mutedChannel.url === channel.url && user.userId === sdk.currentUser?.userId) {
|
|
81
|
+
setMessageToReply(undefined);
|
|
82
|
+
}
|
|
83
|
+
},
|
|
51
84
|
onTypingStatusUpdated(eventChannel) {
|
|
52
85
|
if (isDifferentChannel(channel, eventChannel)) return;
|
|
53
86
|
if (!enableTypingIndicator) return;
|
|
@@ -61,9 +94,11 @@ export const GroupChannelContextsProvider: GroupChannelModule['Provider'] = ({
|
|
|
61
94
|
value={{
|
|
62
95
|
headerTitle: STRINGS.GROUP_CHANNEL.HEADER_TITLE(currentUser?.userId ?? '', channel),
|
|
63
96
|
channel,
|
|
64
|
-
messageToEdit,
|
|
65
|
-
setMessageToEdit,
|
|
66
97
|
keyboardAvoidOffset,
|
|
98
|
+
messageToEdit,
|
|
99
|
+
setMessageToEdit: useCallback((message) => updateInputMode('edit', message), []),
|
|
100
|
+
messageToReply,
|
|
101
|
+
setMessageToReply: useCallback((message) => updateInputMode('reply', message), []),
|
|
67
102
|
}}
|
|
68
103
|
>
|
|
69
104
|
<GroupChannelContexts.TypingIndicator.Provider value={{ typingUsers }}>
|
|
@@ -73,6 +73,10 @@ export interface GroupChannelProps {
|
|
|
73
73
|
| 'searchItem'
|
|
74
74
|
> & {
|
|
75
75
|
onResetMessageList: (callback?: () => void) => void;
|
|
76
|
+
onResetMessageListWithStartingPoint: (startingPoint: number, callback?: () => void) => void;
|
|
77
|
+
|
|
78
|
+
// Changing the search item will trigger the focus animation on messages.
|
|
79
|
+
onUpdateSearchItem: (searchItem?: GroupChannelProps['MessageList']['searchItem']) => void;
|
|
76
80
|
};
|
|
77
81
|
Input: Pick<
|
|
78
82
|
ChannelInputProps,
|
|
@@ -102,10 +106,12 @@ export interface GroupChannelProps {
|
|
|
102
106
|
export interface GroupChannelContextsType {
|
|
103
107
|
Fragment: React.Context<{
|
|
104
108
|
headerTitle: string;
|
|
109
|
+
keyboardAvoidOffset?: number;
|
|
105
110
|
channel: SendbirdGroupChannel;
|
|
106
111
|
messageToEdit?: SendbirdUserMessage | SendbirdFileMessage;
|
|
107
112
|
setMessageToEdit: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
|
|
108
|
-
|
|
113
|
+
messageToReply?: SendbirdUserMessage | SendbirdFileMessage;
|
|
114
|
+
setMessageToReply: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
|
|
109
115
|
}>;
|
|
110
116
|
TypingIndicator: React.Context<{
|
|
111
117
|
typingUsers: SendbirdUser[];
|
|
@@ -132,7 +138,7 @@ export type GroupChannelPubSubContextPayload =
|
|
|
132
138
|
};
|
|
133
139
|
}
|
|
134
140
|
| {
|
|
135
|
-
type: 'MESSAGES_RECEIVED';
|
|
141
|
+
type: 'MESSAGES_RECEIVED' | 'MESSAGES_UPDATED';
|
|
136
142
|
data: {
|
|
137
143
|
messages: SendbirdMessage[];
|
|
138
144
|
};
|
|
@@ -18,7 +18,6 @@ import type { ChannelInputProps } from '../../components/ChannelInput';
|
|
|
18
18
|
import type { ChannelMessageListProps } from '../../components/ChannelMessageList';
|
|
19
19
|
import type { CommonComponent } from '../../types';
|
|
20
20
|
import type { PubSub } from '../../utils/pubsub';
|
|
21
|
-
import type { GroupChannelPubSubContextPayload } from '../groupChannel/types';
|
|
22
21
|
|
|
23
22
|
export type OpenChannelProps = {
|
|
24
23
|
Fragment: {
|
|
@@ -101,7 +100,7 @@ export type OpenChannelContextsType = {
|
|
|
101
100
|
setMessageToEdit: (msg?: SendbirdUserMessage | SendbirdFileMessage) => void;
|
|
102
101
|
keyboardAvoidOffset?: number;
|
|
103
102
|
}>;
|
|
104
|
-
PubSub: React.Context<PubSub<
|
|
103
|
+
PubSub: React.Context<PubSub<OpenChannelPubSubContextPayload>>;
|
|
105
104
|
};
|
|
106
105
|
export interface OpenChannelModule {
|
|
107
106
|
Provider: CommonComponent<OpenChannelProps['Provider']>;
|
|
@@ -86,6 +86,9 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
|
|
|
86
86
|
onMessagesReceived(messages) {
|
|
87
87
|
groupChannelPubSub.publish({ type: 'MESSAGES_RECEIVED', data: { messages } });
|
|
88
88
|
},
|
|
89
|
+
onMessagesUpdated(messages) {
|
|
90
|
+
groupChannelPubSub.publish({ type: 'MESSAGES_UPDATED', data: { messages } });
|
|
91
|
+
},
|
|
89
92
|
collectionCreator,
|
|
90
93
|
sortComparator,
|
|
91
94
|
onChannelDeleted,
|
|
@@ -110,7 +113,17 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
|
|
|
110
113
|
|
|
111
114
|
const onResetMessageList = useCallback((callback?: () => void) => {
|
|
112
115
|
resetWithStartingPoint(Number.MAX_SAFE_INTEGER, callback);
|
|
116
|
+
}, []);
|
|
117
|
+
|
|
118
|
+
const onResetMessageListWithStartingPoint = useCallback((startingPoint: number, callback?: () => void) => {
|
|
119
|
+
resetWithStartingPoint(startingPoint, callback);
|
|
120
|
+
}, []);
|
|
121
|
+
|
|
122
|
+
// Changing the search item will trigger the focus animation on messages.
|
|
123
|
+
const onUpdateSearchItem: GroupChannelProps['MessageList']['onUpdateSearchItem'] = useCallback((searchItem) => {
|
|
124
|
+
// Clean up for animation trigger with useEffect
|
|
113
125
|
setInternalSearchItem(undefined);
|
|
126
|
+
setInternalSearchItem(searchItem);
|
|
114
127
|
}, []);
|
|
115
128
|
|
|
116
129
|
const onPending = (message: SendbirdFileMessage | SendbirdUserMessage) => {
|
|
@@ -169,6 +182,8 @@ const createGroupChannelFragment = (initModule?: Partial<GroupChannelModule>): G
|
|
|
169
182
|
channel={channel}
|
|
170
183
|
searchItem={internalSearchItem}
|
|
171
184
|
onResetMessageList={onResetMessageList}
|
|
185
|
+
onResetMessageListWithStartingPoint={onResetMessageListWithStartingPoint}
|
|
186
|
+
onUpdateSearchItem={onUpdateSearchItem}
|
|
172
187
|
enableMessageGrouping={enableMessageGrouping}
|
|
173
188
|
currentUserId={currentUser?.userId}
|
|
174
189
|
renderMessage={renderItem}
|
|
@@ -16,7 +16,7 @@ function isCacheRestrictedError(error: SendbirdError) {
|
|
|
16
16
|
|
|
17
17
|
async function initEmoji(sdk: SendbirdChatSDK, emojiManager: EmojiManager) {
|
|
18
18
|
await emojiManager.init();
|
|
19
|
-
if (sdk.appInfo
|
|
19
|
+
if (sdk.appInfo?.emojiHash !== emojiManager.emojiHash) {
|
|
20
20
|
try {
|
|
21
21
|
const container = await sdk.getAllEmoji();
|
|
22
22
|
await emojiManager.init(container);
|
|
@@ -85,7 +85,8 @@ const useMentionSuggestion = (params: {
|
|
|
85
85
|
limit: mentionManager.config.suggestionLimit + 1,
|
|
86
86
|
})
|
|
87
87
|
.next()
|
|
88
|
-
.then((members) => members.filter((member) => member.userId !== currentUser?.userId))
|
|
88
|
+
.then((members) => members.filter((member) => member.userId !== currentUser?.userId))
|
|
89
|
+
.then((members) => members.slice(0, mentionManager.config.suggestionLimit));
|
|
89
90
|
} else {
|
|
90
91
|
return freshChannel.members
|
|
91
92
|
.sort((a, b) => a.nickname?.localeCompare(b.nickname))
|
|
@@ -25,8 +25,8 @@ const useMentionTextInput = (params: { messageToEdit?: SendbirdUserMessage | Sen
|
|
|
25
25
|
)
|
|
26
26
|
) {
|
|
27
27
|
const result = mentionManager.templateToTextAndMentionedUsers(
|
|
28
|
-
params.messageToEdit
|
|
29
|
-
params.messageToEdit
|
|
28
|
+
params.messageToEdit?.mentionedMessageTemplate ?? '',
|
|
29
|
+
params.messageToEdit?.mentionedUsers ?? [],
|
|
30
30
|
);
|
|
31
31
|
|
|
32
32
|
mentionedUsersRef.current = result.mentionedUsers;
|
|
@@ -217,10 +217,7 @@ class MentionManager {
|
|
|
217
217
|
public shouldUseMentionedMessageTemplate = (
|
|
218
218
|
message?: SendbirdUserMessage | SendbirdFileMessage,
|
|
219
219
|
mentionEnabled?: boolean,
|
|
220
|
-
):
|
|
221
|
-
SendbirdUserMessage | SendbirdFileMessage,
|
|
222
|
-
'mentionedMessageTemplate' | 'mentionedUsers' | 'mentionedUserIds' | 'mentionType'
|
|
223
|
-
> => {
|
|
220
|
+
): boolean => {
|
|
224
221
|
return Boolean(
|
|
225
222
|
mentionEnabled &&
|
|
226
223
|
message?.mentionedMessageTemplate &&
|
|
@@ -230,10 +227,6 @@ class MentionManager {
|
|
|
230
227
|
};
|
|
231
228
|
}
|
|
232
229
|
|
|
233
|
-
type RequiredSpecific<T, K extends keyof T> = T & {
|
|
234
|
-
[P in K]-?: T[P];
|
|
235
|
-
};
|
|
236
|
-
|
|
237
230
|
const styles = createStyleSheet({
|
|
238
231
|
mentionedText: { fontWeight: '700' },
|
|
239
232
|
});
|
|
@@ -9,6 +9,7 @@ import type {
|
|
|
9
9
|
SendbirdOpenChannel,
|
|
10
10
|
SendbirdParticipant,
|
|
11
11
|
SendbirdUser,
|
|
12
|
+
SendbirdUserMessage,
|
|
12
13
|
} from '@sendbird/uikit-utils';
|
|
13
14
|
|
|
14
15
|
/**
|
|
@@ -243,6 +244,11 @@ export interface StringSet {
|
|
|
243
244
|
USER_NO_NAME: string;
|
|
244
245
|
CHANNEL_NO_MEMBERS: string;
|
|
245
246
|
TYPING_INDICATOR_TYPINGS: (users: SendbirdUser[]) => string | undefined;
|
|
247
|
+
REPLY_FROM_SENDER_TO_RECEIVER: (
|
|
248
|
+
replyMessage: SendbirdUserMessage | SendbirdFileMessage,
|
|
249
|
+
parentMessage: SendbirdUserMessage | SendbirdFileMessage,
|
|
250
|
+
currentUserId?: string,
|
|
251
|
+
) => string;
|
|
246
252
|
|
|
247
253
|
USER_BAR_ME_POSTFIX: string;
|
|
248
254
|
USER_BAR_OPERATOR: string;
|
|
@@ -261,6 +267,7 @@ export interface StringSet {
|
|
|
261
267
|
CHANNEL_INPUT_PLACEHOLDER_ACTIVE: string;
|
|
262
268
|
CHANNEL_INPUT_PLACEHOLDER_DISABLED: string;
|
|
263
269
|
CHANNEL_INPUT_PLACEHOLDER_MUTED: string;
|
|
270
|
+
CHANNEL_INPUT_PLACEHOLDER_REPLY: string;
|
|
264
271
|
CHANNEL_INPUT_EDIT_OK: string;
|
|
265
272
|
CHANNEL_INPUT_EDIT_CANCEL: string;
|
|
266
273
|
/** ChannelInput > Attachments **/
|
|
@@ -268,12 +275,15 @@ export interface StringSet {
|
|
|
268
275
|
CHANNEL_INPUT_ATTACHMENT_CAMERA_VIDEO: string;
|
|
269
276
|
CHANNEL_INPUT_ATTACHMENT_PHOTO_LIBRARY: string;
|
|
270
277
|
CHANNEL_INPUT_ATTACHMENT_FILES: string;
|
|
278
|
+
CHANNEL_INPUT_REPLY_PREVIEW_TITLE: (user: SendbirdUser) => string;
|
|
279
|
+
CHANNEL_INPUT_REPLY_PREVIEW_BODY: (message: SendbirdUserMessage | SendbirdFileMessage) => string;
|
|
271
280
|
|
|
272
281
|
/** Channel > Message **/
|
|
273
282
|
CHANNEL_MESSAGE_COPY: string;
|
|
274
283
|
CHANNEL_MESSAGE_EDIT: string;
|
|
275
284
|
CHANNEL_MESSAGE_SAVE: string;
|
|
276
285
|
CHANNEL_MESSAGE_DELETE: string;
|
|
286
|
+
CHANNEL_MESSAGE_REPLY: string;
|
|
277
287
|
/** Channel > Message > Delete confirm **/
|
|
278
288
|
CHANNEL_MESSAGE_DELETE_CONFIRM_TITLE: string;
|
|
279
289
|
CHANNEL_MESSAGE_DELETE_CONFIRM_OK: string;
|
|
@@ -327,6 +337,7 @@ export interface StringSet {
|
|
|
327
337
|
LEAVE_CHANNEL_ERROR: string;
|
|
328
338
|
UNKNOWN_ERROR: string;
|
|
329
339
|
GET_CHANNEL_ERROR: string;
|
|
340
|
+
FIND_PARENT_MSG_ERROR: string;
|
|
330
341
|
};
|
|
331
342
|
PROFILE_CARD: {
|
|
332
343
|
BUTTON_MESSAGE: string;
|
|
@@ -3,6 +3,7 @@ import type { Locale } from 'date-fns';
|
|
|
3
3
|
import type { PartialDeep } from '@sendbird/uikit-utils';
|
|
4
4
|
import {
|
|
5
5
|
getDateSeparatorFormat,
|
|
6
|
+
getFileTypeFromMessage,
|
|
6
7
|
getGroupChannelLastMessage,
|
|
7
8
|
getGroupChannelPreviewTime,
|
|
8
9
|
getGroupChannelTitle,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
getOpenChannelTitle,
|
|
15
16
|
} from '@sendbird/uikit-utils';
|
|
16
17
|
|
|
18
|
+
import { UNKNOWN_USER_ID } from '../constants';
|
|
17
19
|
import type { StringSet } from './StringSet.type';
|
|
18
20
|
|
|
19
21
|
type StringSetCreateOptions = {
|
|
@@ -248,6 +250,12 @@ export const createBaseStringSet = ({ dateLocale, overrides }: StringSetCreateOp
|
|
|
248
250
|
if (users.length === 2) return `${userNames.join(' and ')} are typing...`;
|
|
249
251
|
return 'Several people are typing...';
|
|
250
252
|
},
|
|
253
|
+
REPLY_FROM_SENDER_TO_RECEIVER: (reply, parent, currentUserId = UNKNOWN_USER_ID) => {
|
|
254
|
+
const senderNickname = reply.sender.nickname || USER_NO_NAME;
|
|
255
|
+
const receiverNickname = parent.sender.nickname || USER_NO_NAME;
|
|
256
|
+
return `${reply.sender.userId !== currentUserId ? senderNickname : 'You'} replied to ${receiverNickname}`;
|
|
257
|
+
},
|
|
258
|
+
|
|
251
259
|
USER_BAR_ME_POSTFIX: ' (You)',
|
|
252
260
|
USER_BAR_OPERATOR: 'Operator',
|
|
253
261
|
REGISTER_AS_OPERATOR: 'Register as operator',
|
|
@@ -261,6 +269,7 @@ export const createBaseStringSet = ({ dateLocale, overrides }: StringSetCreateOp
|
|
|
261
269
|
CHANNEL_MESSAGE_EDIT: 'Edit',
|
|
262
270
|
CHANNEL_MESSAGE_SAVE: 'Save',
|
|
263
271
|
CHANNEL_MESSAGE_DELETE: 'Delete',
|
|
272
|
+
CHANNEL_MESSAGE_REPLY: 'Reply',
|
|
264
273
|
CHANNEL_MESSAGE_DELETE_CONFIRM_TITLE: 'Delete message?',
|
|
265
274
|
CHANNEL_MESSAGE_DELETE_CONFIRM_OK: 'Delete',
|
|
266
275
|
CHANNEL_MESSAGE_DELETE_CONFIRM_CANCEL: 'Cancel',
|
|
@@ -273,8 +282,28 @@ export const createBaseStringSet = ({ dateLocale, overrides }: StringSetCreateOp
|
|
|
273
282
|
CHANNEL_INPUT_PLACEHOLDER_ACTIVE: 'Enter message',
|
|
274
283
|
CHANNEL_INPUT_PLACEHOLDER_DISABLED: 'Chat not available in this channel.',
|
|
275
284
|
CHANNEL_INPUT_PLACEHOLDER_MUTED: "You're muted by the operator.",
|
|
285
|
+
CHANNEL_INPUT_PLACEHOLDER_REPLY: 'Reply to message',
|
|
276
286
|
CHANNEL_INPUT_EDIT_OK: 'Save',
|
|
277
287
|
CHANNEL_INPUT_EDIT_CANCEL: 'Cancel',
|
|
288
|
+
CHANNEL_INPUT_REPLY_PREVIEW_TITLE: (user) => `Reply to ${user.nickname || USER_NO_NAME}`,
|
|
289
|
+
CHANNEL_INPUT_REPLY_PREVIEW_BODY: (message) => {
|
|
290
|
+
if (message.isFileMessage()) {
|
|
291
|
+
const fileType = getFileTypeFromMessage(message);
|
|
292
|
+
switch (fileType) {
|
|
293
|
+
case 'image':
|
|
294
|
+
return message.type.toLowerCase().includes('gif') ? 'GIF' : 'Photo';
|
|
295
|
+
case 'video':
|
|
296
|
+
return 'Video';
|
|
297
|
+
case 'audio':
|
|
298
|
+
return 'Audio';
|
|
299
|
+
default:
|
|
300
|
+
return message.name;
|
|
301
|
+
}
|
|
302
|
+
} else if (message.isUserMessage()) {
|
|
303
|
+
return message.message;
|
|
304
|
+
}
|
|
305
|
+
return 'Unknown message type.';
|
|
306
|
+
},
|
|
278
307
|
...overrides?.LABELS,
|
|
279
308
|
},
|
|
280
309
|
FILE_VIEWER: {
|
|
@@ -325,6 +354,7 @@ export const createBaseStringSet = ({ dateLocale, overrides }: StringSetCreateOp
|
|
|
325
354
|
LEAVE_CHANNEL_ERROR: "Couldn't leave channel.",
|
|
326
355
|
UNKNOWN_ERROR: 'Something went wrong.',
|
|
327
356
|
GET_CHANNEL_ERROR: "Couldn't retrieve channel.",
|
|
357
|
+
FIND_PARENT_MSG_ERROR: "Couldn't find the original message for this reply.",
|
|
328
358
|
...overrides?.TOAST,
|
|
329
359
|
},
|
|
330
360
|
PROFILE_CARD: {
|
package/src/platform/types.ts
CHANGED
|
@@ -61,18 +61,20 @@ export interface FileSystemServiceInterface {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
// ---------- MediaService ---------- //
|
|
64
|
-
|
|
64
|
+
export type VideoProps = {
|
|
65
65
|
source: { uri: string } | number;
|
|
66
66
|
resizeMode?: 'cover' | 'contain' | 'stretch';
|
|
67
67
|
onLoad?: () => void;
|
|
68
|
-
}
|
|
69
|
-
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export type GetVideoThumbnailOptions = {
|
|
70
71
|
url: string;
|
|
71
72
|
timeMills?: number;
|
|
72
73
|
quality?: number;
|
|
73
|
-
}
|
|
74
|
+
};
|
|
75
|
+
export type GetVideoThumbnailResult = Promise<{ path: string } | null>;
|
|
74
76
|
|
|
75
|
-
|
|
77
|
+
export type CompressImageOptions = {
|
|
76
78
|
/**
|
|
77
79
|
* A uri of image file to compress
|
|
78
80
|
* */
|
|
@@ -93,10 +95,8 @@ interface CompressImageOptions {
|
|
|
93
95
|
* 1 means highest quality and 0 the lowest quality.
|
|
94
96
|
* */
|
|
95
97
|
compressionRate?: number;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
type GetVideoThumbnailResult = Promise<{ path: string } | null>;
|
|
99
|
-
type CompressImageResult = Promise<{ uri: string; size: number } | null>;
|
|
98
|
+
};
|
|
99
|
+
export type CompressImageResult = Promise<{ uri: string; size: number } | null>;
|
|
100
100
|
|
|
101
101
|
export interface MediaServiceInterface {
|
|
102
102
|
VideoComponent<Props = {}>(props: VideoProps & Props): JSX.Element;
|
package/src/utils/pubsub.ts
CHANGED
|
@@ -8,7 +8,9 @@ const pubsub = <T>(): PubSub<T> => {
|
|
|
8
8
|
|
|
9
9
|
return {
|
|
10
10
|
publish: (data: unknown) => {
|
|
11
|
-
subscribers.forEach((subscriber) =>
|
|
11
|
+
subscribers.forEach((subscriber) => {
|
|
12
|
+
setTimeout(() => subscriber(data), 0);
|
|
13
|
+
});
|
|
12
14
|
},
|
|
13
15
|
subscribe: (subscriber: Function) => {
|
|
14
16
|
subscribers.add(subscriber);
|
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const VERSION = '3.
|
|
1
|
+
const VERSION = '3.1.1';
|
|
2
2
|
export default VERSION;
|