@droppii-org/chat-mobile 0.2.56 → 0.2.58

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.
Files changed (124) hide show
  1. package/lib/module/assets/images/index.js +2 -1
  2. package/lib/module/assets/images/index.js.map +1 -1
  3. package/lib/module/assets/images/search_empty.png +0 -0
  4. package/lib/module/components/Avatar/Avatar.utils.js +5 -3
  5. package/lib/module/components/Avatar/Avatar.utils.js.map +1 -1
  6. package/lib/module/components/Avatar/SingleAvatar.js +2 -0
  7. package/lib/module/components/Avatar/SingleAvatar.js.map +1 -1
  8. package/lib/module/components/ThreadCard/AvatarSection.js +8 -4
  9. package/lib/module/components/ThreadCard/AvatarSection.js.map +1 -1
  10. package/lib/module/config/api-endpoints.js +2 -1
  11. package/lib/module/config/api-endpoints.js.map +1 -1
  12. package/lib/module/constants/index.js +4 -0
  13. package/lib/module/constants/index.js.map +1 -0
  14. package/lib/module/hooks/message/useSearchMessage.js +58 -0
  15. package/lib/module/hooks/message/useSearchMessage.js.map +1 -0
  16. package/lib/module/hooks/query-keys.js +4 -0
  17. package/lib/module/hooks/query-keys.js.map +1 -1
  18. package/lib/module/index.js +1 -0
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/screens/ChatInfo/ChatInfoActions.js +1 -1
  21. package/lib/module/screens/ChatInfo/ChatInfoActions.js.map +1 -1
  22. package/lib/module/screens/ChatInfo/ChatInfoMediaRow.js +1 -1
  23. package/lib/module/screens/ChatInfo/ChatInfoMediaRow.js.map +1 -1
  24. package/lib/module/screens/MediaView/VideoPlayer.js +13 -1
  25. package/lib/module/screens/MediaView/VideoPlayer.js.map +1 -1
  26. package/lib/module/screens/MediaView/index.js +11 -6
  27. package/lib/module/screens/MediaView/index.js.map +1 -1
  28. package/lib/module/screens/SearchConversation/SearchAllResult.js +123 -0
  29. package/lib/module/screens/SearchConversation/SearchAllResult.js.map +1 -0
  30. package/lib/module/screens/SearchConversation/SearchEmpty.js +32 -0
  31. package/lib/module/screens/SearchConversation/SearchEmpty.js.map +1 -0
  32. package/lib/module/screens/SearchConversation/SearchMessagesResult.js +71 -0
  33. package/lib/module/screens/SearchConversation/SearchMessagesResult.js.map +1 -0
  34. package/lib/module/screens/SearchConversation/SearchResultItem.js +102 -0
  35. package/lib/module/screens/SearchConversation/SearchResultItem.js.map +1 -0
  36. package/lib/module/screens/SearchConversation/TabResult.js +118 -0
  37. package/lib/module/screens/SearchConversation/TabResult.js.map +1 -0
  38. package/lib/module/screens/SearchConversation/index.js +57 -0
  39. package/lib/module/screens/SearchConversation/index.js.map +1 -0
  40. package/lib/module/screens/SearchConversation/types.js +9 -0
  41. package/lib/module/screens/SearchConversation/types.js.map +1 -0
  42. package/lib/module/screens/chat-detail/ChatDetail.js +3 -1
  43. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  44. package/lib/module/services/endpoints.js +2 -1
  45. package/lib/module/services/endpoints.js.map +1 -1
  46. package/lib/module/translation/resources/i18n.js +7 -1
  47. package/lib/module/translation/resources/i18n.js.map +1 -1
  48. package/lib/module/types/chat.js.map +1 -1
  49. package/lib/module/utils/messageUtils.js +5 -5
  50. package/lib/module/utils/messageUtils.js.map +1 -1
  51. package/lib/typescript/src/assets/images/index.d.ts +1 -0
  52. package/lib/typescript/src/assets/images/index.d.ts.map +1 -1
  53. package/lib/typescript/src/components/Avatar/Avatar.types.d.ts +1 -1
  54. package/lib/typescript/src/components/Avatar/Avatar.types.d.ts.map +1 -1
  55. package/lib/typescript/src/components/Avatar/Avatar.utils.d.ts +2 -0
  56. package/lib/typescript/src/components/Avatar/Avatar.utils.d.ts.map +1 -1
  57. package/lib/typescript/src/components/Avatar/SingleAvatar.d.ts.map +1 -1
  58. package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts +2 -1
  59. package/lib/typescript/src/components/ThreadCard/AvatarSection.d.ts.map +1 -1
  60. package/lib/typescript/src/config/api-endpoints.d.ts +1 -0
  61. package/lib/typescript/src/config/api-endpoints.d.ts.map +1 -1
  62. package/lib/typescript/src/constants/index.d.ts +2 -0
  63. package/lib/typescript/src/constants/index.d.ts.map +1 -0
  64. package/lib/typescript/src/hooks/message/useSearchMessage.d.ts +221 -0
  65. package/lib/typescript/src/hooks/message/useSearchMessage.d.ts.map +1 -0
  66. package/lib/typescript/src/hooks/query-keys.d.ts +4 -0
  67. package/lib/typescript/src/hooks/query-keys.d.ts.map +1 -1
  68. package/lib/typescript/src/index.d.ts +1 -0
  69. package/lib/typescript/src/index.d.ts.map +1 -1
  70. package/lib/typescript/src/screens/MediaView/VideoPlayer.d.ts.map +1 -1
  71. package/lib/typescript/src/screens/MediaView/index.d.ts.map +1 -1
  72. package/lib/typescript/src/screens/SearchConversation/SearchAllResult.d.ts +10 -0
  73. package/lib/typescript/src/screens/SearchConversation/SearchAllResult.d.ts.map +1 -0
  74. package/lib/typescript/src/screens/SearchConversation/SearchEmpty.d.ts +2 -0
  75. package/lib/typescript/src/screens/SearchConversation/SearchEmpty.d.ts.map +1 -0
  76. package/lib/typescript/src/screens/SearchConversation/SearchMessagesResult.d.ts +8 -0
  77. package/lib/typescript/src/screens/SearchConversation/SearchMessagesResult.d.ts.map +1 -0
  78. package/lib/typescript/src/screens/SearchConversation/SearchResultItem.d.ts +10 -0
  79. package/lib/typescript/src/screens/SearchConversation/SearchResultItem.d.ts.map +1 -0
  80. package/lib/typescript/src/screens/SearchConversation/TabResult.d.ts +8 -0
  81. package/lib/typescript/src/screens/SearchConversation/TabResult.d.ts.map +1 -0
  82. package/lib/typescript/src/screens/SearchConversation/index.d.ts +7 -0
  83. package/lib/typescript/src/screens/SearchConversation/index.d.ts.map +1 -0
  84. package/lib/typescript/src/screens/SearchConversation/types.d.ts +6 -0
  85. package/lib/typescript/src/screens/SearchConversation/types.d.ts.map +1 -0
  86. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +1 -1
  87. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  88. package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -0
  89. package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
  90. package/lib/typescript/src/services/endpoints.d.ts +1 -0
  91. package/lib/typescript/src/services/endpoints.d.ts.map +1 -1
  92. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  93. package/lib/typescript/src/types/chat.d.ts +13 -1
  94. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  95. package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
  96. package/package.json +1 -1
  97. package/src/assets/images/index.ts +1 -0
  98. package/src/assets/images/search_empty.png +0 -0
  99. package/src/components/Avatar/Avatar.types.ts +1 -1
  100. package/src/components/Avatar/Avatar.utils.ts +5 -3
  101. package/src/components/Avatar/SingleAvatar.tsx +2 -0
  102. package/src/components/ThreadCard/AvatarSection.tsx +5 -2
  103. package/src/config/api-endpoints.ts +2 -0
  104. package/src/constants/index.ts +1 -0
  105. package/src/hooks/message/useSearchMessage.ts +78 -0
  106. package/src/hooks/query-keys.ts +6 -0
  107. package/src/index.tsx +1 -0
  108. package/src/screens/ChatInfo/ChatInfoActions.tsx +1 -1
  109. package/src/screens/ChatInfo/ChatInfoMediaRow.tsx +1 -1
  110. package/src/screens/MediaView/VideoPlayer.tsx +13 -2
  111. package/src/screens/MediaView/index.tsx +10 -6
  112. package/src/screens/SearchConversation/SearchAllResult.tsx +154 -0
  113. package/src/screens/SearchConversation/SearchEmpty.tsx +30 -0
  114. package/src/screens/SearchConversation/SearchMessagesResult.tsx +74 -0
  115. package/src/screens/SearchConversation/SearchResultItem.tsx +107 -0
  116. package/src/screens/SearchConversation/TabResult.tsx +144 -0
  117. package/src/screens/SearchConversation/index.tsx +61 -0
  118. package/src/screens/SearchConversation/types.tsx +5 -0
  119. package/src/screens/chat-detail/ChatDetail.tsx +2 -1
  120. package/src/screens/chat-detail/types.ts +1 -0
  121. package/src/services/endpoints.ts +1 -0
  122. package/src/translation/resources/i18n.ts +7 -0
  123. package/src/types/chat.ts +15 -0
  124. package/src/utils/messageUtils.ts +13 -6
@@ -0,0 +1,74 @@
1
+ import { KContainer, KDivider, KSpacingValue } from '@droppii/libs';
2
+ import { memo, useCallback } from 'react';
3
+ import { useSearchMessage } from '../../hooks/message/useSearchMessage';
4
+ import { useChatContext } from '../../context';
5
+ import { FlatList, StyleSheet } from 'react-native';
6
+ import type { ISearchMessageItem } from '../../types/chat';
7
+ import SearchResultItem from './SearchResultItem';
8
+ import { SearchConversationTabResultType } from './types';
9
+ import { SearchEmpty } from './SearchEmpty';
10
+
11
+ interface ISearchMessagesResultProps {
12
+ searchTerm: string;
13
+ onPressItem?: (item: ISearchMessageItem) => void;
14
+ }
15
+ const SearchMessagesResult = memo(
16
+ ({ searchTerm, onPressItem }: ISearchMessagesResultProps) => {
17
+ const { applicationType } = useChatContext();
18
+ const { dataFlatten, hasNextPage, fetchNextPage, isFetchingNextPage } =
19
+ useSearchMessage({
20
+ query: searchTerm,
21
+ applicationType,
22
+ });
23
+
24
+ const renderItem = useCallback(
25
+ ({ item }: { item: ISearchMessageItem }) => {
26
+ return (
27
+ <SearchResultItem
28
+ item={item}
29
+ tabResultType={SearchConversationTabResultType.Messages}
30
+ onPressItem={onPressItem}
31
+ />
32
+ );
33
+ },
34
+ [onPressItem]
35
+ );
36
+
37
+ const keyExtractor = useCallback((item: ISearchMessageItem) => {
38
+ return `${item?.conversation?.conversationID}-${item?.chatLog?.clientMsgID}`;
39
+ }, []);
40
+
41
+ const onEndReached = useCallback(() => {
42
+ if (hasNextPage && !isFetchingNextPage) {
43
+ fetchNextPage();
44
+ }
45
+ }, [hasNextPage, isFetchingNextPage, fetchNextPage]);
46
+
47
+ const ItemSeparatorComponent = useCallback(() => {
48
+ return <KDivider size={'hairline'} vertical={false} />;
49
+ }, []);
50
+
51
+ return (
52
+ <KContainer.View flex>
53
+ <FlatList
54
+ data={dataFlatten}
55
+ renderItem={renderItem}
56
+ keyExtractor={keyExtractor}
57
+ contentContainerStyle={styles.container}
58
+ showsVerticalScrollIndicator={false}
59
+ onEndReached={onEndReached}
60
+ ItemSeparatorComponent={ItemSeparatorComponent}
61
+ ListEmptyComponent={<SearchEmpty />}
62
+ />
63
+ </KContainer.View>
64
+ );
65
+ }
66
+ );
67
+
68
+ export default SearchMessagesResult;
69
+
70
+ const styles = StyleSheet.create({
71
+ container: {
72
+ paddingHorizontal: KSpacingValue['0.75rem'],
73
+ },
74
+ });
@@ -0,0 +1,107 @@
1
+ import {
2
+ KColors,
3
+ KContainer,
4
+ KImage,
5
+ KLabel,
6
+ KSpacingValue,
7
+ } from '@droppii/libs';
8
+ import { memo, useCallback } from 'react';
9
+ import type { ISearchMessageItem } from '../../types/chat';
10
+ import { StyleSheet } from 'react-native';
11
+ import { SearchConversationTabResultType } from './types';
12
+ import { AvatarSection, NamePrefixIcon } from '../../components/ThreadCard';
13
+ import { getLastMessageText } from '../../utils/messageUtils';
14
+ import { useUserStore } from '../../store';
15
+ import { formatTimestamp } from '../../utils/dateTimeUtils';
16
+
17
+ interface ISearchResultItemProps {
18
+ item: ISearchMessageItem;
19
+ tabResultType: SearchConversationTabResultType;
20
+ onPressItem?: (item: ISearchMessageItem) => void;
21
+ }
22
+ const SearchResultItem = memo((props: ISearchResultItemProps) => {
23
+ const { item, tabResultType, onPressItem } = props || {};
24
+ const currentUserId = useUserStore((s) => s.user?.userID);
25
+
26
+ const timestamp = formatTimestamp(item?.chatLog?.sendTime ?? null);
27
+ const lastMessageText = getLastMessageText(
28
+ item?.chatLog,
29
+ currentUserId,
30
+ item?.conversation
31
+ );
32
+
33
+ const handlePressItem = useCallback(() => {
34
+ onPressItem?.({ conversation: item?.conversation, chatLog: item?.chatLog });
35
+ }, [onPressItem, item?.conversation, item?.chatLog]);
36
+
37
+ return (
38
+ <KContainer.Touchable style={styles.container} onPress={handlePressItem}>
39
+ <KContainer.View style={styles.leftContainer}>
40
+ <AvatarSection
41
+ avatar={item?.conversation?.faceURL ?? null}
42
+ fullName={item?.conversation?.showName}
43
+ peerType={item?.conversation?.peerType}
44
+ size="nm"
45
+ />
46
+ <KContainer.View style={styles.contentContainer}>
47
+ <KContainer.View style={styles.messageContainer}>
48
+ <NamePrefixIcon peerType={item?.conversation?.peerType} />
49
+ <KLabel.Text typo="TextMdMedium" numberOfLines={1} flex>
50
+ {item?.conversation?.showName}
51
+ </KLabel.Text>
52
+ <KLabel.Text typo="TextXsNormal" color={KColors.gray.light}>
53
+ {timestamp}
54
+ </KLabel.Text>
55
+ </KContainer.View>
56
+ <KLabel.Text typo="TextNmNormal" numberOfLines={1} flex>
57
+ {lastMessageText}
58
+ </KLabel.Text>
59
+ </KContainer.View>
60
+ </KContainer.View>
61
+ <KContainer.VisibleView
62
+ visible={
63
+ tabResultType === SearchConversationTabResultType.Conversations
64
+ }
65
+ >
66
+ <KContainer.View style={styles.rightContainer}>
67
+ <KImage.VectorIcons
68
+ name="more-horizontal-b"
69
+ size={24}
70
+ color={KColors.gray.normal}
71
+ />
72
+ </KContainer.View>
73
+ </KContainer.VisibleView>
74
+ </KContainer.Touchable>
75
+ );
76
+ });
77
+
78
+ export default SearchResultItem;
79
+
80
+ const styles = StyleSheet.create({
81
+ container: {
82
+ flexDirection: 'row',
83
+ justifyContent: 'space-between',
84
+ alignItems: 'center',
85
+ gap: KSpacingValue['1rem'],
86
+ paddingVertical: KSpacingValue['0.5rem'],
87
+ },
88
+ leftContainer: {
89
+ flexDirection: 'row',
90
+ alignItems: 'center',
91
+ gap: KSpacingValue['0.5rem'],
92
+ flex: 1,
93
+ },
94
+ rightContainer: {
95
+ alignItems: 'center',
96
+ justifyContent: 'center',
97
+ },
98
+ contentContainer: {
99
+ flex: 1,
100
+ },
101
+ messageContainer: {
102
+ flexDirection: 'row',
103
+ alignItems: 'center',
104
+ gap: KSpacingValue['0.25rem'],
105
+ justifyContent: 'space-between',
106
+ },
107
+ });
@@ -0,0 +1,144 @@
1
+ import {
2
+ KColors,
3
+ KContainer,
4
+ KLabel,
5
+ KRadiusValue,
6
+ KSpacingValue,
7
+ } from '@droppii/libs';
8
+ import { memo, useCallback, useState } from 'react';
9
+ import { StyleSheet } from 'react-native';
10
+ import { TabView } from 'react-native-tab-view';
11
+ import { SearchConversationTabResultType } from './types';
12
+ import { trans } from '../../translation';
13
+ import SearchMessagesResult from './SearchMessagesResult';
14
+ import SearchAllResult from './SearchAllResult';
15
+ import type { ISearchMessageItem } from '../../types/chat';
16
+
17
+ type TabRoute = { key: string; title: string };
18
+
19
+ interface ISearchConversationTabResultProps {
20
+ searchTerm: string;
21
+ onPressItem?: (item: ISearchMessageItem) => void;
22
+ }
23
+
24
+ const TabRoutes: TabRoute[] = [
25
+ { key: SearchConversationTabResultType.All, title: trans('all') },
26
+ // { key: SearchConversationTabResultType.Conversations, title: trans('contacts') },
27
+ { key: SearchConversationTabResultType.Messages, title: trans('messages') },
28
+ ];
29
+
30
+ interface CustomTabBarProps {
31
+ routes: TabRoute[];
32
+ index: number;
33
+ onPress: (i: number) => void;
34
+ }
35
+
36
+ const CustomTabBar = memo(({ routes, index, onPress }: CustomTabBarProps) => (
37
+ <KContainer.View style={styles.tabRow}>
38
+ {routes.map((route, i) => {
39
+ const isActive = i === index;
40
+ return (
41
+ <KContainer.Touchable
42
+ key={route.key}
43
+ onPress={() => onPress(i)}
44
+ style={styles.tabItem}
45
+ activeOpacity={0.7}
46
+ >
47
+ <KLabel.Text
48
+ typo="TextNmBold"
49
+ color={isActive ? KColors.primary.normal : KColors.gray.light}
50
+ >
51
+ {route.title}
52
+ </KLabel.Text>
53
+ {isActive && <KContainer.View style={styles.indicator} />}
54
+ </KContainer.Touchable>
55
+ );
56
+ })}
57
+ </KContainer.View>
58
+ ));
59
+
60
+ const SearchConversationTabResult = memo(
61
+ ({ searchTerm, onPressItem }: ISearchConversationTabResultProps) => {
62
+ const [index, setIndex] = useState(0);
63
+ const [routes] = useState<TabRoute[]>(TabRoutes);
64
+
65
+ const handleChangeTab = useCallback(
66
+ (key: SearchConversationTabResultType) => {
67
+ setIndex(TabRoutes.findIndex((route) => route.key === key));
68
+ },
69
+ []
70
+ );
71
+
72
+ const renderScene = useCallback(
73
+ ({ route }: { route: TabRoute }) => {
74
+ switch (route.key) {
75
+ case SearchConversationTabResultType.All:
76
+ return (
77
+ <SearchAllResult
78
+ searchTerm={searchTerm}
79
+ handleChangeTab={handleChangeTab}
80
+ onPressItem={onPressItem}
81
+ />
82
+ );
83
+ case SearchConversationTabResultType.Conversations:
84
+ return null;
85
+ case SearchConversationTabResultType.Messages:
86
+ return (
87
+ <SearchMessagesResult
88
+ searchTerm={searchTerm}
89
+ onPressItem={onPressItem}
90
+ />
91
+ );
92
+ default:
93
+ return null;
94
+ }
95
+ },
96
+ [searchTerm, handleChangeTab, onPressItem]
97
+ );
98
+
99
+ const renderTabBar = useCallback(
100
+ () => <CustomTabBar routes={routes} index={index} onPress={setIndex} />,
101
+ [routes, index]
102
+ );
103
+
104
+ return (
105
+ <KContainer.View flex>
106
+ <TabView
107
+ navigationState={{ index, routes }}
108
+ renderScene={renderScene}
109
+ renderTabBar={renderTabBar}
110
+ onIndexChange={setIndex}
111
+ swipeEnabled={routes.length > 1}
112
+ lazy
113
+ />
114
+ </KContainer.View>
115
+ );
116
+ }
117
+ );
118
+
119
+ export default SearchConversationTabResult;
120
+
121
+ const styles = StyleSheet.create({
122
+ tabRow: {
123
+ flexDirection: 'row',
124
+ borderBottomWidth: 1,
125
+ borderBottomColor: KColors.border.normal,
126
+ },
127
+ tabItem: {
128
+ paddingVertical: KSpacingValue['0.5rem'],
129
+ height: 40,
130
+ marginHorizontal: KSpacingValue['0.75rem'],
131
+ justifyContent: 'center',
132
+ alignItems: 'center',
133
+ },
134
+ indicator: {
135
+ height: 3,
136
+ backgroundColor: KColors.primary.normal,
137
+ width: '100%',
138
+ borderRadius: KRadiusValue.x,
139
+ position: 'absolute',
140
+ bottom: -1,
141
+ left: 0,
142
+ right: 0,
143
+ },
144
+ });
@@ -0,0 +1,61 @@
1
+ import { KColors, KContainer, KNavigation } from '@droppii/libs';
2
+ import { memo, useRef, useState } from 'react';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { trans } from '../../translation';
5
+ import debounce from 'lodash/debounce';
6
+ import type { TextInput } from 'react-native';
7
+ import SearchConversationTabResult from './TabResult';
8
+ import type { ISearchMessageItem } from '../../types/chat';
9
+
10
+ interface SearchConversationScreenProps {
11
+ onPressItem?: (item: ISearchMessageItem) => void;
12
+ }
13
+ const SearchConversationScreen = memo(
14
+ ({ onPressItem }: SearchConversationScreenProps) => {
15
+ const nav = useNavigation();
16
+ const [searchTerm, setSearchTerm] = useState('');
17
+ const searchInputRef = useRef<TextInput>(null);
18
+
19
+ const debouncedSearch = debounce(
20
+ (text: string) => {
21
+ setSearchTerm(text);
22
+ },
23
+ 500,
24
+ { leading: false, trailing: true }
25
+ );
26
+
27
+ return (
28
+ <KContainer.Page flex background={KColors.white} edges={['bottom']}>
29
+ <KNavigation.HeaderV2Body
30
+ theme="light"
31
+ size="large"
32
+ isNested
33
+ leftButton={{
34
+ id: 'back',
35
+ icon: { vectorName: 'arrow-left-o' },
36
+ onPress: nav.goBack,
37
+ }}
38
+ searchProps={{
39
+ position: 'center',
40
+ placeholder: trans('search'),
41
+ onChangeText: debouncedSearch,
42
+ ref: searchInputRef as any,
43
+ returnKeyType: 'search',
44
+ value: searchTerm,
45
+ autoFocus: true,
46
+ background: KColors.palette.gray.w25,
47
+ br: '2x',
48
+ searchIconLeftColor: KColors.gray.normal,
49
+ marginL: undefined,
50
+ }}
51
+ />
52
+ <SearchConversationTabResult
53
+ searchTerm={searchTerm}
54
+ onPressItem={onPressItem}
55
+ />
56
+ </KContainer.Page>
57
+ );
58
+ }
59
+ );
60
+
61
+ export default SearchConversationScreen;
@@ -0,0 +1,5 @@
1
+ export enum SearchConversationTabResultType {
2
+ All = 'all',
3
+ Conversations = 'conversations',
4
+ Messages = 'messages',
5
+ }
@@ -41,6 +41,7 @@ const ChatDetail = memo(
41
41
  targetUserId = '',
42
42
  targetGroupId = '',
43
43
  targetBotId = '',
44
+ targetMessageId = '',
44
45
  showAddMember,
45
46
  onBack,
46
47
  onPressSearch,
@@ -91,7 +92,7 @@ const ChatDetail = memo(
91
92
  getMoreNewMessages,
92
93
  hasMoreOld,
93
94
  hasMoreNew,
94
- } = useMessages({ conversationId });
95
+ } = useMessages({ conversationId, startClientMsgId: targetMessageId });
95
96
 
96
97
  const setShowFLashMessage = useSetIsShowFLashMessage();
97
98
 
@@ -94,6 +94,7 @@ export interface ChatDetailProps extends Omit<
94
94
  targetUserId?: string;
95
95
  targetGroupId?: string;
96
96
  targetBotId?: string;
97
+ targetMessageId?: string;
97
98
  enabled?: boolean;
98
99
  showAddMember?: boolean;
99
100
  onPressUrl?: (url: string) => void;
@@ -38,6 +38,7 @@ export const ENDPOINTS = {
38
38
  stickersByCategoryId: (id: string) =>
39
39
  `${getApiEndpoint('stickersByCategory')}/${id}/stickers`,
40
40
  stickerHistory: () => getApiEndpoint('stickerHistory'),
41
+ searchMessages: () => `${getApiEndpoint('messages')}/search`,
41
42
  },
42
43
  uploaderService: {
43
44
  get uploadImage() {
@@ -118,6 +118,13 @@ const i18nKey: Record<string, string> = {
118
118
  'Bạn đang trong phiên hỗ trợ với hỗ trợ viên, bạn có muốn <bold>kết thúc phiên hỗ trợ</bold> ngay bây giờ?',
119
119
  'chat:end_support_session_primary': 'Kết thúc',
120
120
  'chat:end_support_session_secondary': 'Tiếp tục',
121
+ 'search': 'Tìm kiếm',
122
+ 'all': 'Tất cả',
123
+ 'contacts': 'Liên hệ',
124
+ 'messages': 'Tin nhắn',
125
+ 'search:empty_description':
126
+ 'Không tìm thấy kết quả nào\nHãy thử lại với cách viết hoặc kết hợp cụm từ khác phù hợp hơn.',
127
+ 'view_all': 'Xem tất cả',
121
128
  };
122
129
 
123
130
  export default {
package/src/types/chat.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import {
2
+ MessageType,
2
3
  type ConversationItem,
3
4
  type MessageItem,
4
5
  } from '@droppii/openim-rn-client-sdk';
@@ -317,3 +318,17 @@ export interface DThreadResourceRawRow {
317
318
  tag: unknown;
318
319
  displayTag: unknown;
319
320
  }
321
+
322
+ export type ISearchMessagesRequest = {
323
+ conversationId?: string;
324
+ contentTypes: MessageType[];
325
+ page: number;
326
+ pageSize: number;
327
+ applicationType: DChatApplicationType;
328
+ searchTerm: string;
329
+ };
330
+
331
+ export interface ISearchMessageItem {
332
+ chatLog: MessageItem;
333
+ conversation: ConversationItem;
334
+ }
@@ -20,10 +20,14 @@ export const isMessageRevoked = (message: MessageItem): boolean =>
20
20
  export const extractTextContent = (message: MessageItem): string => {
21
21
  if (message.textElem?.content) return message.textElem.content;
22
22
  try {
23
- const parsed = JSON.parse(message.content) as { content?: string };
24
- return parsed.content ?? '';
23
+ const parsed = JSON.parse(message.content) as {
24
+ content?: string;
25
+ text?: string;
26
+ description?: string;
27
+ };
28
+ return parsed?.content || parsed?.text || parsed?.description || '';
25
29
  } catch {
26
- return message.content ?? '';
30
+ return message.content || '';
27
31
  }
28
32
  };
29
33
 
@@ -75,14 +79,17 @@ export const getMessagePreview = (message?: MessageItem): string => {
75
79
  case MessageType.UrlTextMessage:
76
80
  // Preview link message - show with [Link] prefix
77
81
  const urlText =
78
- message?.urlTextElem?.content || message?.urlTextElem?.urls?.[0] || '';
82
+ message?.urlTextElem?.content ||
83
+ message?.urlTextElem?.urls?.[0] ||
84
+ extractTextContent(message) ||
85
+ '';
79
86
  return urlText ? urlText : '';
80
87
 
81
88
  case MessageType.AtTextMessage:
82
89
  return extractTextContent(message);
83
90
 
84
91
  case MessageType.QuoteMessage:
85
- return message?.quoteElem?.text || '';
92
+ return message?.quoteElem?.text || extractTextContent(message) || '';
86
93
 
87
94
  case MessageType.RevokeMessage:
88
95
  return trans('msg_type_revoke');
@@ -91,7 +98,7 @@ export const getMessagePreview = (message?: MessageItem): string => {
91
98
  if (message?.customElem?.description) {
92
99
  return message?.customElem?.description;
93
100
  }
94
- return '';
101
+ return extractTextContent(message) || '';
95
102
 
96
103
  case MessageType.StickerMessage:
97
104
  return '[Sticker]';