@messenger-box/platform-mobile 10.0.3-alpha.16 → 10.0.3-alpha.18

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 (31) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/lib/routes.json +14 -1
  3. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  4. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  5. package/lib/screens/inbox/components/CachedImage/index.js +125 -16
  6. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  7. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +32 -21
  8. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  9. package/lib/screens/inbox/containers/ConversationView.js +1175 -400
  10. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  11. package/lib/screens/inbox/containers/Dialogs.js +290 -21
  12. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  13. package/lib/screens/inbox/containers/ThreadConversationView.js +858 -351
  14. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  15. package/lib/screens/inbox/containers/workflow/conversation-xstate.js +380 -0
  16. package/lib/screens/inbox/containers/workflow/conversation-xstate.js.map +1 -0
  17. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js +235 -0
  18. package/lib/screens/inbox/containers/workflow/dialogs-xstate.js.map +1 -0
  19. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js +438 -0
  20. package/lib/screens/inbox/containers/workflow/thread-conversation-xstate.js.map +1 -0
  21. package/package.json +4 -4
  22. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  23. package/src/screens/inbox/components/CachedImage/index.tsx +137 -17
  24. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +35 -9
  25. package/src/screens/inbox/containers/ConversationView.tsx +1510 -641
  26. package/src/screens/inbox/containers/Dialogs.tsx +415 -123
  27. package/src/screens/inbox/containers/ThreadConversationView.tsx +1053 -288
  28. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  29. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  30. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  31. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
@@ -0,0 +1,401 @@
1
+ import { assign, setup } from 'xstate';
2
+ import { merge } from 'lodash-es';
3
+
4
+ export const enum Actions {
5
+ INITIAL_CONTEXT = 'INITIAL_CONTEXT',
6
+ ERROR_HANDLED = 'ERROR_HANDLED',
7
+ SEND_THREAD_MESSAGE = 'SEND_THREAD_MESSAGE',
8
+ SEND_THREAD_MESSAGE_WITH_FILE = 'SEND_THREAD_MESSAGE_WITH_FILE',
9
+ SET_THREAD_MESSAGES = 'SET_THREAD_MESSAGES',
10
+ CLEAR_MESSAGES = 'CLEAR_MESSAGES',
11
+ FETCH_MORE_MESSAGES = 'FETCH_MORE_MESSAGES',
12
+ SUBSCRIBE_TO_THREAD_MESSAGES = 'SUBSCRIBE_TO_THREAD_MESSAGES',
13
+ START_LOADING = 'START_LOADING',
14
+ STOP_LOADING = 'STOP_LOADING',
15
+ SET_IMAGE = 'SET_IMAGE',
16
+ CLEAR_IMAGE = 'CLEAR_IMAGE',
17
+ SET_MESSAGE_TEXT = 'SET_MESSAGE_TEXT',
18
+ }
19
+
20
+ export const enum BaseState {
21
+ Idle = 'idle',
22
+ Error = 'error',
23
+ Loading = 'loading',
24
+ Done = 'done',
25
+ FetchThreadMessages = 'fetchThreadMessages',
26
+ }
27
+
28
+ export const enum MainState {
29
+ SendThreadMessage = 'sendThreadMessage',
30
+ SendThreadMessageWithFile = 'sendThreadMessageWithFile',
31
+ FetchMoreMessages = 'fetchMoreMessages',
32
+ }
33
+
34
+ export const threadConversationXstate = setup({
35
+ types: {
36
+ context: {} as {
37
+ channelId: string | null;
38
+ postParentId: string | null;
39
+ role: string | null;
40
+ threadMessages: any[];
41
+ totalCount: number;
42
+ skip: number;
43
+ loading: boolean;
44
+ loadingOldMessages: boolean;
45
+ error: string | null;
46
+ selectedImage: string;
47
+ files: any[];
48
+ images: any[];
49
+ messageText: string;
50
+ imageLoading: boolean;
51
+ postThread: any;
52
+ threadPost: any[];
53
+ isScrollToBottom: boolean;
54
+ },
55
+ },
56
+ actions: {
57
+ errorState: assign(({ context, event }) => {
58
+ return {
59
+ ...context,
60
+ error: event.data?.message || 'An error occurred',
61
+ loading: false,
62
+ loadingOldMessages: false,
63
+ imageLoading: false,
64
+ };
65
+ }),
66
+ setInitialContext: assign(({ context, event }) => {
67
+ return merge({
68
+ ...context,
69
+ channelId: event.data?.channelId || null,
70
+ postParentId: event.data?.postParentId || null,
71
+ role: event.data?.role || null,
72
+ loading: false,
73
+ });
74
+ }),
75
+ setThreadMessages: assign(({ context, event }) => {
76
+ const messages = event.data?.messages || [];
77
+ console.log(`setThreadMessages: Setting ${messages.length} messages`);
78
+
79
+ // Create a set of unique IDs to remove duplicates
80
+ const messageIds = new Set();
81
+ const uniqueMessages = [];
82
+
83
+ // Process messages to ensure uniqueness
84
+ messages.forEach((msg) => {
85
+ if (msg.id && !messageIds.has(msg.id)) {
86
+ messageIds.add(msg.id);
87
+ uniqueMessages.push(msg);
88
+ }
89
+ });
90
+
91
+ console.log(`setThreadMessages: After deduplication, have ${uniqueMessages.length} unique messages`);
92
+
93
+ return {
94
+ ...context,
95
+ threadMessages: uniqueMessages,
96
+ totalCount: event.data?.totalCount || 0,
97
+ loading: false,
98
+ loadingOldMessages: false,
99
+ threadPost: event.data?.threadPost || [],
100
+ postThread: event.data?.postThread || null,
101
+ };
102
+ }),
103
+ addThreadMessages: assign(({ context, event }) => {
104
+ const newMessages = event.data?.messages || [];
105
+ console.log('Adding thread messages and disabling loading state. New messages:', newMessages.length);
106
+
107
+ if (newMessages.length === 0) {
108
+ return {
109
+ ...context,
110
+ loadingOldMessages: false,
111
+ loading: false,
112
+ };
113
+ }
114
+
115
+ // Create a map of existing message IDs for quick lookup
116
+ const existingMessageIds = new Set();
117
+ context.threadMessages.forEach((msg) => existingMessageIds.add(msg.id));
118
+
119
+ // Filter out any duplicate messages
120
+ const uniqueNewMessages = newMessages.filter((msg) => {
121
+ if (!msg.id || existingMessageIds.has(msg.id)) {
122
+ console.log('Skipping duplicate message:', msg.id);
123
+ return false; // Skip messages with no ID or duplicates
124
+ }
125
+ existingMessageIds.add(msg.id); // Add to set to catch duplicates in the new messages
126
+ return true;
127
+ });
128
+
129
+ console.log(`After filtering, adding ${uniqueNewMessages.length} unique messages`);
130
+
131
+ return {
132
+ ...context,
133
+ threadMessages: [...context.threadMessages, ...uniqueNewMessages],
134
+ loadingOldMessages: false,
135
+ loading: false,
136
+ };
137
+ }),
138
+ addNewMessage: assign(({ context, event }) => {
139
+ const message = event.data?.message;
140
+ console.log('Adding new message to thread:', message?.id);
141
+ if (!message) {
142
+ console.warn('No message data provided to addNewMessage action');
143
+ return context;
144
+ }
145
+
146
+ // Prevent duplicate messages by checking for the same ID
147
+ const existingMessageIndex = context.threadMessages.findIndex((msg) => msg.id === message.id);
148
+ if (existingMessageIndex !== -1) {
149
+ console.log('Message already exists, not adding duplicate:', message.id);
150
+ return {
151
+ ...context,
152
+ loading: false,
153
+ };
154
+ }
155
+
156
+ // Use a set to ensure we only have unique message IDs
157
+ const messageIds = new Set();
158
+ const uniqueMessages = [...context.threadMessages];
159
+
160
+ // Add all existing message IDs to the set
161
+ uniqueMessages.forEach((msg) => messageIds.add(msg.id));
162
+
163
+ // Only add the new message if its ID isn't already in the set
164
+ if (!messageIds.has(message.id)) {
165
+ uniqueMessages.unshift(message); // Add to beginning (newest first)
166
+ }
167
+
168
+ console.log('Successfully added new message to thread');
169
+ return {
170
+ ...context,
171
+ threadMessages: uniqueMessages,
172
+ totalCount: context.totalCount + 1,
173
+ loading: false,
174
+ };
175
+ }),
176
+ updateSkip: assign(({ context, event }) => {
177
+ console.log('Setting loadingOldMessages to true');
178
+ return {
179
+ ...context,
180
+ skip: context.threadMessages.length,
181
+ loadingOldMessages: true,
182
+ loading: event.data?.loading !== undefined ? event.data.loading : context.loading,
183
+ };
184
+ }),
185
+ clearMessages: assign(({ context }) => {
186
+ return {
187
+ ...context,
188
+ threadMessages: [],
189
+ totalCount: 0,
190
+ skip: 0,
191
+ };
192
+ }),
193
+ setPostParentId: assign(({ context, event }) => {
194
+ return {
195
+ ...context,
196
+ postParentId: event.data?.postParentId || null,
197
+ };
198
+ }),
199
+ setPostThread: assign(({ context, event }) => {
200
+ return {
201
+ ...context,
202
+ postThread: event.data?.postThread || null,
203
+ };
204
+ }),
205
+ startLoading: assign(({ context, event }) => {
206
+ return {
207
+ ...context,
208
+ loading: true,
209
+ loadingOldMessages:
210
+ event.data?.loadingOldMessages !== undefined
211
+ ? event.data.loadingOldMessages
212
+ : context.loadingOldMessages,
213
+ };
214
+ }),
215
+ stopLoading: assign(({ context, event }) => {
216
+ return {
217
+ ...context,
218
+ loading: false,
219
+ loadingOldMessages:
220
+ event.data?.loadingOldMessages !== undefined
221
+ ? event.data.loadingOldMessages
222
+ : context.loadingOldMessages,
223
+ };
224
+ }),
225
+ startImageLoading: assign(({ context }) => {
226
+ return {
227
+ ...context,
228
+ imageLoading: true,
229
+ };
230
+ }),
231
+ stopImageLoading: assign(({ context }) => {
232
+ return {
233
+ ...context,
234
+ imageLoading: false,
235
+ };
236
+ }),
237
+ setSelectedImage: assign(({ context, event }) => {
238
+ return {
239
+ ...context,
240
+ selectedImage: event.data?.image || '',
241
+ files: event.data?.files || context.files,
242
+ images: event.data?.images || context.images,
243
+ imageLoading: false,
244
+ };
245
+ }),
246
+ clearImageData: assign(({ context }) => {
247
+ return {
248
+ ...context,
249
+ selectedImage: '',
250
+ files: [],
251
+ images: [],
252
+ };
253
+ }),
254
+ setMessageText: assign(({ context, event }) => {
255
+ return {
256
+ ...context,
257
+ messageText: event.data?.messageText || '',
258
+ };
259
+ }),
260
+ setScrollToBottom: assign(({ context, event }) => {
261
+ return {
262
+ ...context,
263
+ isScrollToBottom: event.data?.isScrollToBottom || false,
264
+ };
265
+ }),
266
+ },
267
+ guards: {
268
+ hasMoreMessages: ({ context }) => {
269
+ return context.totalCount > context.threadMessages.length;
270
+ },
271
+ },
272
+ }).createMachine({
273
+ id: 'thread-conversation-view',
274
+ initial: BaseState.Idle,
275
+ context: {
276
+ channelId: null,
277
+ postParentId: null,
278
+ role: null,
279
+ threadMessages: [],
280
+ totalCount: 0,
281
+ skip: 0,
282
+ loading: false,
283
+ loadingOldMessages: false,
284
+ error: null,
285
+ selectedImage: '',
286
+ files: [],
287
+ images: [],
288
+ messageText: '',
289
+ imageLoading: false,
290
+ postThread: null,
291
+ threadPost: [],
292
+ isScrollToBottom: false,
293
+ },
294
+ states: {
295
+ [BaseState.Idle]: {
296
+ on: {
297
+ [Actions.INITIAL_CONTEXT]: {
298
+ target: BaseState.FetchThreadMessages,
299
+ actions: ['setInitialContext'],
300
+ },
301
+ [Actions.SEND_THREAD_MESSAGE]: {
302
+ target: MainState.SendThreadMessage,
303
+ actions: ['startLoading'],
304
+ },
305
+ [Actions.SEND_THREAD_MESSAGE_WITH_FILE]: {
306
+ target: MainState.SendThreadMessageWithFile,
307
+ actions: ['startLoading'],
308
+ },
309
+ [Actions.FETCH_MORE_MESSAGES]: {
310
+ target: MainState.FetchMoreMessages,
311
+ actions: ['updateSkip'],
312
+ guard: 'hasMoreMessages',
313
+ },
314
+ [Actions.CLEAR_MESSAGES]: {
315
+ target: BaseState.Idle,
316
+ actions: ['clearMessages'],
317
+ },
318
+ [Actions.START_LOADING]: {
319
+ target: BaseState.Idle,
320
+ actions: ['startLoading'],
321
+ },
322
+ [Actions.STOP_LOADING]: {
323
+ target: BaseState.Idle,
324
+ actions: ['stopLoading'],
325
+ },
326
+ [Actions.SET_IMAGE]: {
327
+ target: BaseState.Idle,
328
+ actions: ['setSelectedImage'],
329
+ },
330
+ [Actions.CLEAR_IMAGE]: {
331
+ target: BaseState.Idle,
332
+ actions: ['clearImageData'],
333
+ },
334
+ [Actions.SET_MESSAGE_TEXT]: {
335
+ target: BaseState.Idle,
336
+ actions: ['setMessageText'],
337
+ },
338
+ },
339
+ },
340
+ [BaseState.Error]: {
341
+ entry: ['errorState'],
342
+ on: {
343
+ [Actions.ERROR_HANDLED]: {
344
+ target: BaseState.Idle,
345
+ },
346
+ },
347
+ },
348
+ [BaseState.FetchThreadMessages]: {
349
+ invoke: {
350
+ src: 'fetchThreadMessages',
351
+ input: ({ context, event }) => ({ context, event }),
352
+ onDone: {
353
+ target: BaseState.Idle,
354
+ actions: ['setThreadMessages'],
355
+ },
356
+ onError: {
357
+ target: BaseState.Error,
358
+ },
359
+ },
360
+ },
361
+ [MainState.SendThreadMessage]: {
362
+ invoke: {
363
+ src: 'sendThreadMessage',
364
+ input: ({ context, event }) => ({ context, event }),
365
+ onDone: {
366
+ target: BaseState.Idle,
367
+ actions: ['addNewMessage', 'stopLoading'],
368
+ },
369
+ onError: {
370
+ target: BaseState.Error,
371
+ },
372
+ },
373
+ },
374
+ [MainState.SendThreadMessageWithFile]: {
375
+ invoke: {
376
+ src: 'sendThreadMessageWithFile',
377
+ input: ({ context, event }) => ({ context, event }),
378
+ onDone: {
379
+ target: BaseState.Idle,
380
+ actions: ['addNewMessage', 'clearImageData', 'stopLoading'],
381
+ },
382
+ onError: {
383
+ target: BaseState.Error,
384
+ },
385
+ },
386
+ },
387
+ [MainState.FetchMoreMessages]: {
388
+ invoke: {
389
+ src: 'fetchMoreThreadMessages',
390
+ input: ({ context, event }) => ({ context, event }),
391
+ onDone: {
392
+ target: BaseState.Idle,
393
+ actions: ['addThreadMessages'],
394
+ },
395
+ onError: {
396
+ target: BaseState.Error,
397
+ },
398
+ },
399
+ },
400
+ },
401
+ } as any);