@developer_tribe/react-native-comnyx 0.15.0 → 0.16.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (210) hide show
  1. package/Comnyx.podspec +10 -2
  2. package/README.md +50 -0
  3. package/android/build.gradle +1 -0
  4. package/android/consumer-rules.pro +23 -0
  5. package/android/generated/java/com/comnyx/NativeComnyxSpec.java +46 -0
  6. package/android/generated/jni/RNComnyxSpec-generated.cpp +23 -1
  7. package/android/generated/jni/RNComnyxSpec.h +7 -0
  8. package/android/generated/jni/react/renderer/components/RNComnyxSpec/RNComnyxSpecJSI-generated.cpp +21 -0
  9. package/android/generated/jni/react/renderer/components/RNComnyxSpec/RNComnyxSpecJSI.h +70 -0
  10. package/android/src/main/AndroidManifest.xml +11 -1
  11. package/android/src/main/AndroidManifestNew.xml +11 -1
  12. package/android/src/main/java/com/comnyx/ComnyxMediaPickerModule.kt +91 -51
  13. package/android/src/main/java/com/comnyx/ComnyxModule.kt +7 -0
  14. package/android/src/main/java/com/comnyx/src/messaging/firebase/FirebaseMessagingService.kt +4 -6
  15. package/android/src/main/res/xml/comnyx_file_paths.xml +12 -0
  16. package/ios/APNService.swift +9 -9
  17. package/ios/Comnyx.swift +17 -8
  18. package/ios/ComnyxMediaPicker.swift +47 -26
  19. package/ios/ComnyxMessaging.swift +2 -0
  20. package/ios/PrivacyInfo.xcprivacy +32 -0
  21. package/ios/comnyx_post_install.rb +25 -0
  22. package/ios/generated/RCTAppDependencyProvider.h +25 -0
  23. package/ios/generated/RCTAppDependencyProvider.mm +55 -0
  24. package/ios/generated/RCTModulesConformingToProtocolsProvider.h +18 -0
  25. package/ios/generated/RCTModulesConformingToProtocolsProvider.mm +33 -0
  26. package/ios/generated/RCTThirdPartyComponentsProvider.h +16 -0
  27. package/ios/generated/RCTThirdPartyComponentsProvider.mm +23 -0
  28. package/ios/generated/RNComnyxSpec/RNComnyxSpec-generated.mm +53 -0
  29. package/ios/generated/RNComnyxSpec/RNComnyxSpec.h +67 -0
  30. package/ios/generated/RNComnyxSpecJSI-generated.cpp +38 -0
  31. package/ios/generated/RNComnyxSpecJSI.h +89 -0
  32. package/ios/generated/ReactAppDependencyProvider.podspec +34 -0
  33. package/lib/commonjs/NativeComnyxMediaPicker.js +19 -0
  34. package/lib/commonjs/NativeComnyxMediaPicker.js.map +1 -1
  35. package/lib/commonjs/api/conversations.js +6 -6
  36. package/lib/commonjs/api/conversations.js.map +1 -1
  37. package/lib/commonjs/api/customers.js +3 -2
  38. package/lib/commonjs/api/customers.js.map +1 -1
  39. package/lib/commonjs/api/media.js +20 -6
  40. package/lib/commonjs/api/media.js.map +1 -1
  41. package/lib/commonjs/api/messages.js +3 -2
  42. package/lib/commonjs/api/messages.js.map +1 -1
  43. package/lib/commonjs/components/ChatList.js +132 -90
  44. package/lib/commonjs/components/ChatList.js.map +1 -1
  45. package/lib/commonjs/components/ComnyxErrorBoundary.js +92 -0
  46. package/lib/commonjs/components/ComnyxErrorBoundary.js.map +1 -0
  47. package/lib/commonjs/components/CustomerForm.js +7 -3
  48. package/lib/commonjs/components/CustomerForm.js.map +1 -1
  49. package/lib/commonjs/components/InitFailed.js +77 -21
  50. package/lib/commonjs/components/InitFailed.js.map +1 -1
  51. package/lib/commonjs/components/MediaMessageItem.js +37 -10
  52. package/lib/commonjs/components/MediaMessageItem.js.map +1 -1
  53. package/lib/commonjs/components/MediaViewerModal.js +16 -3
  54. package/lib/commonjs/components/MediaViewerModal.js.map +1 -1
  55. package/lib/commonjs/components/MessageInput.js +83 -15
  56. package/lib/commonjs/components/MessageInput.js.map +1 -1
  57. package/lib/commonjs/components/MessageItem.js +1 -1
  58. package/lib/commonjs/components/MessageItem.js.map +1 -1
  59. package/lib/commonjs/hooks/usePolling.js +30 -21
  60. package/lib/commonjs/hooks/usePolling.js.map +1 -1
  61. package/lib/commonjs/hooks/useThemeColors.js +12 -1
  62. package/lib/commonjs/hooks/useThemeColors.js.map +1 -1
  63. package/lib/commonjs/index.js +6 -0
  64. package/lib/commonjs/index.js.map +1 -1
  65. package/lib/commonjs/notifications/initializeNotifications.js +19 -16
  66. package/lib/commonjs/notifications/initializeNotifications.js.map +1 -1
  67. package/lib/commonjs/register/Accumulator.js +19 -6
  68. package/lib/commonjs/register/Accumulator.js.map +1 -1
  69. package/lib/commonjs/register/collectData.js +1 -1
  70. package/lib/commonjs/register/collectData.js.map +1 -1
  71. package/lib/commonjs/register/login.js +5 -0
  72. package/lib/commonjs/register/login.js.map +1 -1
  73. package/lib/commonjs/store/store.js +6 -0
  74. package/lib/commonjs/store/store.js.map +1 -1
  75. package/lib/commonjs/support/ComnyxSupport.js +77 -16
  76. package/lib/commonjs/support/ComnyxSupport.js.map +1 -1
  77. package/lib/commonjs/support/SupportConfigContext.js +66 -0
  78. package/lib/commonjs/support/SupportConfigContext.js.map +1 -0
  79. package/lib/commonjs/support/index.js +7 -0
  80. package/lib/commonjs/support/index.js.map +1 -1
  81. package/lib/commonjs/types/Theme.js +30 -2
  82. package/lib/commonjs/types/Theme.js.map +1 -1
  83. package/lib/commonjs/version.js +1 -1
  84. package/lib/module/NativeComnyxMediaPicker.js +18 -0
  85. package/lib/module/NativeComnyxMediaPicker.js.map +1 -1
  86. package/lib/module/api/conversations.js +6 -6
  87. package/lib/module/api/conversations.js.map +1 -1
  88. package/lib/module/api/customers.js +3 -2
  89. package/lib/module/api/customers.js.map +1 -1
  90. package/lib/module/api/media.js +21 -6
  91. package/lib/module/api/media.js.map +1 -1
  92. package/lib/module/api/messages.js +3 -2
  93. package/lib/module/api/messages.js.map +1 -1
  94. package/lib/module/components/ChatList.js +133 -91
  95. package/lib/module/components/ChatList.js.map +1 -1
  96. package/lib/module/components/ComnyxErrorBoundary.js +87 -0
  97. package/lib/module/components/ComnyxErrorBoundary.js.map +1 -0
  98. package/lib/module/components/CustomerForm.js +7 -3
  99. package/lib/module/components/CustomerForm.js.map +1 -1
  100. package/lib/module/components/InitFailed.js +79 -23
  101. package/lib/module/components/InitFailed.js.map +1 -1
  102. package/lib/module/components/MediaMessageItem.js +37 -11
  103. package/lib/module/components/MediaMessageItem.js.map +1 -1
  104. package/lib/module/components/MediaViewerModal.js +15 -3
  105. package/lib/module/components/MediaViewerModal.js.map +1 -1
  106. package/lib/module/components/MessageInput.js +84 -16
  107. package/lib/module/components/MessageInput.js.map +1 -1
  108. package/lib/module/components/MessageItem.js +1 -1
  109. package/lib/module/components/MessageItem.js.map +1 -1
  110. package/lib/module/hooks/usePolling.js +30 -21
  111. package/lib/module/hooks/usePolling.js.map +1 -1
  112. package/lib/module/hooks/useThemeColors.js +13 -2
  113. package/lib/module/hooks/useThemeColors.js.map +1 -1
  114. package/lib/module/index.js +1 -0
  115. package/lib/module/index.js.map +1 -1
  116. package/lib/module/notifications/initializeNotifications.js +19 -16
  117. package/lib/module/notifications/initializeNotifications.js.map +1 -1
  118. package/lib/module/register/Accumulator.js +19 -6
  119. package/lib/module/register/Accumulator.js.map +1 -1
  120. package/lib/module/register/collectData.js +1 -1
  121. package/lib/module/register/collectData.js.map +1 -1
  122. package/lib/module/register/login.js +5 -0
  123. package/lib/module/register/login.js.map +1 -1
  124. package/lib/module/store/store.js +6 -0
  125. package/lib/module/store/store.js.map +1 -1
  126. package/lib/module/support/ComnyxSupport.js +79 -18
  127. package/lib/module/support/ComnyxSupport.js.map +1 -1
  128. package/lib/module/support/SupportConfigContext.js +59 -0
  129. package/lib/module/support/SupportConfigContext.js.map +1 -0
  130. package/lib/module/support/index.js +1 -0
  131. package/lib/module/support/index.js.map +1 -1
  132. package/lib/module/types/Theme.js +30 -2
  133. package/lib/module/types/Theme.js.map +1 -1
  134. package/lib/module/version.js +1 -1
  135. package/lib/typescript/src/NativeComnyxMediaPicker.d.ts +9 -0
  136. package/lib/typescript/src/NativeComnyxMediaPicker.d.ts.map +1 -1
  137. package/lib/typescript/src/api/conversations.d.ts +2 -2
  138. package/lib/typescript/src/api/conversations.d.ts.map +1 -1
  139. package/lib/typescript/src/api/customers.d.ts +1 -1
  140. package/lib/typescript/src/api/customers.d.ts.map +1 -1
  141. package/lib/typescript/src/api/media.d.ts +3 -3
  142. package/lib/typescript/src/api/media.d.ts.map +1 -1
  143. package/lib/typescript/src/api/messages.d.ts +1 -1
  144. package/lib/typescript/src/api/messages.d.ts.map +1 -1
  145. package/lib/typescript/src/components/ChatList.d.ts.map +1 -1
  146. package/lib/typescript/src/components/ComnyxErrorBoundary.d.ts +18 -0
  147. package/lib/typescript/src/components/ComnyxErrorBoundary.d.ts.map +1 -0
  148. package/lib/typescript/src/components/CustomerForm.d.ts.map +1 -1
  149. package/lib/typescript/src/components/InitFailed.d.ts +5 -2
  150. package/lib/typescript/src/components/InitFailed.d.ts.map +1 -1
  151. package/lib/typescript/src/components/MediaMessageItem.d.ts.map +1 -1
  152. package/lib/typescript/src/components/MediaViewerModal.d.ts.map +1 -1
  153. package/lib/typescript/src/components/MessageInput.d.ts.map +1 -1
  154. package/lib/typescript/src/components/MessageItem.d.ts.map +1 -1
  155. package/lib/typescript/src/hooks/usePolling.d.ts.map +1 -1
  156. package/lib/typescript/src/hooks/useThemeColors.d.ts.map +1 -1
  157. package/lib/typescript/src/index.d.ts +3 -0
  158. package/lib/typescript/src/index.d.ts.map +1 -1
  159. package/lib/typescript/src/notifications/initializeNotifications.d.ts.map +1 -1
  160. package/lib/typescript/src/register/Accumulator.d.ts.map +1 -1
  161. package/lib/typescript/src/register/collectData.d.ts +4 -1
  162. package/lib/typescript/src/register/collectData.d.ts.map +1 -1
  163. package/lib/typescript/src/register/login.d.ts.map +1 -1
  164. package/lib/typescript/src/store/store.d.ts +6 -2
  165. package/lib/typescript/src/store/store.d.ts.map +1 -1
  166. package/lib/typescript/src/support/ComnyxSupport.d.ts +80 -3
  167. package/lib/typescript/src/support/ComnyxSupport.d.ts.map +1 -1
  168. package/lib/typescript/src/support/SupportConfigContext.d.ts +98 -0
  169. package/lib/typescript/src/support/SupportConfigContext.d.ts.map +1 -0
  170. package/lib/typescript/src/support/index.d.ts +2 -0
  171. package/lib/typescript/src/support/index.d.ts.map +1 -1
  172. package/lib/typescript/src/types/Conversation.d.ts +2 -2
  173. package/lib/typescript/src/types/Conversation.d.ts.map +1 -1
  174. package/lib/typescript/src/types/Customer.d.ts +1 -1
  175. package/lib/typescript/src/types/Customer.d.ts.map +1 -1
  176. package/lib/typescript/src/types/MessageResponse.d.ts +7 -4
  177. package/lib/typescript/src/types/MessageResponse.d.ts.map +1 -1
  178. package/lib/typescript/src/types/Theme.d.ts +26 -0
  179. package/lib/typescript/src/types/Theme.d.ts.map +1 -1
  180. package/lib/typescript/src/version.d.ts +1 -1
  181. package/package.json +19 -30
  182. package/src/NativeComnyxMediaPicker.ts +18 -0
  183. package/src/api/conversations.ts +6 -4
  184. package/src/api/customers.ts +3 -1
  185. package/src/api/media.ts +32 -10
  186. package/src/api/messages.ts +3 -1
  187. package/src/components/ChatList.tsx +147 -99
  188. package/src/components/ComnyxErrorBoundary.tsx +91 -0
  189. package/src/components/CustomerForm.tsx +7 -3
  190. package/src/components/InitFailed.tsx +80 -16
  191. package/src/components/MediaMessageItem.tsx +48 -11
  192. package/src/components/MediaViewerModal.tsx +21 -8
  193. package/src/components/MessageInput.tsx +108 -17
  194. package/src/components/MessageItem.tsx +12 -13
  195. package/src/hooks/usePolling.ts +26 -11
  196. package/src/hooks/useThemeColors.ts +11 -2
  197. package/src/index.ts +16 -0
  198. package/src/notifications/initializeNotifications.ts +22 -20
  199. package/src/register/Accumulator.ts +26 -9
  200. package/src/register/collectData.ts +10 -2
  201. package/src/register/login.ts +5 -0
  202. package/src/store/store.ts +11 -3
  203. package/src/support/ComnyxSupport.tsx +172 -23
  204. package/src/support/SupportConfigContext.tsx +157 -0
  205. package/src/support/index.ts +11 -0
  206. package/src/types/Conversation.ts +2 -2
  207. package/src/types/Customer.ts +1 -2
  208. package/src/types/MessageResponse.ts +4 -4
  209. package/src/types/Theme.ts +38 -0
  210. package/src/version.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@developer_tribe/react-native-comnyx",
3
- "version": "0.15.0",
3
+ "version": "0.16.1",
4
4
  "description": "React Native chat component with integrated support panel, enabling real-time customer communication and efficient agent workflow management.",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./src/index.ts",
@@ -8,27 +8,23 @@
8
8
  "types": "./lib/typescript/src/index.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "import": {
12
- "types": "./lib/typescript/src/index.d.ts",
13
- "default": "./lib/module/index.js"
14
- },
15
- "require": {
16
- "types": "./lib/typescript/src/index.d.ts",
17
- "default": "./lib/commonjs/index.js"
18
- }
11
+ "source": "./src/index.ts",
12
+ "types": "./lib/typescript/src/index.d.ts",
13
+ "import": "./lib/module/index.js",
14
+ "require": "./lib/commonjs/index.js"
19
15
  }
20
16
  },
21
17
  "files": [
22
18
  "src",
23
19
  "lib",
24
20
  "android",
21
+ "android/consumer-rules.pro",
25
22
  "ios",
26
23
  "cpp",
27
24
  "*.podspec",
28
25
  "react-native.config.js",
29
26
  "!node_modules",
30
27
  "!example",
31
- "!example820",
32
28
  "!server-scripts",
33
29
  "!ios/build",
34
30
  "!android/build",
@@ -70,13 +66,14 @@
70
66
  },
71
67
  "devDependencies": {
72
68
  "@commitlint/config-conventional": "^19.6.0",
69
+ "@d11/react-native-fast-image": "^8.13.0",
73
70
  "@evilmartians/lefthook": "^1.5.0",
74
71
  "@react-native-community/cli": "15.0.1",
75
72
  "@react-native/eslint-config": "^0.73.1",
76
73
  "@release-it/conventional-changelog": "^9.0.2",
77
74
  "@testing-library/react-native": "^13.2.0",
78
75
  "@types/jest": "^29.5.5",
79
- "@types/react": "^18.2.44",
76
+ "@types/react": "^19.2.0",
80
77
  "axios": "1.10.0",
81
78
  "commitlint": "^19.6.1",
82
79
  "del-cli": "^5.1.0",
@@ -85,37 +82,29 @@
85
82
  "eslint-plugin-prettier": "^5.0.1",
86
83
  "jest": "^29.7.0",
87
84
  "prettier": "^3.0.3",
85
+ "react-hook-form": "^7.66.0",
86
+ "react-native": "^0.85.1",
88
87
  "react-native-builder-bob": "^0.33.1",
88
+ "react-native-mmkv": "^4.3.1",
89
+ "react-native-safe-area-context": "^5.5.2",
89
90
  "release-it": "^17.10.0",
90
91
  "ts-jest": "^29.4.5",
91
92
  "ts-node": "^10.9.2",
92
93
  "typescript": "5.1.6",
93
94
  "use-sync-external-store": "^1.5.0",
94
- "zustand": "^5.0.3",
95
- "react-hook-form": "^7.66.0",
96
- "react-native-mmkv": "^4.0.0",
97
- "react-native-nitro-modules": "^0.31.4",
98
- "react-native-safe-area-context": "^5.5.2",
99
- "react-native": "^0.82.1"
95
+ "zustand": "^5.0.3"
100
96
  },
101
97
  "resolutions": {
102
- "@types/react": "^18.2.44",
103
- "react": "19.1.1"
98
+ "@types/react": "^19.2.0",
99
+ "react": "19.2.3"
104
100
  },
105
101
  "peerDependencies": {
102
+ "@d11/react-native-fast-image": ">=8.6.0",
106
103
  "react": ">=19.0.0",
104
+ "react-hook-form": ">=7.66.0",
107
105
  "react-native": ">=0.81.0",
108
106
  "react-native-mmkv": ">=4.0.0",
109
- "react-native-nitro-modules": ">=0.31.4",
110
- "react-native-safe-area-context": ">=5.5.2",
111
- "react-hook-form": ">=7.66.0"
112
- },
113
- "jest": {
114
- "preset": "react-native",
115
- "modulePathIgnorePatterns": [
116
- "<rootDir>/example/node_modules",
117
- "<rootDir>/lib/"
118
- ]
107
+ "react-native-safe-area-context": ">=5.5.2"
119
108
  },
120
109
  "commitlint": {
121
110
  "extends": [
@@ -201,7 +190,7 @@
201
190
  ]
202
191
  },
203
192
  "engines": {
204
- "node": ">=20.0.0"
193
+ "node": ">=22.11.0"
205
194
  },
206
195
  "dependencies": {},
207
196
  "packageManager": "yarn@1.22.19+sha512.ff4579ab459bb25aa7c0ff75b62acebe576f6084b36aa842971cf250a5d8c6cd3bc9420b22ce63c7f93a0857bc6ef29291db39c3e7a23aab5adfd5a4dd6c5d71"
@@ -75,6 +75,24 @@ export async function deleteTempFile(uri: string): Promise<void> {
75
75
  return ComnyxMediaPicker.deleteTempFile(uri);
76
76
  }
77
77
 
78
+ /**
79
+ * Android only. Converts a local file URI returned by the picker into a
80
+ * `content://` URI served by the Comnyx FileProvider, suitable for crossing
81
+ * process boundaries (e.g. sharing to another app, system ACTION_VIEW).
82
+ *
83
+ * On iOS, returns the input URI unchanged since iOS does not have the
84
+ * FileUriExposedException problem.
85
+ */
86
+ export async function getShareableUri(fileUri: string): Promise<string> {
87
+ if (!ComnyxMediaPicker) {
88
+ return fileUri;
89
+ }
90
+ if (typeof ComnyxMediaPicker.getShareableUri !== 'function') {
91
+ return fileUri;
92
+ }
93
+ return ComnyxMediaPicker.getShareableUri(fileUri);
94
+ }
95
+
78
96
  export async function cleanupTempFiles(): Promise<void> {
79
97
  if (!ComnyxMediaPicker) {
80
98
  return;
@@ -13,7 +13,8 @@ export function getCustomerConversation(
13
13
  externalId: string,
14
14
  created_at: Date | undefined,
15
15
  page: number = 0,
16
- options: ApiOptions & { per_page?: number }
16
+ options: ApiOptions & { per_page?: number },
17
+ signal?: AbortSignal
17
18
  ): Promise<ConversationResponse> {
18
19
  if (options.fake) {
19
20
  return getFakePaginatedConversationResponse(
@@ -25,10 +26,10 @@ export function getCustomerConversation(
25
26
  .get<ConversationResponse>(`/api/customers/${externalId}/conversation`, {
26
27
  params: {
27
28
  page,
28
- // per_page: PER_PAGE,
29
29
  getOld: 1,
30
30
  getFrom: dateToUnixTimestamp(created_at),
31
31
  },
32
+ signal,
32
33
  })
33
34
  .then((res) => res.data);
34
35
  }
@@ -36,7 +37,8 @@ export function getCustomerConversation(
36
37
  export function getNewCustomerConversation(
37
38
  externalId: string,
38
39
  created_at: Date | undefined,
39
- options: ApiOptions
40
+ options: ApiOptions,
41
+ signal?: AbortSignal
40
42
  ): Promise<ConversationResponse> {
41
43
  if (options.fake) {
42
44
  return getFakeConversationResponse(25, 0, 0, true);
@@ -45,9 +47,9 @@ export function getNewCustomerConversation(
45
47
  .get<ConversationResponse>(`/api/customers/${externalId}/conversation`, {
46
48
  params: {
47
49
  page: 1,
48
- // per_page: 25,
49
50
  getFrom: dateToUnixTimestamp(created_at),
50
51
  },
52
+ signal,
51
53
  })
52
54
  .then((res) => res.data);
53
55
  }
@@ -4,7 +4,8 @@ import { axiosInstance } from './api';
4
4
  // NOTE: This is not a REST API endpoint. Data is collected with debounce and sent to the server at an appropriate time.
5
5
  export function updateCustomer(
6
6
  customerData: CreateCustomerRequest,
7
- externalId?: string
7
+ externalId?: string,
8
+ signal?: AbortSignal
8
9
  ): Promise<{ customer: Customer }> {
9
10
  console.info('[Comnyx] Adding customer info');
10
11
  return axiosInstance
@@ -12,6 +13,7 @@ export function updateCustomer(
12
13
  headers: {
13
14
  'external-id': externalId,
14
15
  },
16
+ signal,
15
17
  })
16
18
  .then((res) => res.data);
17
19
  }
package/src/api/media.ts CHANGED
@@ -9,19 +9,28 @@ import {
9
9
  getFakeMediaMessageResponse,
10
10
  } from '../data/fake/media';
11
11
 
12
+ // React Native's XMLHttpRequest.send accepts this shape to stream a file URI
13
+ // without loading it into memory. Not in lib.dom, so typed locally.
14
+ type RNXHRFile = { uri: string; type: string; name: string };
15
+
12
16
  export function getUploadUrl(
13
17
  fileName: string,
14
18
  contentType: string,
15
- options: ApiOptions
19
+ options: ApiOptions,
20
+ signal?: AbortSignal
16
21
  ): Promise<UploadUrlResponse> {
17
22
  if (options.fake) {
18
23
  return getFakeUploadUrlResponse(fileName);
19
24
  }
20
25
  return axiosInstance
21
- .post<UploadUrlResponse>('/api/media/presign', {
22
- fileName,
23
- fileType: contentType,
24
- })
26
+ .post<UploadUrlResponse>(
27
+ '/api/media/presign',
28
+ {
29
+ fileName,
30
+ fileType: contentType,
31
+ },
32
+ { signal }
33
+ )
25
34
  .then((res) => res.data);
26
35
  }
27
36
 
@@ -30,14 +39,23 @@ export function uploadFileToS3(
30
39
  fileUri: string,
31
40
  contentType: string,
32
41
  onProgress?: (percentage: number) => void,
33
- options?: ApiOptions
42
+ options?: ApiOptions,
43
+ signal?: AbortSignal
34
44
  ): Promise<void> {
35
45
  if (options?.fake) {
36
46
  return fakeUploadToS3(onProgress);
37
47
  }
38
48
 
39
49
  return new Promise((resolve, reject) => {
50
+ if (signal?.aborted) {
51
+ reject(new Error('Upload aborted'));
52
+ return;
53
+ }
54
+
40
55
  const xhr = new XMLHttpRequest();
56
+ const onAbort = () => xhr.abort();
57
+ signal?.addEventListener('abort', onAbort);
58
+ const cleanup = () => signal?.removeEventListener('abort', onAbort);
41
59
 
42
60
  xhr.upload.addEventListener('progress', (event) => {
43
61
  if (event.lengthComputable && onProgress) {
@@ -50,6 +68,7 @@ export function uploadFileToS3(
50
68
  });
51
69
 
52
70
  xhr.addEventListener('load', () => {
71
+ cleanup();
53
72
  if (xhr.status >= 200 && xhr.status < 300) {
54
73
  resolve();
55
74
  } else {
@@ -59,6 +78,7 @@ export function uploadFileToS3(
59
78
  });
60
79
 
61
80
  xhr.addEventListener('error', () => {
81
+ cleanup();
62
82
  console.error(
63
83
  '[Comnyx] Upload XHR error, status:',
64
84
  xhr.status,
@@ -69,20 +89,20 @@ export function uploadFileToS3(
69
89
  });
70
90
 
71
91
  xhr.addEventListener('abort', () => {
92
+ cleanup();
72
93
  reject(new Error('Upload aborted'));
73
94
  });
74
95
 
75
96
  xhr.open('PUT', uploadUrl);
76
97
  xhr.setRequestHeader('Content-Type', contentType);
77
98
 
78
- // React Native supports sending file URIs directly via XHR
79
- const file: any = {
99
+ const file: RNXHRFile = {
80
100
  uri: Platform.OS === 'android' ? fileUri : fileUri.replace('file://', ''),
81
101
  type: contentType,
82
102
  name: fileUri.split('/').pop() || 'file',
83
103
  };
84
104
 
85
- xhr.send(file);
105
+ xhr.send(file as unknown as Document);
86
106
  });
87
107
  }
88
108
 
@@ -91,7 +111,8 @@ export function sendMediaMessage(
91
111
  fileUrls: string[],
92
112
  mediaType: 'image' | 'video',
93
113
  content: string,
94
- options: ApiOptions
114
+ options: ApiOptions,
115
+ signal?: AbortSignal
95
116
  ): Promise<MessageResponse> {
96
117
  if (options.fake) {
97
118
  return getFakeMediaMessageResponse(fileUrls, mediaType);
@@ -110,6 +131,7 @@ export function sendMediaMessage(
110
131
  'Accept': 'application/json',
111
132
  'Content-Type': 'application/json',
112
133
  },
134
+ signal,
113
135
  }
114
136
  )
115
137
  .then((res) => res.data);
@@ -6,7 +6,8 @@ import { axiosInstance } from './api';
6
6
  export function sendCustomerMessage(
7
7
  externalId: string,
8
8
  content: string,
9
- options: ApiOptions
9
+ options: ApiOptions,
10
+ signal?: AbortSignal
10
11
  ): Promise<MessageResponse> {
11
12
  if (options.fake) {
12
13
  return new Promise<MessageResponse>((resolve, _) => {
@@ -27,6 +28,7 @@ export function sendCustomerMessage(
27
28
  'Accept': 'application/json',
28
29
  'Content-Type': 'application/x-www-form-urlencoded',
29
30
  },
31
+ signal,
30
32
  }
31
33
  )
32
34
  .then((res) => res.data);