@droppii-org/chat-mobile 0.2.53 → 0.2.55

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 (70) hide show
  1. package/lib/module/components/Avatar/Avatar.utils.js +4 -2
  2. package/lib/module/components/Avatar/Avatar.utils.js.map +1 -1
  3. package/lib/module/components/Avatar/SingleAvatar.js +2 -0
  4. package/lib/module/components/Avatar/SingleAvatar.js.map +1 -1
  5. package/lib/module/components/ThreadCard/MuteThread.js +4 -61
  6. package/lib/module/components/ThreadCard/MuteThread.js.map +1 -1
  7. package/lib/module/hooks/useMuteConversation.js +66 -1
  8. package/lib/module/hooks/useMuteConversation.js.map +1 -1
  9. package/lib/module/index.js +1 -0
  10. package/lib/module/index.js.map +1 -1
  11. package/lib/module/screens/ChatInfo/ChatInfo.js +63 -0
  12. package/lib/module/screens/ChatInfo/ChatInfo.js.map +1 -0
  13. package/lib/module/screens/ChatInfo/ChatInfoActions.js +141 -0
  14. package/lib/module/screens/ChatInfo/ChatInfoActions.js.map +1 -0
  15. package/lib/module/screens/ChatInfo/ChatInfoMediaRow.js +58 -0
  16. package/lib/module/screens/ChatInfo/ChatInfoMediaRow.js.map +1 -0
  17. package/lib/module/screens/ChatInfo/ChatInfoProfile.js +129 -0
  18. package/lib/module/screens/ChatInfo/ChatInfoProfile.js.map +1 -0
  19. package/lib/module/screens/ChatInfo/index.js +4 -0
  20. package/lib/module/screens/ChatInfo/index.js.map +1 -0
  21. package/lib/module/screens/ChatInfo/types.js +4 -0
  22. package/lib/module/screens/ChatInfo/types.js.map +1 -0
  23. package/lib/module/screens/chat-detail/ChatDetail.js +5 -3
  24. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  25. package/lib/module/translation/resources/i18n.js +12 -0
  26. package/lib/module/translation/resources/i18n.js.map +1 -1
  27. package/lib/typescript/src/components/Avatar/Avatar.types.d.ts +1 -1
  28. package/lib/typescript/src/components/Avatar/Avatar.types.d.ts.map +1 -1
  29. package/lib/typescript/src/components/Avatar/Avatar.utils.d.ts +2 -0
  30. package/lib/typescript/src/components/Avatar/Avatar.utils.d.ts.map +1 -1
  31. package/lib/typescript/src/components/Avatar/SingleAvatar.d.ts.map +1 -1
  32. package/lib/typescript/src/components/ThreadCard/MuteThread.d.ts.map +1 -1
  33. package/lib/typescript/src/hooks/useMuteConversation.d.ts.map +1 -1
  34. package/lib/typescript/src/index.d.ts +2 -0
  35. package/lib/typescript/src/index.d.ts.map +1 -1
  36. package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts +4 -0
  37. package/lib/typescript/src/screens/ChatInfo/ChatInfo.d.ts.map +1 -0
  38. package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts +11 -0
  39. package/lib/typescript/src/screens/ChatInfo/ChatInfoActions.d.ts.map +1 -0
  40. package/lib/typescript/src/screens/ChatInfo/ChatInfoMediaRow.d.ts +7 -0
  41. package/lib/typescript/src/screens/ChatInfo/ChatInfoMediaRow.d.ts.map +1 -0
  42. package/lib/typescript/src/screens/ChatInfo/ChatInfoProfile.d.ts +8 -0
  43. package/lib/typescript/src/screens/ChatInfo/ChatInfoProfile.d.ts.map +1 -0
  44. package/lib/typescript/src/screens/ChatInfo/index.d.ts +3 -0
  45. package/lib/typescript/src/screens/ChatInfo/index.d.ts.map +1 -0
  46. package/lib/typescript/src/screens/ChatInfo/types.d.ts +11 -0
  47. package/lib/typescript/src/screens/ChatInfo/types.d.ts.map +1 -0
  48. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts +1 -1
  49. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  50. package/lib/typescript/src/screens/chat-detail/types.d.ts +1 -1
  51. package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
  52. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  53. package/package.json +1 -1
  54. package/src/build-ignore.d.ts +1 -0
  55. package/src/components/Avatar/Avatar.types.ts +1 -1
  56. package/src/components/Avatar/Avatar.utils.ts +2 -0
  57. package/src/components/Avatar/SingleAvatar.tsx +2 -0
  58. package/src/components/ThreadCard/MuteThread.tsx +4 -61
  59. package/src/hooks/useMuteConversation.tsx +124 -0
  60. package/src/index.tsx +2 -0
  61. package/src/screens/ChatInfo/ChatInfo.tsx +61 -0
  62. package/src/screens/ChatInfo/ChatInfoActions.tsx +168 -0
  63. package/src/screens/ChatInfo/ChatInfoMediaRow.tsx +73 -0
  64. package/src/screens/ChatInfo/ChatInfoProfile.tsx +145 -0
  65. package/src/screens/ChatInfo/index.ts +2 -0
  66. package/src/screens/ChatInfo/types.ts +11 -0
  67. package/src/screens/chat-detail/ChatDetail.tsx +6 -3
  68. package/src/screens/chat-detail/types.ts +1 -1
  69. package/src/translation/resources/i18n.ts +12 -0
  70. package/src/hooks/useMuteConversation.ts +0 -59
@@ -0,0 +1,124 @@
1
+ import { useCallback } from 'react';
2
+ import OpenIMSDK, {
3
+ MessageReceiveOptType,
4
+ } from '@droppii/openim-rn-client-sdk';
5
+ import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
6
+ import { UIUtils } from '../utils/UIUtils';
7
+ import { trans } from '../translation';
8
+ import { KContainer, KLabel } from '@droppii/libs';
9
+ import { Image, StyleSheet } from 'react-native';
10
+ import Images from '../assets/images';
11
+
12
+ export function useMuteConversation() {
13
+ const openMutePopup = useCallback(() => {
14
+ return new Promise((resolve, reject) => {
15
+ UIUtils.popup.open({
16
+ header: {
17
+ title: { text: trans('chat:mute_confirm_title') },
18
+ alignment: 'center',
19
+ },
20
+ body: {
21
+ renderContent: () => {
22
+ return (
23
+ <KContainer.View padding={'1rem'} justifyContent alignItems>
24
+ <KContainer.View paddingV={'1rem'}>
25
+ <Image
26
+ source={Images.NOTIFICATION_WARNING}
27
+ style={styles.notificationWarning}
28
+ />
29
+ </KContainer.View>
30
+ <KLabel.RichText
31
+ typo="TextMdNormal"
32
+ richTextOptions={{
33
+ i18nKey: trans('chat:mute_confirm_desc'),
34
+ components: {
35
+ b: <KLabel.Text typo="TextMdBold" />,
36
+ },
37
+ }}
38
+ />
39
+ </KContainer.View>
40
+ );
41
+ },
42
+ },
43
+ actions: {
44
+ buttons: [
45
+ {
46
+ label: trans('chat:mute_confirm_secondary'),
47
+ kind: 'light',
48
+ onPress: reject,
49
+ },
50
+ {
51
+ label: trans('chat:mute_confirm_primary'),
52
+ kind: 'primary',
53
+ onPress: resolve,
54
+ },
55
+ ],
56
+ type: 'horizontal-button',
57
+ },
58
+ });
59
+ });
60
+ }, []);
61
+
62
+ const muteConversation = useCallback(
63
+ async (conversation?: ConversationItem) => {
64
+ if (conversation == null) return;
65
+
66
+ try {
67
+ await openMutePopup();
68
+ } catch {
69
+ return;
70
+ }
71
+
72
+ try {
73
+ await OpenIMSDK.setConversationRecvMessageOpt({
74
+ conversationID: conversation.conversationID,
75
+ opt: MessageReceiveOptType.NotNotify,
76
+ });
77
+ UIUtils.toast.open({
78
+ title: trans('chat:mute_toast_success'),
79
+ theme: 'light',
80
+ });
81
+ } catch (error) {
82
+ console.error('muteConversation failed', error);
83
+ UIUtils.toast.open({
84
+ title: trans('chat:generic_error'),
85
+ theme: 'error',
86
+ });
87
+ }
88
+ },
89
+ [openMutePopup]
90
+ );
91
+
92
+ const unmuteConversation = useCallback(
93
+ async (conversation?: ConversationItem) => {
94
+ if (conversation == null) return;
95
+
96
+ try {
97
+ await OpenIMSDK.setConversationRecvMessageOpt({
98
+ conversationID: conversation.conversationID,
99
+ opt: MessageReceiveOptType.Normal,
100
+ });
101
+ UIUtils.toast.open({
102
+ title: trans('chat:unmute_toast_success'),
103
+ theme: 'light',
104
+ });
105
+ } catch (error) {
106
+ console.error('unmuteConversation failed', error);
107
+ UIUtils.toast.open({
108
+ title: trans('chat:generic_error'),
109
+ theme: 'error',
110
+ });
111
+ }
112
+ },
113
+ []
114
+ );
115
+
116
+ return { muteConversation, unmuteConversation };
117
+ }
118
+
119
+ const styles = StyleSheet.create({
120
+ notificationWarning: {
121
+ width: 120,
122
+ height: 144,
123
+ },
124
+ });
package/src/index.tsx CHANGED
@@ -31,6 +31,7 @@ export { default as MediaViewerScreen } from './screens/MediaView';
31
31
  export { default as ResourceCenterScreen } from './screens/ResourceCenter';
32
32
  export type { ResourceCenterScreenProps } from './screens/ResourceCenter/types';
33
33
  export * from './screens/chat-detail';
34
+ export * from './screens/ChatInfo';
34
35
 
35
36
  export type {
36
37
  PeerType,
@@ -52,6 +53,7 @@ export type {
52
53
  ChatQuickActionsRenderParams,
53
54
  ChatPanelProps,
54
55
  } from './screens/chat-detail';
56
+ export type * from './screens/ChatInfo';
55
57
 
56
58
  export { registerUIUtils, UIUtils } from './utils/UIUtils';
57
59
 
@@ -0,0 +1,61 @@
1
+ import { memo } from 'react';
2
+ import { KContainer, KNavigation } from '@droppii/libs';
3
+ import { useNavigation } from '@react-navigation/native';
4
+ import { useGetConversationTarget } from '../../hooks/conversation/useGetConversationDetail';
5
+ import { useConversation } from '../../store';
6
+ import ChatInfoProfile from './ChatInfoProfile';
7
+ import ChatInfoMediaRow from './ChatInfoMediaRow';
8
+ import ChatInfoActions from './ChatInfoActions';
9
+ import type { ChatInfoProps } from './types';
10
+ import { trans } from '../../translation';
11
+
12
+ const ChatInfo = memo(
13
+ ({
14
+ conversationId = '',
15
+ onBack,
16
+ onPressSearch,
17
+ onPressMedia,
18
+ onPressOrders,
19
+ onPressCreateGroup,
20
+ onPressAddToGroup,
21
+ }: ChatInfoProps) => {
22
+ const navigation = useNavigation();
23
+
24
+ const conversation = useConversation(conversationId);
25
+ const { data: target } = useGetConversationTarget(conversationId);
26
+ const isTargetActive = target ? target.isActive : true;
27
+
28
+ return (
29
+ <KContainer.Page flex edges={['bottom']} background="#EBEDF2">
30
+ <KNavigation.Header
31
+ theme="light"
32
+ alignment="left"
33
+ size="small"
34
+ leftButton={{
35
+ id: 'ChatInfoBackButton',
36
+ icon: { vectorName: 'arrow-left-o' },
37
+ onPress: onBack ?? navigation.goBack,
38
+ }}
39
+ title={trans('chat:info_title')}
40
+ shadow={false}
41
+ />
42
+ <KContainer.ScrollView showsVerticalScrollIndicator={false}>
43
+ <ChatInfoProfile
44
+ conversation={conversation}
45
+ onPressSearch={onPressSearch}
46
+ />
47
+ <ChatInfoMediaRow onPressMedia={onPressMedia} />
48
+ <ChatInfoActions
49
+ conversation={conversation}
50
+ isTargetActive={isTargetActive}
51
+ onPressOrders={onPressOrders}
52
+ onPressCreateGroup={onPressCreateGroup}
53
+ onPressAddToGroup={onPressAddToGroup}
54
+ />
55
+ </KContainer.ScrollView>
56
+ </KContainer.Page>
57
+ );
58
+ }
59
+ );
60
+
61
+ export default ChatInfo;
@@ -0,0 +1,168 @@
1
+ import { memo, useCallback, useMemo } from 'react';
2
+ import {
3
+ KContainer,
4
+ KListItem,
5
+ KColors,
6
+ type KListItemBaseItemProps,
7
+ KLabel,
8
+ } from '@droppii/libs';
9
+ import type { ConversationItem } from '@droppii/openim-rn-client-sdk';
10
+ import { usePinConversation } from '../../hooks/usePinConversation';
11
+ import { trans } from '../../translation';
12
+
13
+ interface ChatInfoActionsProps {
14
+ conversation?: ConversationItem;
15
+ isTargetActive: boolean;
16
+ onPressOrders?: () => void;
17
+ onPressCreateGroup?: () => void;
18
+ onPressAddToGroup?: () => void;
19
+ }
20
+
21
+ const ChatInfoActions = memo(
22
+ ({
23
+ conversation,
24
+ isTargetActive,
25
+ onPressOrders,
26
+ onPressCreateGroup,
27
+ onPressAddToGroup,
28
+ }: ChatInfoActionsProps) => {
29
+ const { pinConversation, unpinConversation } = usePinConversation();
30
+ const isPinned = Boolean(conversation?.isPinned);
31
+ const showName = conversation?.showName || '';
32
+
33
+ const handlePinPress = useCallback(() => {
34
+ if (isPinned) {
35
+ unpinConversation(conversation);
36
+ } else {
37
+ pinConversation(conversation);
38
+ }
39
+ }, [isPinned, conversation, pinConversation, unpinConversation]);
40
+
41
+ const handleDeleteHistory = useCallback(() => {}, []);
42
+
43
+ const primaryData = useMemo(() => {
44
+ const items: KListItemBaseItemProps[] = [
45
+ {
46
+ leftNode: { icon: { vectorName: 'receipt-o' } },
47
+ onPress: onPressOrders,
48
+ paddingH: '0.75rem',
49
+ paddingV: '0.75rem',
50
+ customLabel: (
51
+ <KLabel.Text typo="TextMdMedium" numberOfLines={1}>
52
+ {trans('chat:info_orders', { name: showName })}
53
+ </KLabel.Text>
54
+ ),
55
+ },
56
+ ];
57
+
58
+ if (isTargetActive) {
59
+ items.push(
60
+ {
61
+ leftNode: { icon: { vectorName: 'user-two-o' } },
62
+ onPress: onPressCreateGroup,
63
+ paddingH: '0.75rem',
64
+ paddingV: '0.75rem',
65
+ customLabel: (
66
+ <KLabel.Text typo="TextMdMedium" numberOfLines={1}>
67
+ {trans('chat:info_create_group', { name: showName })}
68
+ </KLabel.Text>
69
+ ),
70
+ },
71
+ {
72
+ leftNode: { icon: { vectorName: 'user-add-o' } },
73
+ onPress: onPressAddToGroup,
74
+ paddingH: '0.75rem',
75
+ paddingV: '0.75rem',
76
+ customLabel: (
77
+ <KLabel.Text typo="TextMdMedium" numberOfLines={1}>
78
+ {trans('chat:info_add_to_group')}
79
+ </KLabel.Text>
80
+ ),
81
+ }
82
+ );
83
+ }
84
+
85
+ items.push({
86
+ leftNode: {
87
+ icon: { vectorName: isPinned ? 'thumbtack-off-o' : 'thumbtack-o' },
88
+ },
89
+ onPress: handlePinPress,
90
+ showChevron: false,
91
+ paddingH: '0.75rem',
92
+ paddingV: '0.75rem',
93
+ customLabel: (
94
+ <KLabel.Text typo="TextMdMedium" numberOfLines={1}>
95
+ {isPinned
96
+ ? trans('chat:info_unpin_message')
97
+ : trans('chat:info_pin_message')}
98
+ </KLabel.Text>
99
+ ),
100
+ });
101
+
102
+ return items;
103
+ }, [
104
+ showName,
105
+ isTargetActive,
106
+ isPinned,
107
+ onPressOrders,
108
+ onPressCreateGroup,
109
+ onPressAddToGroup,
110
+ handlePinPress,
111
+ ]);
112
+
113
+ const deleteData: KListItemBaseItemProps[] = useMemo(
114
+ () => [
115
+ {
116
+ label: trans('chat:info_delete_history'),
117
+ leftNode: {
118
+ icon: {
119
+ vectorName: 'trash-alt-o',
120
+ tintColor: KColors.danger.normal,
121
+ },
122
+ },
123
+ tintColor: KColors.danger.normal,
124
+ onPress: handleDeleteHistory,
125
+ showChevron: false,
126
+ paddingH: '0.75rem',
127
+ paddingV: '0.75rem',
128
+ customLabel: (
129
+ <KLabel.Text
130
+ typo="TextMdMedium"
131
+ color={KColors.danger.normal}
132
+ numberOfLines={1}
133
+ >
134
+ {trans('chat:info_delete_history')}
135
+ </KLabel.Text>
136
+ ),
137
+ },
138
+ ],
139
+ [handleDeleteHistory]
140
+ );
141
+
142
+ return (
143
+ <>
144
+ <KContainer.View
145
+ background={KColors.white}
146
+ br={'3x'}
147
+ marginH="0.75rem"
148
+ marginT="0.75rem"
149
+ hiddenOverflow
150
+ >
151
+ <KListItem.Base data={primaryData} />
152
+ </KContainer.View>
153
+
154
+ <KContainer.View
155
+ background={KColors.white}
156
+ br={'3x'}
157
+ marginH="0.75rem"
158
+ marginT="0.75rem"
159
+ hiddenOverflow
160
+ >
161
+ <KListItem.Base data={deleteData} />
162
+ </KContainer.View>
163
+ </>
164
+ );
165
+ }
166
+ );
167
+
168
+ export default ChatInfoActions;
@@ -0,0 +1,73 @@
1
+ import { memo } from 'react';
2
+ import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
3
+ import { trans } from '../../translation';
4
+ import { DThreadResourceContentType } from '../../types/chat';
5
+
6
+ const MEDIA_TABS: Array<{
7
+ tab: DThreadResourceContentType;
8
+ iconName: string;
9
+ labelKey: string;
10
+ }> = [
11
+ {
12
+ tab: DThreadResourceContentType.IMAGE,
13
+ iconName: 'image-o',
14
+ labelKey: 'chat:info_media_photo',
15
+ },
16
+ {
17
+ tab: DThreadResourceContentType.VIDEO,
18
+ iconName: 'video-o',
19
+ labelKey: 'chat:info_media_video',
20
+ },
21
+ {
22
+ tab: DThreadResourceContentType.FILE,
23
+ iconName: 'paperclip-o',
24
+ labelKey: 'chat:info_media_file',
25
+ },
26
+ {
27
+ tab: DThreadResourceContentType.URL_TEXT,
28
+ iconName: 'link-alt-o',
29
+ labelKey: 'chat:info_media_link',
30
+ },
31
+ ];
32
+
33
+ interface ChatInfoMediaRowProps {
34
+ onPressMedia?: (tab: DThreadResourceContentType) => void;
35
+ }
36
+
37
+ const ChatInfoMediaRow = memo(({ onPressMedia }: ChatInfoMediaRowProps) => {
38
+ return (
39
+ <KContainer.View
40
+ row
41
+ background={KColors.white}
42
+ br={'3x'}
43
+ marginH="0.75rem"
44
+ marginT="0.75rem"
45
+ >
46
+ {MEDIA_TABS.map(({ tab, iconName, labelKey }) => (
47
+ <KContainer.Touchable
48
+ key={tab}
49
+ flex
50
+ alignItems
51
+ justifyContent
52
+ paddingV="0.75rem"
53
+ onPress={() => onPressMedia?.(tab)}
54
+ >
55
+ <KImage.VectorIcons
56
+ name={iconName}
57
+ size={24}
58
+ color={KColors.gray.dark}
59
+ />
60
+ <KLabel.Text
61
+ typo="TextXsNormal"
62
+ color={KColors.gray.dark}
63
+ marginT="0.25rem"
64
+ >
65
+ {trans(labelKey)}
66
+ </KLabel.Text>
67
+ </KContainer.Touchable>
68
+ ))}
69
+ </KContainer.View>
70
+ );
71
+ });
72
+
73
+ export default ChatInfoMediaRow;
@@ -0,0 +1,145 @@
1
+ import { memo, useCallback, useMemo } from 'react';
2
+ import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
3
+ import {
4
+ MessageReceiveOptType,
5
+ PeerType,
6
+ type ConversationItem,
7
+ } from '@droppii/openim-rn-client-sdk';
8
+ import { Avatar } from '../../components/Avatar';
9
+ import { useMuteConversation } from '../../hooks/useMuteConversation';
10
+ import { trans } from '../../translation';
11
+ import { StyleSheet } from 'react-native';
12
+ import { NamePrefixIcon } from '../../components/ThreadCard';
13
+
14
+ interface QuickActionProps {
15
+ iconName: string;
16
+ label: string;
17
+ background: string;
18
+ iconColor: string;
19
+ onPress?: () => void;
20
+ }
21
+
22
+ const QuickAction = memo(
23
+ ({ iconName, label, background, iconColor, onPress }: QuickActionProps) => (
24
+ <KContainer.View alignItems paddingH="0.75rem" paddingV="0.5rem">
25
+ <KContainer.Touchable
26
+ height={40}
27
+ width={40}
28
+ br={'round'}
29
+ background={background}
30
+ center
31
+ onPress={onPress}
32
+ >
33
+ <KImage.VectorIcons name={iconName} size={18} color={iconColor} />
34
+ </KContainer.Touchable>
35
+ <KLabel.Text
36
+ typo="TextSmMedium"
37
+ color={KColors.gray.dark}
38
+ marginT="0.25rem"
39
+ textAlign="center"
40
+ >
41
+ {label}
42
+ </KLabel.Text>
43
+ </KContainer.View>
44
+ )
45
+ );
46
+
47
+ interface ChatInfoProfileProps {
48
+ conversation?: ConversationItem;
49
+ onPressSearch?: () => void;
50
+ }
51
+
52
+ const ChatInfoProfile = memo(
53
+ ({ conversation, onPressSearch }: ChatInfoProfileProps) => {
54
+ const { faceURL, showName = '' } = conversation ?? {};
55
+
56
+ const isMuted =
57
+ conversation != null &&
58
+ conversation.recvMsgOpt !== MessageReceiveOptType.Normal;
59
+
60
+ const { muteConversation, unmuteConversation } = useMuteConversation();
61
+
62
+ const handleNotificationPress = useCallback(() => {
63
+ if (isMuted) {
64
+ unmuteConversation(conversation);
65
+ } else {
66
+ muteConversation(conversation);
67
+ }
68
+ }, [isMuted, conversation, muteConversation, unmuteConversation]);
69
+
70
+ const badge = useMemo(() => {
71
+ switch (conversation?.peerType) {
72
+ case PeerType.Bot:
73
+ return { variant: 'bot' } as const;
74
+
75
+ case PeerType.Customer:
76
+ return { variant: 'mall' } as const;
77
+ default:
78
+ return;
79
+ }
80
+ }, [conversation?.peerType]);
81
+
82
+ return (
83
+ <KContainer.View
84
+ background={KColors.white}
85
+ brBL={'4x'}
86
+ brBR={'4x'}
87
+ paddingV="0.5rem"
88
+ >
89
+ <KContainer.View alignItems>
90
+ <Avatar
91
+ source={faceURL}
92
+ size="4xlg"
93
+ fullName={showName}
94
+ badge={badge}
95
+ />
96
+ <KContainer.View row alignItems marginT="0.5rem">
97
+ <NamePrefixIcon peerType={conversation?.peerType} />
98
+ <KLabel.Text
99
+ typo="TextLgBold"
100
+ color={KColors.black}
101
+ numberOfLines={1}
102
+ >
103
+ {showName}
104
+ </KLabel.Text>
105
+ </KContainer.View>
106
+ </KContainer.View>
107
+
108
+ <KContainer.View
109
+ row
110
+ justifyContent="center"
111
+ alignItems
112
+ style={styles.quickActionContainer}
113
+ marginT="0.5rem"
114
+ >
115
+ <QuickAction
116
+ iconName="search-o"
117
+ label={trans('chat:info_search_action')}
118
+ onPress={onPressSearch}
119
+ background={KColors.palette.gray.w25}
120
+ iconColor={KColors.gray.dark}
121
+ />
122
+ <QuickAction
123
+ iconName={isMuted ? 'bell-b' : 'bell-off-o'}
124
+ label={
125
+ isMuted ? trans('chat:unmute_action') : trans('chat:mute_action')
126
+ }
127
+ background={
128
+ isMuted ? KColors.primary.normal : KColors.palette.gray.w25
129
+ }
130
+ iconColor={isMuted ? KColors.white : KColors.gray.dark}
131
+ onPress={handleNotificationPress}
132
+ />
133
+ </KContainer.View>
134
+ </KContainer.View>
135
+ );
136
+ }
137
+ );
138
+
139
+ export default ChatInfoProfile;
140
+
141
+ const styles = StyleSheet.create({
142
+ quickActionContainer: {
143
+ gap: 8,
144
+ },
145
+ });
@@ -0,0 +1,2 @@
1
+ export { default as ChatInfo } from './ChatInfo';
2
+ export type * from './types';
@@ -0,0 +1,11 @@
1
+ import type { DThreadResourceContentType } from '../../types/chat';
2
+
3
+ export interface ChatInfoProps {
4
+ conversationId?: string;
5
+ onBack?: () => void;
6
+ onPressSearch?: () => void;
7
+ onPressMedia?: (tab: DThreadResourceContentType) => void;
8
+ onPressOrders?: () => void;
9
+ onPressCreateGroup?: () => void;
10
+ onPressAddToGroup?: () => void;
11
+ }
@@ -46,7 +46,6 @@ const ChatDetail = memo(
46
46
  onPressSearch,
47
47
  onPressAddMember,
48
48
  onPressMenu,
49
- onPressAvatar,
50
49
  onPressUrl,
51
50
  customMessageItemFactory,
52
51
  pannelActions,
@@ -149,6 +148,10 @@ const ChatDetail = memo(
149
148
  });
150
149
  }, [currentUser, unpinMessage, customMessageItemFactory]);
151
150
 
151
+ const handlePressMenu = useCallback(() => {
152
+ onPressMenu?.(conversationId);
153
+ }, [conversationId, onPressMenu]);
154
+
152
155
  return (
153
156
  <KContainer.Page flex edges={['bottom']}>
154
157
  <ChatDetailHeader
@@ -158,8 +161,8 @@ const ChatDetail = memo(
158
161
  onBack={onBack ?? handleBackDefault}
159
162
  onPressSearch={onPressSearch}
160
163
  onPressAddMember={onPressAddMember}
161
- onPressMenu={onPressMenu}
162
- onPressAvatar={onPressAvatar}
164
+ onPressMenu={handlePressMenu}
165
+ onPressAvatar={handlePressMenu}
163
166
  />
164
167
 
165
168
  <PinnedMessageBar
@@ -42,7 +42,7 @@ export interface ChatDetailHeaderProps {
42
42
  onBack?: () => void;
43
43
  onPressSearch?: () => void;
44
44
  onPressAddMember?: () => void;
45
- onPressMenu?: () => void;
45
+ onPressMenu?: (conversationId?: string) => void;
46
46
  onPressAvatar?: () => void;
47
47
  conversationId: string;
48
48
  targetUserId?: string;
@@ -80,6 +80,18 @@ const i18nKey: Record<string, string> = {
80
80
  'chat:mute_confirm_secondary': 'Quay lại',
81
81
  'chat:mute_toast_success': 'Đã tắt thông báo',
82
82
  'chat:unmute_toast_success': 'Đã bật thông báo',
83
+ 'chat:info_title': 'Tuỳ chọn',
84
+ 'chat:info_search_action': 'Tìm tin nhắn',
85
+ 'chat:info_media_photo': 'Ảnh',
86
+ 'chat:info_media_video': 'Video',
87
+ 'chat:info_media_file': 'Tập tin',
88
+ 'chat:info_media_link': 'Liên kết',
89
+ 'chat:info_orders': 'Đơn hàng đã tạo cho {{name}}',
90
+ 'chat:info_create_group': 'Tạo nhóm trò chuyện với {{name}}',
91
+ 'chat:info_add_to_group': 'Thêm vào nhóm',
92
+ 'chat:info_pin_message': 'Ghim trò chuyện',
93
+ 'chat:info_unpin_message': 'Bỏ ghim trò chuyện',
94
+ 'chat:info_delete_history': 'Xoá lịch sử trò chuyện',
83
95
  'start': 'Bắt đầu',
84
96
  'restart': 'Bắt đầu lại',
85
97
  'gallery': 'Ảnh/Video',