@droppii-org/chat-mobile 0.2.35 → 0.2.38

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 (160) hide show
  1. package/lib/module/components/messages/linkMessage/index.js +1 -10
  2. package/lib/module/components/messages/linkMessage/index.js.map +1 -1
  3. package/lib/module/components/messages/quotedMessage/index.js +173 -0
  4. package/lib/module/components/messages/quotedMessage/index.js.map +1 -0
  5. package/lib/module/context/ChatContext.js +26 -22
  6. package/lib/module/context/ChatContext.js.map +1 -1
  7. package/lib/module/context/ChatDetailContext.js +7 -4
  8. package/lib/module/context/ChatDetailContext.js.map +1 -1
  9. package/lib/module/core/useChatListener.js +0 -1
  10. package/lib/module/core/useChatListener.js.map +1 -1
  11. package/lib/module/core/useUserListener.js +12 -21
  12. package/lib/module/core/useUserListener.js.map +1 -1
  13. package/lib/module/hooks/message/useSendMessage.js +26 -4
  14. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  15. package/lib/module/hooks/useChatMessages.js.map +1 -1
  16. package/lib/module/hooks/useFileAttachment.js +3 -1
  17. package/lib/module/hooks/useFileAttachment.js.map +1 -1
  18. package/lib/module/index.js +0 -7
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/screens/chat-detail/ChatComposer.js +2 -1
  21. package/lib/module/screens/chat-detail/ChatComposer.js.map +1 -1
  22. package/lib/module/screens/chat-detail/ChatCurrentQuotedMessage.js +142 -0
  23. package/lib/module/screens/chat-detail/ChatCurrentQuotedMessage.js.map +1 -0
  24. package/lib/module/screens/chat-detail/ChatDetail.js +10 -1
  25. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  26. package/lib/module/screens/chat-detail/ChatListLegend.js.map +1 -1
  27. package/lib/module/screens/chat-detail/PinnedMessageBar.js +8 -3
  28. package/lib/module/screens/chat-detail/PinnedMessageBar.js.map +1 -1
  29. package/lib/module/screens/chat-detail/PinnedMessagesSheet.js +173 -0
  30. package/lib/module/screens/chat-detail/PinnedMessagesSheet.js.map +1 -0
  31. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +2 -1
  32. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
  33. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxMenu.js +17 -1
  34. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxMenu.js.map +1 -1
  35. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js +11 -1
  36. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js.map +1 -1
  37. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxWrapper.js +1 -0
  38. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxWrapper.js.map +1 -1
  39. package/lib/module/screens/chat-detail/messageToolbox/messageToolbox.utils.js +5 -2
  40. package/lib/module/screens/chat-detail/messageToolbox/messageToolbox.utils.js.map +1 -1
  41. package/lib/module/screens/inbox/Inbox.js +1 -5
  42. package/lib/module/screens/inbox/Inbox.js.map +1 -1
  43. package/lib/module/services/apis.js +0 -3
  44. package/lib/module/services/apis.js.map +1 -1
  45. package/lib/module/services/message.js.map +1 -1
  46. package/lib/module/store/message.js.map +1 -1
  47. package/lib/module/store/pinnedMessage.js.map +1 -1
  48. package/lib/module/store/user.js +2 -3
  49. package/lib/module/store/user.js.map +1 -1
  50. package/lib/module/translation/resources/i18n.js +9 -2
  51. package/lib/module/translation/resources/i18n.js.map +1 -1
  52. package/lib/module/types/auth.js +0 -7
  53. package/lib/module/types/auth.js.map +1 -1
  54. package/lib/module/types/chat.js +12 -0
  55. package/lib/module/types/chat.js.map +1 -1
  56. package/lib/module/utils/UIUtils.js +6 -0
  57. package/lib/module/utils/UIUtils.js.map +1 -1
  58. package/lib/module/utils/legendListMessage.js +1 -0
  59. package/lib/module/utils/legendListMessage.js.map +1 -1
  60. package/lib/module/utils/message.js.map +1 -1
  61. package/lib/module/utils/messageUtils.js +18 -1
  62. package/lib/module/utils/messageUtils.js.map +1 -1
  63. package/lib/typescript/src/components/messages/linkMessage/index.d.ts.map +1 -1
  64. package/lib/typescript/src/components/messages/quotedMessage/index.d.ts +7 -0
  65. package/lib/typescript/src/components/messages/quotedMessage/index.d.ts.map +1 -0
  66. package/lib/typescript/src/components/messages/types.d.ts +2 -2
  67. package/lib/typescript/src/components/messages/types.d.ts.map +1 -1
  68. package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
  69. package/lib/typescript/src/context/ChatDetailContext.d.ts.map +1 -1
  70. package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
  71. package/lib/typescript/src/core/useUserListener.d.ts.map +1 -1
  72. package/lib/typescript/src/hooks/message/usePinMessage.d.ts +1 -1
  73. package/lib/typescript/src/hooks/message/useSendMessage.d.ts +2 -1
  74. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  75. package/lib/typescript/src/hooks/useChatMessages.d.ts +2 -2
  76. package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
  77. package/lib/typescript/src/hooks/useFileAttachment.d.ts.map +1 -1
  78. package/lib/typescript/src/index.d.ts +1 -1
  79. package/lib/typescript/src/index.d.ts.map +1 -1
  80. package/lib/typescript/src/screens/chat-detail/ChatComposer.d.ts.map +1 -1
  81. package/lib/typescript/src/screens/chat-detail/ChatCurrentQuotedMessage.d.ts +2 -0
  82. package/lib/typescript/src/screens/chat-detail/ChatCurrentQuotedMessage.d.ts.map +1 -0
  83. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  84. package/lib/typescript/src/screens/chat-detail/PinnedMessageBar.d.ts +4 -3
  85. package/lib/typescript/src/screens/chat-detail/PinnedMessageBar.d.ts.map +1 -1
  86. package/lib/typescript/src/screens/chat-detail/PinnedMessagesSheet.d.ts +9 -0
  87. package/lib/typescript/src/screens/chat-detail/PinnedMessagesSheet.d.ts.map +1 -0
  88. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts +2 -3
  89. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
  90. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.d.ts +11 -7
  91. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.d.ts.map +1 -1
  92. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.d.ts +4 -4
  93. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.d.ts.map +1 -1
  94. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.d.ts.map +1 -1
  95. package/lib/typescript/src/screens/chat-detail/messageToolbox/messageToolbox.utils.d.ts +5 -3
  96. package/lib/typescript/src/screens/chat-detail/messageToolbox/messageToolbox.utils.d.ts.map +1 -1
  97. package/lib/typescript/src/screens/chat-detail/messageToolbox/types.d.ts +2 -2
  98. package/lib/typescript/src/screens/chat-detail/messageToolbox/types.d.ts.map +1 -1
  99. package/lib/typescript/src/screens/chat-detail/types.d.ts +5 -5
  100. package/lib/typescript/src/screens/chat-detail/types.d.ts.map +1 -1
  101. package/lib/typescript/src/screens/inbox/Inbox.d.ts.map +1 -1
  102. package/lib/typescript/src/services/apis.d.ts +0 -1
  103. package/lib/typescript/src/services/apis.d.ts.map +1 -1
  104. package/lib/typescript/src/services/message.d.ts +1 -2
  105. package/lib/typescript/src/services/message.d.ts.map +1 -1
  106. package/lib/typescript/src/store/message.d.ts.map +1 -1
  107. package/lib/typescript/src/store/pinnedMessage.d.ts +4 -4
  108. package/lib/typescript/src/store/pinnedMessage.d.ts.map +1 -1
  109. package/lib/typescript/src/store/user.d.ts +4 -4
  110. package/lib/typescript/src/store/user.d.ts.map +1 -1
  111. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  112. package/lib/typescript/src/types/auth.d.ts +0 -5
  113. package/lib/typescript/src/types/auth.d.ts.map +1 -1
  114. package/lib/typescript/src/types/chat.d.ts +19 -36
  115. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  116. package/lib/typescript/src/utils/UIUtils.d.ts.map +1 -1
  117. package/lib/typescript/src/utils/legendListMessage.d.ts +4 -4
  118. package/lib/typescript/src/utils/legendListMessage.d.ts.map +1 -1
  119. package/lib/typescript/src/utils/message.d.ts +4 -5
  120. package/lib/typescript/src/utils/message.d.ts.map +1 -1
  121. package/lib/typescript/src/utils/messageUtils.d.ts +9 -7
  122. package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
  123. package/package.json +2 -2
  124. package/src/components/messages/linkMessage/index.tsx +1 -11
  125. package/src/components/messages/quotedMessage/index.tsx +197 -0
  126. package/src/components/messages/types.ts +2 -2
  127. package/src/context/ChatContext.tsx +30 -25
  128. package/src/context/ChatDetailContext.tsx +9 -3
  129. package/src/core/useChatListener.ts +0 -1
  130. package/src/core/useUserListener.ts +9 -25
  131. package/src/hooks/message/useSendMessage.ts +25 -4
  132. package/src/hooks/useChatMessages.ts +4 -6
  133. package/src/hooks/useFileAttachment.ts +3 -1
  134. package/src/index.tsx +5 -6
  135. package/src/screens/chat-detail/ChatComposer.tsx +2 -0
  136. package/src/screens/chat-detail/ChatCurrentQuotedMessage.tsx +150 -0
  137. package/src/screens/chat-detail/ChatDetail.tsx +13 -2
  138. package/src/screens/chat-detail/ChatListLegend.tsx +3 -3
  139. package/src/screens/chat-detail/PinnedMessageBar.tsx +53 -49
  140. package/src/screens/chat-detail/PinnedMessagesSheet.tsx +243 -0
  141. package/src/screens/chat-detail/legend/LegendChatMessage.tsx +4 -4
  142. package/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.tsx +30 -6
  143. package/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.tsx +15 -6
  144. package/src/screens/chat-detail/messageToolbox/MessageToolboxWrapper.tsx +1 -0
  145. package/src/screens/chat-detail/messageToolbox/messageToolbox.utils.ts +21 -12
  146. package/src/screens/chat-detail/messageToolbox/types.ts +2 -2
  147. package/src/screens/chat-detail/types.ts +5 -5
  148. package/src/screens/inbox/Inbox.tsx +1 -5
  149. package/src/services/apis.ts +0 -4
  150. package/src/services/message.ts +1 -2
  151. package/src/store/message.ts +3 -3
  152. package/src/store/pinnedMessage.ts +4 -4
  153. package/src/store/user.ts +5 -5
  154. package/src/translation/resources/i18n.ts +10 -1
  155. package/src/types/auth.ts +0 -6
  156. package/src/types/chat.ts +19 -40
  157. package/src/utils/UIUtils.ts +5 -0
  158. package/src/utils/legendListMessage.ts +4 -5
  159. package/src/utils/message.ts +10 -11
  160. package/src/utils/messageUtils.ts +37 -9
@@ -11,12 +11,16 @@ interface MessageToolboxMenuProps {
11
11
  showUnpinMessage?: boolean;
12
12
  showRetryMessage?: boolean;
13
13
  showRevokeMessage?: boolean;
14
- onCopyMessage: () => void;
15
- onCopyMessageLink: () => void;
16
- onPinMessage: () => void;
17
- onUnpinMessage: () => void;
18
- onRetryMessage: () => void;
19
- onRevokeMessage: () => void;
14
+ showViewOriginalMessage?: boolean;
15
+ onPinMessage?: () => void;
16
+ onUnpinMessage?: () => void;
17
+ onViewOriginalMessage?: () => void;
18
+ showQuoteMessage?: boolean;
19
+ onCopyMessage?: () => void;
20
+ onCopyMessageLink?: () => void;
21
+ onRetryMessage?: () => void;
22
+ onRevokeMessage?: () => void;
23
+ onQuoteMessage?: () => void;
20
24
  }
21
25
 
22
26
  export const MessageToolboxMenu = memo(
@@ -27,15 +31,27 @@ export const MessageToolboxMenu = memo(
27
31
  showUnpinMessage,
28
32
  showRetryMessage,
29
33
  showRevokeMessage,
34
+ showViewOriginalMessage,
35
+ showQuoteMessage,
30
36
  onCopyMessage,
31
37
  onCopyMessageLink,
32
38
  onPinMessage,
33
39
  onUnpinMessage,
34
40
  onRetryMessage,
35
41
  onRevokeMessage,
42
+ onViewOriginalMessage,
43
+ onQuoteMessage,
36
44
  }: MessageToolboxMenuProps) => {
37
45
  return (
38
46
  <KContainer.View style={styles.card}>
47
+ <MessageToolboxItem
48
+ icon="arrow-reply-o"
49
+ color={KColors.gray.dark}
50
+ label={trans('chat:reply_message')}
51
+ visible={showQuoteMessage}
52
+ onPress={onQuoteMessage}
53
+ />
54
+
39
55
  <MessageToolboxItem
40
56
  icon="copy-o"
41
57
  color={KColors.gray.dark}
@@ -68,6 +84,14 @@ export const MessageToolboxMenu = memo(
68
84
  onPress={onUnpinMessage}
69
85
  />
70
86
 
87
+ <MessageToolboxItem
88
+ icon="chat-square-o"
89
+ color={KColors.gray.dark}
90
+ label={trans('chat:view_original_message')}
91
+ visible={showViewOriginalMessage}
92
+ onPress={onViewOriginalMessage}
93
+ />
94
+
71
95
  <MessageToolboxItem
72
96
  icon="arrow-reload-o"
73
97
  color={KColors.danger.normal}
@@ -15,17 +15,18 @@ import {
15
15
  getCopyableMessageText,
16
16
  getMessageToolboxItems,
17
17
  } from './messageToolbox.utils';
18
- import type { DMessageItem } from '../../../types/chat';
19
18
  import type { MeasuredRect, MessageToolboxRef } from './types';
20
19
  import { MessageToolboxWrapper } from './MessageToolboxWrapper';
21
20
  import type { ReactNode } from 'react';
22
21
  import { useSendMessage } from '../../../hooks/message/useSendMessage';
22
+ import { useChatDetailContext } from '../../../context';
23
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
23
24
 
24
25
  interface MessageToolboxOverlayProps {
25
26
  currentUserId?: string;
26
- customMessageItemFactory?: (item: DMessageItem) => ReactNode;
27
- onPinMessage?: (message: DMessageItem) => void;
28
- onUnpinMessage?: (message: DMessageItem) => void;
27
+ customMessageItemFactory?: (item: MessageItem) => ReactNode;
28
+ onPinMessage?: (message: MessageItem) => void;
29
+ onUnpinMessage?: (message: MessageItem) => void;
29
30
  }
30
31
 
31
32
  export const MessageToolboxOverlay = forwardRef<
@@ -41,8 +42,9 @@ export const MessageToolboxOverlay = forwardRef<
41
42
  },
42
43
  ref
43
44
  ) => {
45
+ const { setQuotedMessage } = useChatDetailContext();
44
46
  const [visible, setVisible] = useState(false);
45
- const [message, setMessage] = useState<DMessageItem | undefined>(undefined);
47
+ const [message, setMessage] = useState<MessageItem | undefined>(undefined);
46
48
  const [rect, setRect] = useState<MeasuredRect | null>(null);
47
49
  const toolboxItems = useMemo(
48
50
  () => getMessageToolboxItems(message, currentUserId),
@@ -57,7 +59,7 @@ export const MessageToolboxOverlay = forwardRef<
57
59
  }, []);
58
60
 
59
61
  const show = useCallback(
60
- (msg: DMessageItem, msgRect: MeasuredRect) => {
62
+ (msg: MessageItem, msgRect: MeasuredRect) => {
61
63
  const toolboxNotAvailable =
62
64
  Object.values(getMessageToolboxItems(msg, currentUserId)).filter(
63
65
  Boolean
@@ -135,6 +137,12 @@ export const MessageToolboxOverlay = forwardRef<
135
137
  onUnpinMessage?.(message);
136
138
  }, [message, hide, onUnpinMessage]);
137
139
 
140
+ const handleQuoteMessage = useCallback(() => {
141
+ if (!message) return;
142
+ setQuotedMessage(message);
143
+ hide();
144
+ }, [message, hide, setQuotedMessage]);
145
+
138
146
  if (!visible || !message || !rect) {
139
147
  return null;
140
148
  }
@@ -171,6 +179,7 @@ export const MessageToolboxOverlay = forwardRef<
171
179
  onUnpinMessage={handleUnpinMessage}
172
180
  onRetryMessage={handleRetryMessage}
173
181
  onRevokeMessage={handleRevokeMessage}
182
+ onQuoteMessage={handleQuoteMessage}
174
183
  />
175
184
  }
176
185
  />
@@ -74,6 +74,7 @@ export const MessageToolboxWrapper = memo(
74
74
  const containerStyles = useAnimatedStyle(() => ({
75
75
  top: Math.max(rect.y, insets.top) + topOffset,
76
76
  left: rect.x,
77
+ width: rect.width,
77
78
  gap: MENU_GAP,
78
79
  transform: [{ translateY: translateY.value }],
79
80
  }));
@@ -1,5 +1,8 @@
1
- import { MessageStatus, MessageType } from '@droppii/openim-rn-client-sdk';
2
- import type { DMessageItem } from '../../../types/chat';
1
+ import {
2
+ MessageStatus,
3
+ MessageType,
4
+ type MessageItem,
5
+ } from '@droppii/openim-rn-client-sdk';
3
6
  import { getMessageText } from '../../../utils/legendListMessage';
4
7
  import { isMessageRevoked } from '../../../utils/messageUtils';
5
8
 
@@ -22,46 +25,50 @@ const PIN_SUPPORTED_TYPES: number[] = [
22
25
  MessageType.FileMessage,
23
26
  ];
24
27
 
25
- const isMessageSucceeded = (message: DMessageItem): boolean =>
28
+ const isMessageSucceeded = (message: MessageItem): boolean =>
26
29
  message.status !== MessageStatus.Failed &&
27
30
  message.status !== MessageStatus.Sending;
28
31
 
29
32
  // Failed or revoked messages never offer either copy action.
30
- const isEligibleForToolbox = (message: DMessageItem): boolean =>
33
+ const isEligibleForToolbox = (message: MessageItem): boolean =>
31
34
  isMessageSucceeded(message) && !isMessageRevoked(message);
32
35
 
33
- const isCopyMessageSupported = (message: DMessageItem): boolean =>
36
+ const isCopyMessageSupported = (message: MessageItem): boolean =>
34
37
  isEligibleForToolbox(message) &&
35
38
  COPYABLE_TEXT_TYPES.includes(message.contentType);
36
39
 
37
40
  // All message types are supported, as long as the message is eligible.
38
- // const isCopyMessageLinkSupported = (message: DMessageItem): boolean =>
41
+ // const isCopyMessageLinkSupported = (message: MessageItem): boolean =>
39
42
  // isEligibleForToolbox(message);
40
43
 
41
- const isRetrySupported = (message: DMessageItem): boolean =>
44
+ const isRetrySupported = (message: MessageItem): boolean =>
42
45
  message.status === MessageStatus.Failed;
43
46
 
44
47
  // Merged/album messages (grouped photos) count as "image" for pinning
45
48
  // purposes, mirroring the preview logic in utils/messageUtils.ts.
46
- const isMergedImageMessage = (message: DMessageItem): boolean =>
49
+ const isMergedImageMessage = (message: MessageItem): boolean =>
47
50
  message.contentType === MessageType.MergeMessage &&
48
51
  !!message.mergeElem?.multiMessage?.some(
49
52
  (msg) => msg.contentType === MessageType.PictureMessage
50
53
  );
51
54
 
52
55
  // BR-002: Pin message supports only successfully sent messages.
53
- const isPinMessageSupported = (message: DMessageItem): boolean =>
56
+ const isPinMessageSupported = (message: MessageItem): boolean =>
54
57
  isEligibleForToolbox(message) &&
55
58
  (PIN_SUPPORTED_TYPES.includes(message.contentType) ||
56
59
  isMergedImageMessage(message));
57
60
 
61
+ const isQuoteMessageSupported = (message: MessageItem): boolean =>
62
+ isMessageSucceeded(message) &&
63
+ message?.contentType !== MessageType.RevokeMessage;
64
+
58
65
  // Revoke is only available within 24h of a successful send.
59
66
  const REVOKE_WINDOW_MS = 24 * 60 * 60 * 1000;
60
67
 
61
68
  // Revoke is only available for messages sent by the current user.
62
69
  // And not limited by message content type.
63
70
  const isRevokeMessageSupported = (
64
- message: DMessageItem,
71
+ message: MessageItem,
65
72
  currentUserId?: string
66
73
  ): boolean =>
67
74
  isEligibleForToolbox(message) &&
@@ -69,7 +76,7 @@ const isRevokeMessageSupported = (
69
76
  message.sendID === currentUserId &&
70
77
  Date.now() - (message.sendTime || message.createTime || 0) < REVOKE_WINDOW_MS;
71
78
 
72
- export const getCopyableMessageText = (message: DMessageItem): string => {
79
+ export const getCopyableMessageText = (message: MessageItem): string => {
73
80
  if (message.contentType === MessageType.UrlTextMessage) {
74
81
  return message.urlTextElem?.content ?? '';
75
82
  }
@@ -77,7 +84,7 @@ export const getCopyableMessageText = (message: DMessageItem): string => {
77
84
  };
78
85
 
79
86
  export const getMessageToolboxItems = (
80
- message?: DMessageItem,
87
+ message?: MessageItem,
81
88
  currentUserId?: string
82
89
  ) => {
83
90
  if (message == null) {
@@ -88,6 +95,7 @@ export const getMessageToolboxItems = (
88
95
  // const showCopyMessageLink = isCopyMessageLinkSupported(message);
89
96
  const showRetryMessage = isRetrySupported(message);
90
97
  const showRevokeMessage = isRevokeMessageSupported(message, currentUserId);
98
+ const showQuoteMessage = isQuoteMessageSupported(message);
91
99
 
92
100
  const isPinSupported = isPinMessageSupported(message);
93
101
  const showPinMessage = isPinSupported && !message.isPinned;
@@ -100,5 +108,6 @@ export const getMessageToolboxItems = (
100
108
  showRevokeMessage,
101
109
  showPinMessage,
102
110
  showUnpinMessage,
111
+ showQuoteMessage,
103
112
  };
104
113
  };
@@ -1,4 +1,4 @@
1
- import type { DMessageItem } from '../../../types/chat';
1
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
2
2
 
3
3
  export interface MeasuredRect {
4
4
  x: number;
@@ -8,6 +8,6 @@ export interface MeasuredRect {
8
8
  }
9
9
 
10
10
  export interface MessageToolboxRef {
11
- show: (message: DMessageItem, rect: MeasuredRect) => void;
11
+ show: (message: MessageItem, rect: MeasuredRect) => void;
12
12
  hide: () => void;
13
13
  }
@@ -1,7 +1,7 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import type { MediaItem } from '../../hooks/useMediaViewer';
3
- import type { DMessageItem } from '../../types/chat';
4
3
  import type { MeasuredRect } from './messageToolbox/types';
4
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
5
5
 
6
6
  export type DChatActionIconProvider = 'MaterialCommunityIcons' | 'DroppiiNew';
7
7
 
@@ -70,9 +70,9 @@ export interface ChatComposerProps {
70
70
  }
71
71
 
72
72
  export interface ChatListProps {
73
- messages?: DMessageItem[];
73
+ messages?: MessageItem[];
74
74
  currentUserId?: string;
75
- customMessageItemFactory?: (item: DMessageItem) => ReactNode;
75
+ customMessageItemFactory?: (item: MessageItem) => ReactNode;
76
76
  onLoadEarlier?: () => void;
77
77
  isLoading?: boolean;
78
78
  isLoadingEarlier?: boolean;
@@ -82,7 +82,7 @@ export interface ChatListProps {
82
82
  hasMoreNewer?: boolean;
83
83
  onMediaPress?: (items: MediaItem[], index?: number) => void;
84
84
  onPressUrl?: (url: string) => void;
85
- onLongPress?: (message: DMessageItem, rect: MeasuredRect) => void;
85
+ onLongPress?: (message: MessageItem, rect: MeasuredRect) => void;
86
86
  }
87
87
 
88
88
  export interface ChatDetailProps extends Omit<
@@ -96,6 +96,6 @@ export interface ChatDetailProps extends Omit<
96
96
  enabled?: boolean;
97
97
  showAddMember?: boolean;
98
98
  onPressUrl?: (url: string) => void;
99
- customMessageItemFactory?: (item: DMessageItem) => ReactNode;
99
+ customMessageItemFactory?: (item: MessageItem) => ReactNode;
100
100
  pannelActions?: DChatPannelAction[];
101
101
  }
@@ -3,8 +3,6 @@ import { StyleSheet } from 'react-native';
3
3
  import { TabView } from 'react-native-tab-view';
4
4
  import { KContainer, KImage, KLabel, KColors } from '@droppii/libs';
5
5
  import { MessagesTab } from './MessagesTab';
6
- import { useUserStore } from '../../store';
7
- import { LoginStatus } from '@droppii/openim-rn-client-sdk';
8
6
 
9
7
  interface InboxProps {
10
8
  onPressThread?: (item: string) => void;
@@ -17,7 +15,6 @@ type TabRoute = { key: string; title: string };
17
15
 
18
16
  const Inbox = memo(
19
17
  ({ onPressThread, onPressSearch, onPressEdit, onPressGroup }: InboxProps) => {
20
- const connectStatus = useUserStore((state) => state.connectStatus);
21
18
  const [index, setIndex] = useState(0);
22
19
  const [routes] = useState<TabRoute[]>([
23
20
  { key: 'messages', title: 'Tin nhắn' },
@@ -25,13 +22,12 @@ const Inbox = memo(
25
22
 
26
23
  const renderScene = useCallback(
27
24
  ({ route }: { route: TabRoute }) => {
28
- if (connectStatus !== LoginStatus.Logged) return null;
29
25
  if (route.key === 'messages') {
30
26
  return <MessagesTab onPressThread={onPressThread} />;
31
27
  }
32
28
  return null;
33
29
  },
34
- [onPressThread, connectStatus]
30
+ [onPressThread]
35
31
  );
36
32
 
37
33
  const renderTabBar = useCallback(
@@ -17,8 +17,4 @@ export namespace ChatAPI {
17
17
  useConversationStore.getState().reset();
18
18
  return OpenIMSDK.logout(operationID);
19
19
  };
20
-
21
- export const getUser = async (operationID?: string | undefined) => {
22
- return OpenIMSDK.getSelfUserInfo(operationID);
23
- };
24
20
  }
@@ -3,7 +3,6 @@ import OpenIMSDK, {
3
3
  type AdvancedGetMessageResult,
4
4
  type MessageItem,
5
5
  } from '@droppii/openim-rn-client-sdk';
6
- import type { DMessageItem } from '../types/chat';
7
6
  import { useConversationStore } from '../store';
8
7
  import { getReceiverId } from '../utils/message';
9
8
 
@@ -34,7 +33,7 @@ export namespace ChatMessageAPI {
34
33
 
35
34
  export async function sendTextMessage(params: {
36
35
  text: string;
37
- }): Promise<DMessageItem> {
36
+ }): Promise<MessageItem> {
38
37
  const currentConversation = useConversationStore
39
38
  .getState()
40
39
  .getCurrentConversation();
@@ -1,7 +1,7 @@
1
1
  import { create } from 'zustand';
2
2
  import { MessageType } from '@droppii/openim-rn-client-sdk';
3
3
  import type { MessageItem } from '@droppii/openim-rn-client-sdk';
4
- import type { DMessageItem, MessageStore } from '../types/chat';
4
+ import type { MessageStore } from '../types/chat';
5
5
  import { mergeMessages } from '../utils/message';
6
6
 
7
7
  export const useMessageStore = create<MessageStore>()((set, get) => ({
@@ -15,7 +15,7 @@ export const useMessageStore = create<MessageStore>()((set, get) => ({
15
15
 
16
16
  pushNewMessage: (message: MessageItem) => {
17
17
  set((state) => ({
18
- messages: mergeMessages(state.messages, [message as DMessageItem]),
18
+ messages: mergeMessages(state.messages, [message]),
19
19
  }));
20
20
  },
21
21
 
@@ -25,7 +25,7 @@ export const useMessageStore = create<MessageStore>()((set, get) => ({
25
25
  (msg) => msg.clientMsgID === message.clientMsgID
26
26
  );
27
27
  if (idx < 0) return;
28
- tmpList[idx] = { ...tmpList[idx]!, ...message } as DMessageItem;
28
+ tmpList[idx] = { ...tmpList[idx]!, ...message };
29
29
  set({ messages: tmpList });
30
30
  },
31
31
 
@@ -1,11 +1,11 @@
1
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
1
2
  import { create } from 'zustand';
2
- import type { DMessageItem } from '../types/chat';
3
3
 
4
4
  export interface PinnedMessageStore {
5
- messages: DMessageItem[];
5
+ messages: MessageItem[];
6
6
  totalCount: number;
7
- setMessages: (messages: DMessageItem[], totalCount: number) => void;
8
- addMessage: (message: DMessageItem) => void;
7
+ setMessages: (messages: MessageItem[], totalCount: number) => void;
8
+ addMessage: (message: MessageItem) => void;
9
9
  removeMessage: (clientMsgID: string) => void;
10
10
  reset: () => void;
11
11
  }
package/src/store/user.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import { create } from 'zustand';
2
- import { LoginStatus, type SelfUserInfo } from '@droppii/openim-rn-client-sdk';
3
- import { SyncStatus } from '../types/auth';
2
+ import { type SelfUserInfo } from '@droppii/openim-rn-client-sdk';
3
+ import { ConnectStatus, SyncStatus } from '../types/chat';
4
4
 
5
5
  export interface UserStore {
6
6
  user?: SelfUserInfo;
7
7
  setUser: (user: SelfUserInfo) => void;
8
- connectStatus: LoginStatus;
9
- updateConnectStatus: (status: LoginStatus) => void;
8
+ connectStatus: ConnectStatus;
9
+ updateConnectStatus: (status: ConnectStatus) => void;
10
10
  syncStatus: SyncStatus;
11
11
  updateSyncStatus: (status: SyncStatus) => void;
12
12
  }
13
13
 
14
14
  export const useUserStore = create<UserStore>()((set) => ({
15
- connectStatus: LoginStatus.Logout,
15
+ connectStatus: ConnectStatus.Disconnected,
16
16
  syncStatus: SyncStatus.Loading,
17
17
  setUser(user) {
18
18
  set({ user });
@@ -1,7 +1,8 @@
1
1
  const i18nKey: Record<string, string> = {
2
2
  'thread_card_bot_crm_name': 'Droppii Hỗ Trợ',
3
3
  'thread_card_fallback_name': 'Người dùng',
4
- 'chat:file_too_large': 'Tệp quá lớn. Tối đa 10MB',
4
+ 'chat:file_too_large':
5
+ 'Tệp tải lên không hợp lệ. Kích thước tệp không được vượt quá {{maxSize}}MB',
5
6
  'chat:file_max_count': 'Chỉ có thể đính kèm tối đa 3 tệp',
6
7
  'chat:file_pick_failed': 'Không thể chọn tệp',
7
8
  'chat:file_upload_failed': 'Lỗi tải tệp lên',
@@ -47,6 +48,10 @@ const i18nKey: Record<string, string> = {
47
48
  'chat:pin_limit_desc':
48
49
  'Chỉ được ghim tối đa 5 tin nhắn. Vui lòng bỏ ghim một tin nhắn hiện có trước khi ghim tin nhắn mới.',
49
50
  'chat:pin_limit_primary': 'Đã hiểu',
51
+ 'chat:pinned_messages_title': 'Tin nhắn đã ghim',
52
+ 'chat:pinned_messages_hint':
53
+ 'Nhấn giữ tin nhắn để chọn "Bỏ Ghim" hoặc "Xem tin nhắn gốc"',
54
+ 'chat:view_original_message': 'Xem tin nhắn gốc',
50
55
  'msg_type_image': '[Hình ảnh]',
51
56
  'msg_type_voice': '[Tin nhắn thoại]',
52
57
  'msg_type_video': '[Video]',
@@ -71,6 +76,10 @@ const i18nKey: Record<string, string> = {
71
76
  'send_order': 'Gửi đơn hàng',
72
77
  'send_product': 'Gửi sản phẩm',
73
78
  'create_appointment': 'Tạo lịch hẹn',
79
+ 'chat:reply_message': 'Trả lời',
80
+ 'chat:reply_to': 'Trả lời {{name}}',
81
+ 'yourself': 'chính mình',
82
+ 'you': 'Bạn',
74
83
  };
75
84
 
76
85
  export default {
package/src/types/auth.ts CHANGED
@@ -18,9 +18,3 @@ export type GetOpenIMTokenResponse = {
18
18
  token: string;
19
19
  expiresIn: number;
20
20
  };
21
-
22
- export enum SyncStatus {
23
- Loading = 0,
24
- Success = 1,
25
- Failed = 2,
26
- }
package/src/types/chat.ts CHANGED
@@ -28,6 +28,7 @@ export interface ChatUIAdapter {
28
28
  toast?: { open: (params: any) => void };
29
29
  alert?: { open: (params: any) => void };
30
30
  popup?: { open: (params: any) => void };
31
+ bottomSheet?: { open: (params: any) => void };
31
32
  }
32
33
 
33
34
  export interface ChatContextType {
@@ -36,6 +37,7 @@ export interface ChatContextType {
36
37
  onPressFlashMessage?: (message: ConversationItem) => void;
37
38
  isShowFLashMessage: boolean;
38
39
  setIsShowFLashMessage: (value: boolean) => void;
40
+ handleLoginSdk: () => void;
39
41
  }
40
42
 
41
43
  export type ChatProviderProps = PropsWithChildren<{
@@ -97,6 +99,18 @@ export interface DBotStatus {
97
99
  botSupportPlatform: unknown | null;
98
100
  }
99
101
 
102
+ export enum SyncStatus {
103
+ Loading = 0,
104
+ Success = 1,
105
+ Failed = 2,
106
+ }
107
+
108
+ export enum ConnectStatus {
109
+ Disconnected = 0,
110
+ Connected = 1,
111
+ Connecting = 2,
112
+ }
113
+
100
114
  export interface DConversationPeerUser {
101
115
  id: string;
102
116
  username?: string;
@@ -118,42 +132,6 @@ export interface DConversationQueryParams {
118
132
  pageSize: number;
119
133
  }
120
134
 
121
- export interface DMessageItem extends MessageItem {
122
- isInternal?: boolean;
123
- atUserIDList?: unknown;
124
- attachedInfo?: 'null';
125
- options?: DMessageOption;
126
- isPinned?: boolean;
127
- pinnedByUserID?: string;
128
- pinnedTime?: number;
129
- }
130
-
131
- export interface DMessageOption {
132
- conversationUpdate: boolean;
133
- offlinePush: boolean;
134
- senderConversationUpdate: boolean;
135
- unreadCount: boolean;
136
- }
137
-
138
- export interface DMessagePushInfo {
139
- title: string;
140
- desc: string;
141
- /**
142
- * @instance DMessagePushInfoEx
143
- */
144
- ex: string;
145
- signalInfo: string;
146
- iospushSound: 'default';
147
- iosbadgeCount: boolean;
148
- }
149
-
150
- export interface DMessagePushInfoEx {
151
- icon: string; // url
152
- conversationId: string;
153
- title: string;
154
- desc: string;
155
- }
156
-
157
135
  export interface IMessageItemEx {
158
136
  applicationType: DChatApplicationType;
159
137
  sessionId?: string;
@@ -167,13 +145,13 @@ export interface IMessageItemEx {
167
145
  }
168
146
 
169
147
  export interface MessageStore {
170
- messages: DMessageItem[];
148
+ messages: MessageItem[];
171
149
  hasMoreEarlier: boolean;
172
150
  hasMoreNewer: boolean;
173
- setMessages: (messages: DMessageItem[], hasMore: boolean) => void;
151
+ setMessages: (messages: MessageItem[], hasMore: boolean) => void;
174
152
  pushNewMessage: (message: MessageItem) => void;
175
153
  updateOneMessage: (
176
- message: Partial<DMessageItem> & Pick<MessageItem, 'clientMsgID'>
154
+ message: Partial<MessageItem> & Pick<MessageItem, 'clientMsgID'>
177
155
  ) => void;
178
156
  deleteOneMessage: (clientMsgID: string) => void;
179
157
  reset: () => void;
@@ -181,12 +159,13 @@ export interface MessageStore {
181
159
 
182
160
  export interface ChatDetailContextType {
183
161
  conversationFlow?: IConversationFlow;
184
- refetchConversationFlow: () => void;
185
162
  isBotConversation: boolean;
186
163
  setConverationFlowStep: (step?: IConversationFlowStep) => void;
187
164
  flowState?: DFlowState;
188
165
  runButtonContext: (stringContext: DFlowContext) => Promise<boolean>;
189
166
  conversation?: ConversationItem;
167
+ quotedMessage?: MessageItem;
168
+ setQuotedMessage: (item?: MessageItem) => void;
190
169
  }
191
170
 
192
171
  export interface ChatDetailProviderProps extends PropsWithChildren {}
@@ -10,6 +10,7 @@ const defaultAdapter: Required<ChatUIAdapter> = {
10
10
  toast: { open: openWithAlert },
11
11
  alert: { open: openWithAlert },
12
12
  popup: { open: openWithAlert },
13
+ bottomSheet: { open: openWithAlert },
13
14
  };
14
15
 
15
16
  let _adapter: ChatUIAdapter = {};
@@ -28,4 +29,8 @@ export const UIUtils: Required<ChatUIAdapter> = {
28
29
  popup: {
29
30
  open: (params) => (_adapter.popup ?? defaultAdapter.popup).open(params),
30
31
  },
32
+ bottomSheet: {
33
+ open: (params) =>
34
+ (_adapter.bottomSheet ?? defaultAdapter.bottomSheet).open(params),
35
+ },
31
36
  };
@@ -1,10 +1,9 @@
1
- import { MessageType } from '@droppii/openim-rn-client-sdk';
2
- import type { DMessageItem } from '../types/chat';
1
+ import { MessageType, type MessageItem } from '@droppii/openim-rn-client-sdk';
3
2
 
4
3
  /**
5
4
  * Extract message text based on content type
6
5
  */
7
- export const getMessageText = (message: DMessageItem): string => {
6
+ export const getMessageText = (message: MessageItem): string => {
8
7
  switch (message.contentType) {
9
8
  case MessageType.TextMessage:
10
9
  return message.textElem?.content ?? message.content;
@@ -49,7 +48,7 @@ export interface PrecomputedMessageData {
49
48
  * Returns: Map of messageId -> {dayStart, messageType, createdAt}
50
49
  */
51
50
  export const precomputeLegendListData = (
52
- messages: DMessageItem[]
51
+ messages: MessageItem[]
53
52
  ): Map<string, PrecomputedMessageData> => {
54
53
  const dataMap = new Map<string, PrecomputedMessageData>();
55
54
  let lastDay: number | null = null;
@@ -81,7 +80,7 @@ export const precomputeLegendListData = (
81
80
  * Kept for backward compatibility
82
81
  */
83
82
  export const computeDayStarts = (
84
- messages: DMessageItem[]
83
+ messages: MessageItem[]
85
84
  ): Map<string, boolean> => {
86
85
  const dayStartMap = new Map<string, boolean>();
87
86
  let lastDay: number | null = null;
@@ -4,20 +4,19 @@ import {
4
4
  type ConversationItem,
5
5
  type MessageItem,
6
6
  } from '@droppii/openim-rn-client-sdk';
7
- import { type DMessageItem } from '../types/chat';
8
7
  import { getConversationID } from './conversation';
9
8
 
10
- const getMessageTime = (message: DMessageItem) =>
9
+ const getMessageTime = (message: MessageItem) =>
11
10
  message.sendTime || message.createTime || 0;
12
11
 
13
- const getMessageKey = (message: DMessageItem) =>
12
+ const getMessageKey = (message: MessageItem) =>
14
13
  message.clientMsgID || message.serverMsgID;
15
14
 
16
15
  export const mergeMessages = (
17
- current: DMessageItem[],
18
- incoming: DMessageItem[]
19
- ): DMessageItem[] => {
20
- const map = new Map<string, DMessageItem>();
16
+ current: MessageItem[],
17
+ incoming: MessageItem[]
18
+ ): MessageItem[] => {
19
+ const map = new Map<string, MessageItem>();
21
20
 
22
21
  for (const message of [...current, ...incoming]) {
23
22
  const key = getMessageKey(message);
@@ -54,7 +53,7 @@ export type HistoryPaginationAnchor = {
54
53
 
55
54
  export const resolveHistoryLastMinSeq = (
56
55
  history: { lastMinSeq?: number },
57
- fallbackMessage?: DMessageItem
56
+ fallbackMessage?: MessageItem
58
57
  ): number => {
59
58
  if (history.lastMinSeq != null) {
60
59
  return history.lastMinSeq;
@@ -64,7 +63,7 @@ export const resolveHistoryLastMinSeq = (
64
63
  };
65
64
 
66
65
  export const getHistoryPaginationAnchor = (
67
- messages: DMessageItem[]
66
+ messages: MessageItem[]
68
67
  ): HistoryPaginationAnchor | null => {
69
68
  if (!messages.length) {
70
69
  return null;
@@ -86,8 +85,8 @@ export const getHistoryPaginationAnchor = (
86
85
  };
87
86
 
88
87
  export const hasNewHistoryMessages = (
89
- current: DMessageItem[],
90
- incoming: DMessageItem[]
88
+ current: MessageItem[],
89
+ incoming: MessageItem[]
91
90
  ): boolean => {
92
91
  const currentKeys = new Set(
93
92
  current.map((message) => getMessageKey(message)).filter(Boolean)