@droppii-org/chat-mobile 0.2.31 → 0.2.33

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 (99) hide show
  1. package/lib/module/components/ThreadCard/ThreadCard.js +4 -0
  2. package/lib/module/components/ThreadCard/ThreadCard.js.map +1 -1
  3. package/lib/module/context/ChatContext.js +46 -12
  4. package/lib/module/context/ChatContext.js.map +1 -1
  5. package/lib/module/context/global.js +6 -0
  6. package/lib/module/context/global.js.map +1 -0
  7. package/lib/module/core/useChatListener.js +48 -12
  8. package/lib/module/core/useChatListener.js.map +1 -1
  9. package/lib/module/hooks/message/usePinMessage.js +133 -0
  10. package/lib/module/hooks/message/usePinMessage.js.map +1 -0
  11. package/lib/module/hooks/message/useSendMessage.js +9 -3
  12. package/lib/module/hooks/message/useSendMessage.js.map +1 -1
  13. package/lib/module/hooks/useChatMessages.js +5 -1
  14. package/lib/module/hooks/useChatMessages.js.map +1 -1
  15. package/lib/module/hooks/useImageAttachment.js +2 -0
  16. package/lib/module/hooks/useImageAttachment.js.map +1 -1
  17. package/lib/module/index.js +9 -1
  18. package/lib/module/index.js.map +1 -1
  19. package/lib/module/screens/chat-detail/ChatDetail.js +13 -1
  20. package/lib/module/screens/chat-detail/ChatDetail.js.map +1 -1
  21. package/lib/module/screens/chat-detail/PinnedMessageBar.js +158 -0
  22. package/lib/module/screens/chat-detail/PinnedMessageBar.js.map +1 -0
  23. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js +47 -10
  24. package/lib/module/screens/chat-detail/legend/LegendChatMessage.js.map +1 -1
  25. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxMenu.js +16 -0
  26. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxMenu.js.map +1 -1
  27. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js +15 -1
  28. package/lib/module/screens/chat-detail/messageToolbox/MessageToolboxOverlay.js.map +1 -1
  29. package/lib/module/screens/chat-detail/messageToolbox/messageToolbox.utils.js +16 -1
  30. package/lib/module/screens/chat-detail/messageToolbox/messageToolbox.utils.js.map +1 -1
  31. package/lib/module/services/attachmentOrchestrator.js +3 -1
  32. package/lib/module/services/attachmentOrchestrator.js.map +1 -1
  33. package/lib/module/store/pinnedMessage.js +34 -0
  34. package/lib/module/store/pinnedMessage.js.map +1 -0
  35. package/lib/module/translation/resources/i18n.js +12 -0
  36. package/lib/module/translation/resources/i18n.js.map +1 -1
  37. package/lib/module/types/chat.js.map +1 -1
  38. package/lib/module/utils/messageUtils.js +77 -1
  39. package/lib/module/utils/messageUtils.js.map +1 -1
  40. package/lib/module/utils/toastFlashMessage.js +56 -0
  41. package/lib/module/utils/toastFlashMessage.js.map +1 -0
  42. package/lib/typescript/src/components/ThreadCard/ThreadCard.d.ts.map +1 -1
  43. package/lib/typescript/src/context/ChatContext.d.ts.map +1 -1
  44. package/lib/typescript/src/context/global.d.ts +3 -0
  45. package/lib/typescript/src/context/global.d.ts.map +1 -0
  46. package/lib/typescript/src/core/useChatListener.d.ts.map +1 -1
  47. package/lib/typescript/src/hooks/message/usePinMessage.d.ts +9 -0
  48. package/lib/typescript/src/hooks/message/usePinMessage.d.ts.map +1 -0
  49. package/lib/typescript/src/hooks/message/useSendMessage.d.ts +3 -1
  50. package/lib/typescript/src/hooks/message/useSendMessage.d.ts.map +1 -1
  51. package/lib/typescript/src/hooks/useChatMessages.d.ts.map +1 -1
  52. package/lib/typescript/src/hooks/useImageAttachment.d.ts.map +1 -1
  53. package/lib/typescript/src/index.d.ts +4 -3
  54. package/lib/typescript/src/index.d.ts.map +1 -1
  55. package/lib/typescript/src/screens/chat-detail/ChatDetail.d.ts.map +1 -1
  56. package/lib/typescript/src/screens/chat-detail/PinnedMessageBar.d.ts +8 -0
  57. package/lib/typescript/src/screens/chat-detail/PinnedMessageBar.d.ts.map +1 -0
  58. package/lib/typescript/src/screens/chat-detail/legend/LegendChatMessage.d.ts.map +1 -1
  59. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.d.ts +5 -1
  60. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.d.ts.map +1 -1
  61. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.d.ts +2 -0
  62. package/lib/typescript/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.d.ts.map +1 -1
  63. package/lib/typescript/src/screens/chat-detail/messageToolbox/messageToolbox.utils.d.ts +4 -0
  64. package/lib/typescript/src/screens/chat-detail/messageToolbox/messageToolbox.utils.d.ts.map +1 -1
  65. package/lib/typescript/src/services/attachmentOrchestrator.d.ts.map +1 -1
  66. package/lib/typescript/src/store/pinnedMessage.d.ts +11 -0
  67. package/lib/typescript/src/store/pinnedMessage.d.ts.map +1 -0
  68. package/lib/typescript/src/translation/resources/i18n.d.ts.map +1 -1
  69. package/lib/typescript/src/types/chat.d.ts +8 -1
  70. package/lib/typescript/src/types/chat.d.ts.map +1 -1
  71. package/lib/typescript/src/types/imageUpload.d.ts +1 -1
  72. package/lib/typescript/src/types/imageUpload.d.ts.map +1 -1
  73. package/lib/typescript/src/utils/messageUtils.d.ts +8 -0
  74. package/lib/typescript/src/utils/messageUtils.d.ts.map +1 -1
  75. package/lib/typescript/src/utils/toastFlashMessage.d.ts +12 -0
  76. package/lib/typescript/src/utils/toastFlashMessage.d.ts.map +1 -0
  77. package/package.json +5 -3
  78. package/src/components/ThreadCard/ThreadCard.tsx +4 -0
  79. package/src/context/ChatContext.tsx +66 -9
  80. package/src/context/global.ts +6 -0
  81. package/src/core/useChatListener.ts +73 -11
  82. package/src/hooks/message/usePinMessage.ts +153 -0
  83. package/src/hooks/message/useSendMessage.ts +13 -9
  84. package/src/hooks/useChatMessages.ts +6 -2
  85. package/src/hooks/useImageAttachment.ts +2 -0
  86. package/src/index.tsx +10 -18
  87. package/src/screens/chat-detail/ChatDetail.tsx +12 -0
  88. package/src/screens/chat-detail/PinnedMessageBar.tsx +177 -0
  89. package/src/screens/chat-detail/legend/LegendChatMessage.tsx +47 -10
  90. package/src/screens/chat-detail/messageToolbox/MessageToolboxMenu.tsx +24 -0
  91. package/src/screens/chat-detail/messageToolbox/MessageToolboxOverlay.tsx +142 -116
  92. package/src/screens/chat-detail/messageToolbox/messageToolbox.utils.ts +31 -0
  93. package/src/services/attachmentOrchestrator.ts +2 -0
  94. package/src/store/pinnedMessage.ts +38 -0
  95. package/src/translation/resources/i18n.ts +13 -0
  96. package/src/types/chat.ts +8 -1
  97. package/src/types/imageUpload.ts +1 -1
  98. package/src/utils/messageUtils.ts +91 -3
  99. package/src/utils/toastFlashMessage.ts +67 -0
@@ -0,0 +1,11 @@
1
+ import type { DMessageItem } from '../types/chat';
2
+ export interface PinnedMessageStore {
3
+ messages: DMessageItem[];
4
+ totalCount: number;
5
+ setMessages: (messages: DMessageItem[], totalCount: number) => void;
6
+ addMessage: (message: DMessageItem) => void;
7
+ removeMessage: (clientMsgID: string) => void;
8
+ reset: () => void;
9
+ }
10
+ export declare const usePinnedMessageStore: import("zustand").UseBoundStore<import("zustand").StoreApi<PinnedMessageStore>>;
11
+ //# sourceMappingURL=pinnedMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinnedMessage.d.ts","sourceRoot":"","sources":["../../../../src/store/pinnedMessage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IACpE,UAAU,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;IAC5C,aAAa,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC7C,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,eAAO,MAAM,qBAAqB,iFAyBjC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../../src/translation/resources/i18n.ts"],"names":[],"mappings":";;;AA8DA,wBAEE"}
1
+ {"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../../../../src/translation/resources/i18n.ts"],"names":[],"mappings":";;;AA2EA,wBAEE"}
@@ -23,11 +23,15 @@ export interface ChatUIAdapter {
23
23
  export interface ChatContextType {
24
24
  logGA?: LogGA;
25
25
  applicationType: DChatApplicationType;
26
+ onPressFlashMessage?: (message: ConversationItem) => void;
27
+ isShowFLashMessage: boolean;
28
+ setIsShowFLashMessage: (value: boolean) => void;
26
29
  }
27
30
  export type ChatProviderProps = PropsWithChildren<{
28
31
  logGA?: LogGA;
29
32
  applicationType: DChatApplicationType;
30
33
  getChatToken: () => Promise<GetOpenIMTokenResponse | null>;
34
+ onFlashMessagePress?: (c: ConversationItem) => void;
31
35
  }>;
32
36
  export declare enum DChatApplicationType {
33
37
  DROPPII = "DROPPII",
@@ -71,6 +75,9 @@ export interface DMessageItem extends MessageItem {
71
75
  atUserIDList?: unknown;
72
76
  attachedInfo?: 'null';
73
77
  options?: DMessageOption;
78
+ isPinned?: boolean;
79
+ pinnedByUserID?: string;
80
+ pinnedTime?: number;
74
81
  }
75
82
  export interface DMessageOption {
76
83
  conversationUpdate: boolean;
@@ -112,7 +119,7 @@ export interface MessageStore {
112
119
  hasMoreNewer: boolean;
113
120
  setMessages: (messages: DMessageItem[], hasMore: boolean) => void;
114
121
  pushNewMessage: (message: MessageItem) => void;
115
- updateOneMessage: (message: Partial<MessageItem> & Pick<MessageItem, 'clientMsgID'>) => void;
122
+ updateOneMessage: (message: Partial<DMessageItem> & Pick<MessageItem, 'clientMsgID'>) => void;
116
123
  deleteOneMessage: (clientMsgID: string) => void;
117
124
  reset: () => void;
118
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../../src/types/chat.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../../src/types/chat.ts"],"names":[],"mappings":"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"}
@@ -18,7 +18,7 @@ export interface ImageUploadConfig {
18
18
  timeout?: number;
19
19
  retryAttempts?: number;
20
20
  }
21
- export interface UploadProgress {
21
+ export interface IUploadProgress {
22
22
  completed: number;
23
23
  total: number;
24
24
  percentage: number;
@@ -1 +1 @@
1
- {"version":3,"file":"imageUpload.d.ts","sourceRoot":"","sources":["../../../../src/types/imageUpload.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB"}
1
+ {"version":3,"file":"imageUpload.d.ts","sourceRoot":"","sources":["../../../../src/types/imageUpload.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;CACpB"}
@@ -6,5 +6,13 @@ import { type DMessageItem } from '../types/chat';
6
6
  export declare const isMessageRevoked: (message: DMessageItem) => boolean;
7
7
  export declare const extractTextContent: (message: DMessageItem) => string;
8
8
  export declare const getMessagePreview: (message: DMessageItem) => string;
9
+ export type PinnedMessageMediaType = 'image' | 'video' | 'file' | 'text';
10
+ export interface PinnedMessagePreview {
11
+ mediaType: PinnedMessageMediaType;
12
+ subtitleKey: string;
13
+ thumbnailUrl?: string;
14
+ fileIcon?: number;
15
+ }
16
+ export declare const getPinnedMessagePreview: (message: DMessageItem) => PinnedMessagePreview;
9
17
  export declare const getLastMessageText: (message: DMessageItem | undefined, currentUserId?: string, conversation?: ConversationItem) => string;
10
18
  //# sourceMappingURL=messageUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"messageUtils.d.ts","sourceRoot":"","sources":["../../../../src/utils/messageUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAIlD,eAAO,MAAM,gBAAgB,GAAI,SAAS,YAAY,KAAG,OACN,CAAC;AAEpD,eAAO,MAAM,kBAAkB,GAAI,SAAS,YAAY,KAAG,MAQ1D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,SAAS,YAAY,KAAG,MAmEzD,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,YAAY,GAAG,SAAS,EACjC,gBAAgB,MAAM,EACtB,eAAe,gBAAgB,KAC9B,MAmBF,CAAC"}
1
+ {"version":3,"file":"messageUtils.d.ts","sourceRoot":"","sources":["../../../../src/utils/messageUtils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,eAAe,CAAC;AAMlD,eAAO,MAAM,gBAAgB,GAAI,SAAS,YAAY,KAAG,OACN,CAAC;AAEpD,eAAO,MAAM,kBAAkB,GAAI,SAAS,YAAY,KAAG,MAQ1D,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAI,SAAS,YAAY,KAAG,MAkEzD,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzE,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,sBAAsB,CAAC;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAmBD,eAAO,MAAM,uBAAuB,GAClC,SAAS,YAAY,KACpB,oBA0DF,CAAC;AAEF,eAAO,MAAM,kBAAkB,GAC7B,SAAS,YAAY,GAAG,SAAS,EACjC,gBAAgB,MAAM,EACtB,eAAe,gBAAgB,KAC9B,MAkBF,CAAC"}
@@ -0,0 +1,12 @@
1
+ interface ShowFlashMessageParams {
2
+ key: string;
3
+ title: string;
4
+ body?: string;
5
+ onPress?: () => void;
6
+ }
7
+ export declare const ToastFlashMessage: {
8
+ show: (params: ShowFlashMessageParams) => void;
9
+ hide: (key: string) => void;
10
+ };
11
+ export {};
12
+ //# sourceMappingURL=toastFlashMessage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toastFlashMessage.d.ts","sourceRoot":"","sources":["../../../../src/utils/toastFlashMessage.ts"],"names":[],"mappings":"AAEA,UAAU,sBAAsB;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB;AA4BD,eAAO,MAAM,iBAAiB;mBACb,sBAAsB;gBAkBzB,MAAM;CAYnB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@droppii-org/chat-mobile",
3
- "version": "0.2.31",
3
+ "version": "0.2.33",
4
4
  "description": "Droppii chat mobile",
5
5
  "keywords": [
6
6
  "react-native",
@@ -78,7 +78,7 @@
78
78
  },
79
79
  "devDependencies": {
80
80
  "@commitlint/config-conventional": "^20.5.0",
81
- "@droppii/libs": "git+ssh://git@github.com:droppii/mobile-components.git#v1.1.17",
81
+ "@droppii/libs": "git+ssh://git@github.com:droppii/mobile-components.git#v1.1.19",
82
82
  "@eslint/compat": "^2.0.3",
83
83
  "@eslint/eslintrc": "^3.3.5",
84
84
  "@eslint/js": "^10.0.1",
@@ -121,11 +121,12 @@
121
121
  "react-native-mmkv": "4.0.0",
122
122
  "react-native-permissions": "^5.6.0",
123
123
  "react-native-photo-view": "git+ssh://git@github.com/droppii/react-native-photo-view.git",
124
- "react-native-reanimated": "^4.4.0",
124
+ "react-native-reanimated": "3.19.1",
125
125
  "react-native-safe-area-context": "^5.8.0",
126
126
  "react-native-snap-carousel": "3.9.0",
127
127
  "react-native-svg": "^15.15.5",
128
128
  "react-native-tab-view": "^4.3.1",
129
+ "react-native-toast-message": "^2.4.0",
129
130
  "react-native-vector-icons": "*",
130
131
  "react-native-video": "6.19.2",
131
132
  "react-native-web": "~0.21.1",
@@ -156,6 +157,7 @@
156
157
  "react-native-snap-carousel": "*",
157
158
  "react-native-svg": "*",
158
159
  "react-native-tab-view": "*",
160
+ "react-native-toast-message": "*",
159
161
  "react-native-video": "*",
160
162
  "zustand": "*"
161
163
  },
@@ -15,6 +15,7 @@ import {
15
15
  } from '@droppii/openim-rn-client-sdk';
16
16
  import { MuteThread } from './MuteThread';
17
17
  import { useIsJoinedGroup } from '../../hooks/useIsJoinedGroup';
18
+ import isEmpty from 'lodash/isEmpty';
18
19
 
19
20
  interface ThreadCardProps {
20
21
  item: string;
@@ -41,6 +42,9 @@ const ThreadCard = memo(({ item, onPress }: ThreadCardProps) => {
41
42
 
42
43
  const latestMsgData: MessageItem = useMemo(() => {
43
44
  let result = null;
45
+ if (isEmpty(latestMsg)) {
46
+ return null;
47
+ }
44
48
  try {
45
49
  result = JSON.parse(latestMsg || '{}');
46
50
  } catch (error) {
@@ -4,10 +4,17 @@ import {
4
4
  useContext,
5
5
  useEffect,
6
6
  useMemo,
7
+ useState,
7
8
  } from 'react';
8
9
  import type { ChatContextType, ChatProviderProps } from '../types/chat';
9
- import OpenIMSDK, { LoginStatus } from '@droppii/openim-rn-client-sdk';
10
+ import OpenIMSDK, {
11
+ LoginStatus,
12
+ type ConversationItem,
13
+ } from '@droppii/openim-rn-client-sdk';
14
+ import Toast from 'react-native-toast-message';
10
15
  import { useUserStore } from '../store';
16
+ import { useChatSdk } from '../core';
17
+ import { useSafeAreaInsets } from 'react-native-safe-area-context';
11
18
 
12
19
  export const ChatContext = createContext<ChatContextType | undefined>(
13
20
  undefined
@@ -26,12 +33,10 @@ const ChatProviderInner = ({
26
33
  children,
27
34
  applicationType,
28
35
  getChatToken,
36
+ onFlashMessagePress,
29
37
  }: ChatProviderProps) => {
30
38
  const connectStatus = useUserStore((state) => state.connectStatus);
31
- const value = useMemo(
32
- () => ({ logGA, applicationType, getChatToken }),
33
- [logGA, applicationType, getChatToken]
34
- );
39
+ const [isShowFLashMessage, setShow] = useState(true);
35
40
 
36
41
  const handleSdkLogin = useCallback(async () => {
37
42
  if (!!getChatToken && connectStatus === LoginStatus.Logout) {
@@ -55,9 +60,61 @@ const ChatProviderInner = ({
55
60
  handleSdkLogin();
56
61
  }, [handleSdkLogin]);
57
62
 
58
- return <ChatContext.Provider value={value}>{children}</ChatContext.Provider>;
63
+ const onPressFlashMessage = useCallback(
64
+ (c: ConversationItem) => {
65
+ onFlashMessagePress?.(c);
66
+ },
67
+ [onFlashMessagePress]
68
+ );
69
+
70
+ const setIsShowFLashMessage = useCallback((v: boolean) => {
71
+ console.log('setIsShowFLashMessage');
72
+ setShow(v);
73
+ }, []);
74
+
75
+ const value = useMemo(
76
+ () => ({
77
+ logGA,
78
+ applicationType,
79
+ getChatToken,
80
+ onPressFlashMessage,
81
+ isShowFLashMessage: isShowFLashMessage,
82
+ setIsShowFLashMessage: setIsShowFLashMessage,
83
+ }),
84
+ [
85
+ logGA,
86
+ applicationType,
87
+ getChatToken,
88
+ onPressFlashMessage,
89
+ isShowFLashMessage,
90
+ setIsShowFLashMessage,
91
+ ]
92
+ );
93
+
94
+ const { top } = useSafeAreaInsets();
95
+ return (
96
+ <ChatContext.Provider value={value}>
97
+ {
98
+ <>
99
+ <ChatSdkBridge />
100
+ {children}
101
+ <Toast topOffset={top} />
102
+ </>
103
+ }
104
+ </ChatContext.Provider>
105
+ );
59
106
  };
60
107
 
61
- export const ChatProvider = ({ ...props }: ChatProviderProps) => (
62
- <ChatProviderInner {...props} />
63
- );
108
+ // useChatSdk() -> useChatListener() -> useFlashMessagePress() reads from
109
+ // ChatContext via useChatContext(), which throws unless called by a
110
+ // descendant of ChatContext.Provider. ChatProviderInner IS the component
111
+ // that creates the Provider, so it cannot consume its own context — this
112
+ // bridge exists purely to run useChatSdk() one level below the Provider.
113
+ const ChatSdkBridge = () => {
114
+ useChatSdk();
115
+ return null;
116
+ };
117
+
118
+ export const ChatProvider = ({ ...props }: ChatProviderProps) => {
119
+ return <ChatProviderInner {...props} />;
120
+ };
@@ -0,0 +1,6 @@
1
+ import { useChatContext } from './ChatContext';
2
+
3
+ export const useGetIsShowFLashMessage = () =>
4
+ useChatContext?.().isShowFLashMessage;
5
+ export const useSetIsShowFLashMessage = () =>
6
+ useChatContext?.().setIsShowFLashMessage;
@@ -1,16 +1,27 @@
1
1
  import OpenIMSDK, {
2
+ MessageReceiveOptType,
2
3
  OpenIMEvent,
3
4
  type ConversationItem,
4
5
  type GroupMemberItem,
5
6
  type MessageItem,
7
+ type MessagePinned,
6
8
  type RevokedInfo,
7
9
  } from '@droppii/openim-rn-client-sdk';
8
10
  import { useCallback, useEffect } from 'react';
9
11
  import { useConversationStore } from '../store/conversation';
12
+ import { ToastFlashMessage } from '../utils/toastFlashMessage';
13
+ import { useUserStore } from '../store/user';
14
+ import { getLastMessageText } from '../utils/messageUtils';
15
+ import { useChatContext } from '../context';
16
+ import isEmpty from 'lodash/isEmpty';
10
17
  import { markMessageRevoked, useMessageStore } from '../store/message';
18
+ import { syncPinnedMessagesOnEvent } from '../hooks/message/usePinMessage';
11
19
 
12
20
  export const useChatListener = () => {
13
21
  const updateOneMessage = useMessageStore((state) => state.updateOneMessage);
22
+ const currentUserId = useUserStore((s) => s.user?.userID);
23
+ const onPressFlashMessage = useChatContext()?.onPressFlashMessage;
24
+ const isShowFLashMessage = useChatContext()?.isShowFLashMessage;
14
25
 
15
26
  const onSendMessageProgress = useCallback(
16
27
  ({ progress, message }: { progress: number; message: MessageItem }) => {
@@ -26,20 +37,39 @@ export const useChatListener = () => {
26
37
 
27
38
  const onConversationChanged = useCallback(
28
39
  (conversations: ConversationItem[]) => {
29
- console.log('[Listener] OnConversationChanged', {
30
- count: conversations.length,
31
- ids: conversations.map((c) => c.conversationID),
32
- });
40
+ // console.log('isShowFLashMessage', isShowFLashMessage);
33
41
  useConversationStore.getState().updateConversations(conversations);
42
+ if (isShowFLashMessage) {
43
+ for (const conversation of conversations) {
44
+ if (
45
+ conversation.recvMsgOpt === MessageReceiveOptType.NotNotify &&
46
+ !isEmpty(conversation?.latestMsg)
47
+ ) {
48
+ continue;
49
+ }
50
+ const latestMsg = JSON.parse(conversation.latestMsg || '{}');
51
+ const lastMessageText = getLastMessageText(
52
+ latestMsg,
53
+ currentUserId,
54
+ conversation
55
+ );
56
+ ToastFlashMessage.show({
57
+ key: conversation.conversationID,
58
+ title: conversation.showName || 'New Message',
59
+ body: lastMessageText,
60
+ onPress: () => {
61
+ ToastFlashMessage.hide(conversation.conversationID);
62
+ onPressFlashMessage?.(conversation);
63
+ },
64
+ });
65
+ }
66
+ }
34
67
  },
35
- []
68
+ [currentUserId, isShowFLashMessage, onPressFlashMessage]
36
69
  );
37
70
 
38
71
  const onNewConversation = useCallback((conversations: ConversationItem[]) => {
39
- console.log('[Listener] OnNewConversation', {
40
- count: conversations.length,
41
- ids: conversations.map((c) => c.conversationID),
42
- });
72
+ console.log('[Listener] OnNewConversation', conversations);
43
73
  useConversationStore.getState().updateConversations(conversations);
44
74
  }, []);
45
75
 
@@ -61,10 +91,32 @@ export const useChatListener = () => {
61
91
  markMessageRevoked(revokedInfo.clientMsgID);
62
92
  }, []);
63
93
 
94
+ const onMessagePinned = useCallback(
95
+ (messagePinned: MessagePinned) => {
96
+ const currentConversationId =
97
+ useConversationStore.getState().currentConversationId;
98
+ if (messagePinned.conversationID === currentConversationId) {
99
+ updateOneMessage({
100
+ clientMsgID: messagePinned.clientMsgID,
101
+ isPinned: messagePinned.isPinned,
102
+ pinnedByUserID: messagePinned.isPinned
103
+ ? messagePinned.operatorUserID
104
+ : undefined,
105
+ pinnedTime: messagePinned.isPinned
106
+ ? messagePinned.pinnedTime
107
+ : undefined,
108
+ });
109
+ }
110
+ syncPinnedMessagesOnEvent(messagePinned.conversationID);
111
+ },
112
+ [updateOneMessage]
113
+ );
114
+
64
115
  useEffect(() => {
65
116
  // Conversation
66
117
  OpenIMSDK.on(OpenIMEvent.OnConversationChanged, onConversationChanged);
67
118
  OpenIMSDK.on(OpenIMEvent.OnNewConversation, onNewConversation);
119
+ // OpenIMSDK.on(OpenIMEvent.OnRecvNewMessages, onRecvNewMessages);
68
120
 
69
121
  // Group members
70
122
  OpenIMSDK.on(OpenIMEvent.OnGroupMemberAdded, onGroupMemberAdded);
@@ -73,6 +125,7 @@ export const useChatListener = () => {
73
125
  // Message status
74
126
  OpenIMSDK.on(OpenIMEvent.SendMessageProgress, onSendMessageProgress);
75
127
  OpenIMSDK.on(OpenIMEvent.OnNewRecvMessageRevoked, onMessageRevoked);
128
+ OpenIMSDK.on(OpenIMEvent.OnRecvMessagePinned, onMessagePinned);
76
129
 
77
130
  return () => {
78
131
  // Conversation
@@ -85,8 +138,17 @@ export const useChatListener = () => {
85
138
 
86
139
  // Message status
87
140
  OpenIMSDK.off(OpenIMEvent.SendMessageProgress, onSendMessageProgress);
141
+ // OpenIMSDK.off(OpenIMEvent.OnRecvNewMessages, onRecvNewMessages);
88
142
  OpenIMSDK.off(OpenIMEvent.OnNewRecvMessageRevoked, onMessageRevoked);
143
+ OpenIMSDK.off(OpenIMEvent.OnRecvMessagePinned, onMessagePinned);
89
144
  };
90
- // eslint-disable-next-line react-hooks/exhaustive-deps
91
- }, []);
145
+ }, [
146
+ onConversationChanged,
147
+ onGroupMemberAdded,
148
+ onGroupMemberDeleted,
149
+ onMessagePinned,
150
+ onMessageRevoked,
151
+ onNewConversation,
152
+ onSendMessageProgress,
153
+ ]);
92
154
  };
@@ -0,0 +1,153 @@
1
+ import { useCallback, useEffect } from 'react';
2
+ import OpenIMSDK from '@droppii/openim-rn-client-sdk';
3
+ import type { MessageItem } from '@droppii/openim-rn-client-sdk';
4
+ import { useConversationStore } from '../../store/conversation';
5
+ import { useMessageStore } from '../../store/message';
6
+ import { usePinnedMessageStore } from '../../store/pinnedMessage';
7
+ import { useUserStore } from '../../store/user';
8
+ import { UIUtils } from '../../utils/UIUtils';
9
+ import { trans } from '../../translation';
10
+
11
+ const MAX_PINNED_MESSAGES = 5;
12
+
13
+ export const fetchPinnedMessages = async (conversationID: string) => {
14
+ const result = await OpenIMSDK.getPinnedMessageList({
15
+ conversationID,
16
+ offset: 0,
17
+ pageSize: MAX_PINNED_MESSAGES,
18
+ });
19
+
20
+ const previouslyPinnedIds = new Set(
21
+ usePinnedMessageStore.getState().messages.map((msg) => msg.clientMsgID)
22
+ );
23
+ const pinnedIds = new Set(result.messageList.map((msg) => msg.clientMsgID));
24
+
25
+ usePinnedMessageStore
26
+ .getState()
27
+ .setMessages(result.messageList, result.totalCount);
28
+
29
+ // Reconcile the per-message `isPinned` flag (used by the toolbox and the
30
+ // pinned badge) with the authoritative list from the server — messages
31
+ // pinned outside this session (before remount, or from another device)
32
+ // never get this flag set otherwise.
33
+ const { updateOneMessage } = useMessageStore.getState();
34
+ pinnedIds.forEach((clientMsgID) => {
35
+ updateOneMessage({ clientMsgID, isPinned: true });
36
+ });
37
+ previouslyPinnedIds.forEach((clientMsgID) => {
38
+ if (!pinnedIds.has(clientMsgID)) {
39
+ updateOneMessage({ clientMsgID, isPinned: false });
40
+ }
41
+ });
42
+ };
43
+
44
+ const showPinLimitReachedModal = () => {
45
+ UIUtils.alert.open({
46
+ title: trans('chat:pin_limit_title'),
47
+ message: trans('chat:pin_limit_desc'),
48
+ primaryIndex: 0,
49
+ buttons: [
50
+ {
51
+ label: trans('chat:pin_limit_primary'),
52
+ kind: 'primary',
53
+ onPress: () => {},
54
+ },
55
+ ],
56
+ });
57
+ };
58
+
59
+ export const usePinMessage = (conversationID?: string) => {
60
+ const pinnedMessages = usePinnedMessageStore((state) => state.messages);
61
+ const addMessage = usePinnedMessageStore((state) => state.addMessage);
62
+ const removeMessage = usePinnedMessageStore((state) => state.removeMessage);
63
+ const reset = usePinnedMessageStore((state) => state.reset);
64
+
65
+ useEffect(() => {
66
+ if (!conversationID) return;
67
+
68
+ fetchPinnedMessages(conversationID).catch((error) => {
69
+ console.error('fetchPinnedMessages', error);
70
+ });
71
+
72
+ return () => {
73
+ reset();
74
+ };
75
+ }, [conversationID, reset]);
76
+
77
+ const pinMessage = useCallback(
78
+ async (message: MessageItem) => {
79
+ if (!conversationID) return;
80
+
81
+ if (pinnedMessages.length >= MAX_PINNED_MESSAGES) {
82
+ showPinLimitReachedModal();
83
+ return;
84
+ }
85
+
86
+ try {
87
+ await OpenIMSDK.pinMsg(conversationID, message.clientMsgID);
88
+ addMessage(message);
89
+ useMessageStore.getState().updateOneMessage({
90
+ clientMsgID: message.clientMsgID,
91
+ isPinned: true,
92
+ pinnedByUserID: useUserStore.getState().user?.userID,
93
+ pinnedTime: Date.now(),
94
+ });
95
+ UIUtils.toast.open({
96
+ title: trans('chat:pin_message_success'),
97
+ theme: 'success',
98
+ });
99
+ } catch (error) {
100
+ console.error('pinMessage', error);
101
+ UIUtils.toast.open({
102
+ title: trans('chat:generic_error'),
103
+ theme: 'error',
104
+ });
105
+ }
106
+ },
107
+ [conversationID, pinnedMessages.length, addMessage]
108
+ );
109
+
110
+ const unpinMessage = useCallback(
111
+ async (message: MessageItem) => {
112
+ if (!conversationID) return;
113
+
114
+ try {
115
+ await OpenIMSDK.unpinMsg(conversationID, message.clientMsgID);
116
+ removeMessage(message.clientMsgID);
117
+ useMessageStore.getState().updateOneMessage({
118
+ clientMsgID: message.clientMsgID,
119
+ isPinned: false,
120
+ pinnedByUserID: undefined,
121
+ pinnedTime: undefined,
122
+ });
123
+ UIUtils.toast.open({
124
+ title: trans('chat:unpin_message_success'),
125
+ theme: 'success',
126
+ });
127
+ } catch (error) {
128
+ console.error('unpinMessage', error);
129
+ UIUtils.toast.open({
130
+ title: trans('chat:generic_error'),
131
+ theme: 'error',
132
+ });
133
+ }
134
+ },
135
+ [conversationID, removeMessage]
136
+ );
137
+
138
+ return {
139
+ pinnedMessages,
140
+ pinMessage,
141
+ unpinMessage,
142
+ };
143
+ };
144
+
145
+ export const syncPinnedMessagesOnEvent = (conversationID: string) => {
146
+ const currentConversationId =
147
+ useConversationStore.getState().currentConversationId;
148
+ if (conversationID !== currentConversationId) return;
149
+
150
+ fetchPinnedMessages(conversationID).catch((error) => {
151
+ console.error('syncPinnedMessagesOnEvent', error);
152
+ });
153
+ };
@@ -1,5 +1,6 @@
1
1
  import { useCallback } from 'react';
2
2
  import { useConversationStore } from '../../store/conversation';
3
+ import { useUserStore } from '../../store/user';
3
4
  import type {
4
5
  CustomMsgParams,
5
6
  MessageItem,
@@ -50,15 +51,15 @@ export const useSendMessage = () => {
50
51
  pushNewMessage({ ...message, status: MessageStatus.Sending });
51
52
 
52
53
  try {
53
- const sent = await OpenIMSDK.sendMessage(
54
- buildSendParams(
55
- message,
56
- recvID,
57
- groupID,
58
- extendMessageInfo,
59
- plainText
60
- )
54
+ const sendParams = buildSendParams(
55
+ message,
56
+ recvID,
57
+ groupID,
58
+ extendMessageInfo,
59
+ plainText
61
60
  );
61
+ console.log('[useSendMessage] dispatchSend params', sendParams);
62
+ const sent = await OpenIMSDK.sendMessage(sendParams);
62
63
  deleteOneMessage(message.clientMsgID);
63
64
  pushNewMessage(sent);
64
65
  } catch {
@@ -162,6 +163,7 @@ export const useSendMessage = () => {
162
163
  recvID: recvID || '',
163
164
  groupID: groupID || '',
164
165
  message,
166
+ offlinePushInfo: generateOfflinePushInfo(message.contentType, ''),
165
167
  };
166
168
 
167
169
  try {
@@ -208,13 +210,14 @@ export const useSendMessage = () => {
208
210
  };
209
211
  };
210
212
 
211
- const generateOfflinePushInfo = (
213
+ export const generateOfflinePushInfo = (
212
214
  contentType: MessageType,
213
215
  plainText: string
214
216
  ) => {
215
217
  const conversationData = useConversationStore
216
218
  ?.getState?.()
217
219
  ?.getCurrentConversation();
220
+ const operatorUserID = useUserStore.getState().user?.userID || '';
218
221
  const title = conversationData?.showName || 'Droppii';
219
222
  const desc = generateContentBasedOnMessageType(contentType, plainText);
220
223
  return {
@@ -223,6 +226,7 @@ const generateOfflinePushInfo = (
223
226
  ex: JSON.stringify({
224
227
  icon: conversationData?.faceURL || '',
225
228
  conversationId: conversationData?.conversationID || '',
229
+ operatorUserID,
226
230
  title,
227
231
  desc,
228
232
  }),