@messenger-box/platform-mobile 10.0.3-alpha.5 → 10.0.3-alpha.50

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 (98) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/lib/compute.js +2 -3
  3. package/lib/compute.js.map +1 -1
  4. package/lib/index.js.map +1 -1
  5. package/lib/queries/inboxQueries.js +65 -0
  6. package/lib/queries/inboxQueries.js.map +1 -0
  7. package/lib/routes.json +2 -3
  8. package/lib/screens/inbox/DialogMessages.js +1 -1
  9. package/lib/screens/inbox/DialogMessages.js.map +1 -1
  10. package/lib/screens/inbox/DialogThreadMessages.js +4 -8
  11. package/lib/screens/inbox/DialogThreadMessages.js.map +1 -1
  12. package/lib/screens/inbox/DialogThreads.js +57 -12
  13. package/lib/screens/inbox/DialogThreads.js.map +1 -1
  14. package/lib/screens/inbox/Inbox.js +1 -1
  15. package/lib/screens/inbox/Inbox.js.map +1 -1
  16. package/lib/screens/inbox/components/CachedImage/consts.js +1 -1
  17. package/lib/screens/inbox/components/CachedImage/consts.js.map +1 -1
  18. package/lib/screens/inbox/components/CachedImage/index.js +168 -46
  19. package/lib/screens/inbox/components/CachedImage/index.js.map +1 -1
  20. package/lib/screens/inbox/components/DialogItem.js +169 -0
  21. package/lib/screens/inbox/components/DialogItem.js.map +1 -0
  22. package/lib/screens/inbox/components/GiftedChatInboxComponent.js +313 -0
  23. package/lib/screens/inbox/components/GiftedChatInboxComponent.js.map +1 -0
  24. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js +147 -31
  25. package/lib/screens/inbox/components/SlackMessageContainer/SlackBubble.js.map +1 -1
  26. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js +6 -1
  27. package/lib/screens/inbox/components/SlackMessageContainer/SlackMessage.js.map +1 -1
  28. package/lib/screens/inbox/components/SubscriptionHandler.js +24 -0
  29. package/lib/screens/inbox/components/SubscriptionHandler.js.map +1 -0
  30. package/lib/screens/inbox/components/ThreadsViewItem.js +66 -55
  31. package/lib/screens/inbox/components/ThreadsViewItem.js.map +1 -1
  32. package/lib/screens/inbox/config/config.js +2 -2
  33. package/lib/screens/inbox/config/config.js.map +1 -1
  34. package/lib/screens/inbox/containers/ConversationView.js +1111 -434
  35. package/lib/screens/inbox/containers/ConversationView.js.map +1 -1
  36. package/lib/screens/inbox/containers/Dialogs.js +193 -80
  37. package/lib/screens/inbox/containers/Dialogs.js.map +1 -1
  38. package/lib/screens/inbox/containers/ThreadConversationView.js +725 -216
  39. package/lib/screens/inbox/containers/ThreadConversationView.js.map +1 -1
  40. package/lib/screens/inbox/containers/ThreadsView.js +83 -50
  41. package/lib/screens/inbox/containers/ThreadsView.js.map +1 -1
  42. package/lib/screens/inbox/hooks/useInboxMessages.js +31 -0
  43. package/lib/screens/inbox/hooks/useInboxMessages.js.map +1 -0
  44. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js +108 -0
  45. package/lib/screens/inbox/hooks/useSafeDialogThreadsMachine.js.map +1 -0
  46. package/lib/screens/inbox/workflow/dialog-threads-xstate.js +151 -0
  47. package/lib/screens/inbox/workflow/dialog-threads-xstate.js.map +1 -0
  48. package/package.json +4 -4
  49. package/src/compute.ts +5 -6
  50. package/src/index.ts +2 -0
  51. package/src/navigation/InboxNavigation.tsx +3 -3
  52. package/src/queries/inboxQueries.ts +299 -0
  53. package/src/queries/index.d.ts +2 -0
  54. package/src/queries/index.ts +1 -0
  55. package/src/screens/inbox/DialogMessages.tsx +1 -1
  56. package/src/screens/inbox/DialogThreadMessages.tsx +7 -14
  57. package/src/screens/inbox/DialogThreads.tsx +55 -61
  58. package/src/screens/inbox/Inbox.tsx +1 -1
  59. package/src/screens/inbox/components/Actionsheet.tsx +30 -0
  60. package/src/screens/inbox/components/CachedImage/consts.ts +4 -3
  61. package/src/screens/inbox/components/CachedImage/index.tsx +232 -61
  62. package/src/screens/inbox/components/DialogItem.tsx +306 -0
  63. package/src/screens/inbox/components/DialogsHeader.tsx +6 -13
  64. package/src/screens/inbox/components/DialogsListItem.tsx +262 -198
  65. package/src/screens/inbox/components/ExpandableInput.tsx +460 -0
  66. package/src/screens/inbox/components/ExpandableInputActionSheet.tsx +518 -0
  67. package/src/screens/inbox/components/GiftedChatInboxComponent.tsx +411 -0
  68. package/src/screens/inbox/components/ServiceDialogsListItem.tsx +337 -194
  69. package/src/screens/inbox/components/SlackInput.tsx +23 -0
  70. package/src/screens/inbox/components/SlackMessageContainer/SlackBubble.tsx +233 -23
  71. package/src/screens/inbox/components/SlackMessageContainer/SlackMessage.tsx +1 -1
  72. package/src/screens/inbox/components/SmartLoader.tsx +61 -0
  73. package/src/screens/inbox/components/SubscriptionHandler.tsx +41 -0
  74. package/src/screens/inbox/components/SupportServiceDialogsListItem.tsx +53 -55
  75. package/src/screens/inbox/components/ThreadsViewItem.tsx +178 -285
  76. package/src/screens/inbox/components/workflow/dialogs-list-item-xstate.ts +145 -0
  77. package/src/screens/inbox/components/workflow/service-dialogs-list-item-xstate.ts +159 -0
  78. package/src/screens/inbox/config/config.ts +2 -2
  79. package/src/screens/inbox/containers/ConversationView.tsx +1843 -702
  80. package/src/screens/inbox/containers/ConversationView.tsx.bk +1467 -0
  81. package/src/screens/inbox/containers/Dialogs.tsx +402 -204
  82. package/src/screens/inbox/containers/SupportServiceDialogs.tsx +4 -4
  83. package/src/screens/inbox/containers/ThreadConversationView.tsx +1350 -319
  84. package/src/screens/inbox/containers/ThreadsView.tsx +105 -193
  85. package/src/screens/inbox/containers/workflow/apollo/handleResult.ts +20 -0
  86. package/src/screens/inbox/containers/workflow/conversation-xstate.ts +313 -0
  87. package/src/screens/inbox/containers/workflow/dialogs-xstate.ts +196 -0
  88. package/src/screens/inbox/containers/workflow/thread-conversation-xstate.ts +401 -0
  89. package/src/screens/inbox/hooks/useInboxMessages.ts +34 -0
  90. package/src/screens/inbox/hooks/useSafeDialogThreadsMachine.ts +136 -0
  91. package/src/screens/inbox/index.ts +37 -0
  92. package/src/screens/inbox/machines/threadsMachine.ts +147 -0
  93. package/src/screens/inbox/workflow/dialog-threads-xstate.ts +163 -0
  94. package/tsconfig.json +11 -54
  95. package/lib/screens/inbox/components/DialogsListItem.js +0 -171
  96. package/lib/screens/inbox/components/DialogsListItem.js.map +0 -1
  97. package/lib/screens/inbox/components/ServiceDialogsListItem.js +0 -171
  98. package/lib/screens/inbox/components/ServiceDialogsListItem.js.map +0 -1
@@ -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);
@@ -0,0 +1,34 @@
1
+ import { useCallback } from 'react';
2
+
3
+ /**
4
+ * useInboxMessages - a generic hook for fetching and subscribing to messages
5
+ *
6
+ * @param useQueryHook - Apollo query hook (e.g., useChannelMessagesQuery)
7
+ * @param queryVariables - variables for the query
8
+ * @param subscriptionDocument - GraphQL subscription document
9
+ * @param subscriptionVariables - variables for the subscription
10
+ * @param updateQuery - Apollo updateQuery function (optional)
11
+ * @param onError - error handler (optional)
12
+ * @returns { data, loading, error, refetch, subscribe }
13
+ */
14
+ export function useInboxMessages({
15
+ useQueryHook,
16
+ queryVariables,
17
+ subscriptionDocument,
18
+ subscriptionVariables,
19
+ updateQuery,
20
+ onError,
21
+ }) {
22
+ const { data, loading, error, refetch, subscribeToMore } = useQueryHook(queryVariables);
23
+
24
+ const subscribe = useCallback(() => {
25
+ return subscribeToMore({
26
+ document: subscriptionDocument,
27
+ variables: subscriptionVariables,
28
+ updateQuery,
29
+ onError,
30
+ });
31
+ }, [subscribeToMore, subscriptionDocument, subscriptionVariables, updateQuery, onError]);
32
+
33
+ return { data, loading, error, refetch, subscribe };
34
+ }
@@ -0,0 +1,136 @@
1
+ import { useState, useCallback, useMemo } from 'react';
2
+ import { BaseState, Actions, dialogThreadsXstate } from '../workflow/dialog-threads-xstate';
3
+
4
+ // Define proper types for the state and context
5
+ export interface DialogThreadsContext {
6
+ channelId?: string;
7
+ postParentId?: string | number;
8
+ role?: string;
9
+ channelsDetail: any;
10
+ threadData: any[];
11
+ loading: boolean;
12
+ error: any;
13
+ }
14
+
15
+ export interface DialogThreadsState {
16
+ context: DialogThreadsContext;
17
+ value: BaseState;
18
+ matches: (stateValue: string) => boolean;
19
+ }
20
+
21
+ // Define proper action types
22
+ export type DialogThreadsEvent =
23
+ | { type: typeof Actions.INITIALIZE; data: { channelId?: string; postParentId?: string | number; role?: string } }
24
+ | { type: typeof Actions.FETCH_CHANNEL_DETAIL; data: { id: string } }
25
+ | { type: typeof Actions.SET_CHANNEL_DETAIL; data: { channelsDetail: any } }
26
+ | { type: typeof Actions.FETCH_THREADS; data?: any }
27
+ | { type: typeof Actions.SET_THREADS; data: { threadData: any[] } }
28
+ | { type: typeof Actions.ERROR; data: { error: any } };
29
+
30
+ /**
31
+ * Custom hook to safely use the dialog threads state machine
32
+ * This provides a fallback implementation in case useMachine from XState has issues
33
+ */
34
+ export function useSafeDialogThreadsMachine(): [DialogThreadsState, (event: DialogThreadsEvent) => void] {
35
+ // Initialize with default state from the machine's initial context
36
+ const [state, setState] = useState<DialogThreadsState>({
37
+ context: {
38
+ channelId: undefined,
39
+ postParentId: undefined,
40
+ role: undefined,
41
+ channelsDetail: null,
42
+ threadData: [],
43
+ loading: true,
44
+ error: null,
45
+ },
46
+ value: BaseState.Idle,
47
+ matches: (value: string) => value === BaseState.Idle,
48
+ });
49
+
50
+ // Create a memoized function to determine state matching
51
+ const matches = useCallback((value: string) => value === state.value, [state.value]);
52
+
53
+ // Update the matches function when state changes
54
+ useMemo(() => {
55
+ setState((prev) => ({
56
+ ...prev,
57
+ matches,
58
+ }));
59
+ }, [matches]);
60
+
61
+ // Create a safe send function to handle events
62
+ const send = useCallback((event: DialogThreadsEvent) => {
63
+ try {
64
+ // Handle specific events based on the event type
65
+ if (event.type === Actions.INITIALIZE) {
66
+ setState((prev) => ({
67
+ ...prev,
68
+ context: {
69
+ ...prev.context,
70
+ channelId: event.data?.channelId,
71
+ postParentId: event.data?.postParentId,
72
+ role: event.data?.role,
73
+ loading: true,
74
+ error: null,
75
+ },
76
+ value: BaseState.LoadingChannel,
77
+ }));
78
+ } else if (event.type === Actions.SET_CHANNEL_DETAIL) {
79
+ setState((prev) => ({
80
+ ...prev,
81
+ context: {
82
+ ...prev.context,
83
+ channelsDetail: event.data?.channelsDetail,
84
+ loading: false,
85
+ },
86
+ value: BaseState.LoadingThreads,
87
+ }));
88
+ } else if (event.type === Actions.SET_THREADS) {
89
+ setState((prev) => ({
90
+ ...prev,
91
+ context: {
92
+ ...prev.context,
93
+ threadData: event.data?.threadData || [],
94
+ loading: false,
95
+ },
96
+ value: BaseState.Active,
97
+ }));
98
+ } else if (event.type === Actions.FETCH_THREADS) {
99
+ setState((prev) => ({
100
+ ...prev,
101
+ context: {
102
+ ...prev.context,
103
+ loading: true,
104
+ },
105
+ value: BaseState.LoadingThreads,
106
+ }));
107
+ } else if (event.type === Actions.ERROR) {
108
+ setState((prev) => ({
109
+ ...prev,
110
+ context: {
111
+ ...prev.context,
112
+ error: event.data?.error,
113
+ loading: false,
114
+ },
115
+ value: BaseState.Error,
116
+ }));
117
+ }
118
+ } catch (error) {
119
+ // Handle errors gracefully
120
+ setState((prev) => ({
121
+ ...prev,
122
+ context: {
123
+ ...prev.context,
124
+ error,
125
+ loading: false,
126
+ },
127
+ value: BaseState.Error,
128
+ }));
129
+ }
130
+ }, []);
131
+
132
+ // Return as a tuple to match useMachine API
133
+ return [state, send];
134
+ }
135
+
136
+ export default useSafeDialogThreadsMachine;
@@ -0,0 +1,37 @@
1
+ // State machines
2
+ export {
3
+ dialogThreadsXstate,
4
+ Actions as DialogThreadsActions,
5
+ BaseState as DialogThreadsState,
6
+ } from './workflow/dialog-threads-xstate';
7
+ export {
8
+ threadConversationXstate,
9
+ Actions as ThreadConversationActions,
10
+ BaseState as ThreadConversationState,
11
+ } from './containers/workflow/thread-conversation-xstate';
12
+ export {
13
+ conversationXstate,
14
+ Actions as ConversationActions,
15
+ BaseState as ConversationState,
16
+ } from './containers/workflow/conversation-xstate';
17
+ export {
18
+ dialogsXstate,
19
+ Actions as DialogsActions,
20
+ BaseState as DialogsState,
21
+ } from './containers/workflow/dialogs-xstate';
22
+
23
+ // Hooks
24
+ export { default as useSafeDialogThreadsMachine } from './hooks/useSafeDialogThreadsMachine';
25
+
26
+ // Components
27
+ export { DialogThreads } from './DialogThreads';
28
+ export { ThreadsView } from './containers/ThreadsView';
29
+ export { ThreadConversationView } from './containers/ThreadConversationView';
30
+ export { ConversationView } from './containers/ConversationView';
31
+ export { Dialogs } from './containers/Dialogs';
32
+
33
+ // Configuration
34
+ export { config } from './config';
35
+
36
+ // Utility
37
+ export { threadsMachineConfig, setupThreadSubscription } from './machines/threadsMachine';