@messenger-box/platform-mobile 10.0.3-alpha.7 → 10.0.3-alpha.72

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 +116 -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,460 @@
1
+ import React, { useEffect, useRef, useState } from 'react';
2
+ import {
3
+ View,
4
+ TouchableOpacity,
5
+ Keyboard,
6
+ Dimensions,
7
+ StyleSheet,
8
+ Text,
9
+ TouchableWithoutFeedback,
10
+ Modal,
11
+ Image,
12
+ TextInput,
13
+ KeyboardAvoidingView,
14
+ Platform,
15
+ ScrollView,
16
+ ActivityIndicator,
17
+ } from 'react-native';
18
+ import { HStack } from '@admin-layout/gluestack-ui-mobile';
19
+ import { MaterialIcons, Ionicons, MaterialCommunityIcons } from '@expo/vector-icons';
20
+ import colors from 'tailwindcss/colors';
21
+
22
+ const { height: SCREEN_HEIGHT, width: SCREEN_WIDTH } = Dimensions.get('window');
23
+ const MAX_HEIGHT = SCREEN_HEIGHT * 0.5; // Half screen height instead of 80%
24
+ const BASE_MIN_HEIGHT = 150; // Default compact height without images
25
+ const IMAGE_PREVIEW_HEIGHT = 90; // Height needed for image preview section including margins
26
+ const HANDLE_HEIGHT = 30;
27
+
28
+ interface SelectedImage {
29
+ uri?: string;
30
+ url?: string;
31
+ [key: string]: any;
32
+ }
33
+
34
+ interface ExpandableInputProps {
35
+ onClose: () => void;
36
+ onSend: () => void;
37
+ onSelectImages: () => void;
38
+ text: string;
39
+ onChangeText: (text: string) => void;
40
+ textInputRef: React.RefObject<any>;
41
+ isSendDisabled: boolean;
42
+ selectedImages: Array<any>;
43
+ onRemoveImage: (index: number) => void;
44
+ loading?: boolean;
45
+ onHeightChange?: (height: number) => void;
46
+ }
47
+
48
+ const ImagePreview: React.FC<{
49
+ images: SelectedImage[];
50
+ onRemove: (index: number) => void;
51
+ }> = React.memo(({ images, onRemove }) => (
52
+ <View style={styles.imagePreviewWrapper}>
53
+ <ScrollView
54
+ horizontal
55
+ showsHorizontalScrollIndicator={false}
56
+ style={styles.imagePreviewContainer}
57
+ contentContainerStyle={styles.imagePreviewContent}
58
+ >
59
+ {images.map((img, index) => (
60
+ <View key={`image-preview-${index}`} style={styles.imagePreview}>
61
+ <View style={styles.imageBox}>
62
+ {img.uri || img.url ? (
63
+ <Image
64
+ source={{ uri: img.uri || img.url }}
65
+ style={{ width: '100%', height: '100%' }}
66
+ resizeMode="cover"
67
+ />
68
+ ) : (
69
+ <View
70
+ style={{
71
+ width: '100%',
72
+ height: '100%',
73
+ backgroundColor: colors.gray[200],
74
+ }}
75
+ />
76
+ )}
77
+ </View>
78
+ <TouchableOpacity
79
+ onPress={() => onRemove(index)}
80
+ style={styles.removeImageButton}
81
+ accessibilityLabel="Remove image"
82
+ >
83
+ <Ionicons name="close" size={16} color="white" />
84
+ </TouchableOpacity>
85
+ </View>
86
+ ))}
87
+ </ScrollView>
88
+ </View>
89
+ ));
90
+
91
+ const SendButton: React.FC<{
92
+ onSend: () => void;
93
+ disabled: boolean;
94
+ loading: boolean;
95
+ }> = React.memo(({ onSend, disabled, loading }) => (
96
+ <TouchableOpacity
97
+ onPress={onSend}
98
+ disabled={disabled || loading}
99
+ style={styles.sendIconContainer}
100
+ accessibilityLabel="Send message"
101
+ >
102
+ <View style={{ padding: 4 }}>
103
+ {loading ? (
104
+ <View
105
+ style={{
106
+ width: 32,
107
+ height: 32,
108
+ alignItems: 'center',
109
+ justifyContent: 'center',
110
+ }}
111
+ >
112
+ <ActivityIndicator size="small" color={colors.blue[400]} />
113
+ </View>
114
+ ) : (
115
+ <MaterialCommunityIcons
116
+ name="send-circle"
117
+ size={32}
118
+ color={disabled ? colors.gray[400] : colors.blue[500]}
119
+ />
120
+ )}
121
+ </View>
122
+ </TouchableOpacity>
123
+ ));
124
+
125
+ const ExpandableInput = ({
126
+ onClose,
127
+ onSend,
128
+ onSelectImages,
129
+ text,
130
+ onChangeText,
131
+ textInputRef,
132
+ isSendDisabled,
133
+ selectedImages,
134
+ onRemoveImage,
135
+ loading = false,
136
+ onHeightChange,
137
+ }: ExpandableInputProps) => {
138
+ const [isExpanded, setIsExpanded] = useState(false);
139
+ const inputRef = useRef<TextInput>(null);
140
+ const [isInputFocused, setIsInputFocused] = useState(false);
141
+
142
+ // Calculate height based on whether we have images
143
+ const getMinHeight = () => {
144
+ return selectedImages.length > 0 ? BASE_MIN_HEIGHT + IMAGE_PREVIEW_HEIGHT : BASE_MIN_HEIGHT;
145
+ };
146
+
147
+ const [sheetHeight, setSheetHeight] = useState(getMinHeight());
148
+
149
+ // Update height when images array changes
150
+ useEffect(() => {
151
+ if (!isExpanded) {
152
+ setSheetHeight(getMinHeight());
153
+ }
154
+ }, [selectedImages.length, isExpanded]);
155
+
156
+ // Memoize handlers
157
+ const handleTextChange = React.useCallback(
158
+ (newText) => {
159
+ onChangeText(newText);
160
+ },
161
+ [onChangeText],
162
+ );
163
+
164
+ const handleSend = React.useCallback(() => {
165
+ if (inputRef.current) {
166
+ inputRef.current.blur();
167
+ setTimeout(() => {
168
+ onSend();
169
+ }, 50);
170
+ } else {
171
+ onSend();
172
+ }
173
+ }, [onSend]);
174
+
175
+ // Close sheet (no animation)
176
+ const closeSheet = () => {
177
+ if (inputRef.current) {
178
+ inputRef.current.blur();
179
+ }
180
+ Keyboard.dismiss();
181
+ setIsExpanded(false);
182
+ setSheetHeight(getMinHeight());
183
+ onClose();
184
+ };
185
+
186
+ // Expand the sheet to max height
187
+ const expandSheet = () => {
188
+ setIsExpanded(true);
189
+ setSheetHeight(MAX_HEIGHT);
190
+ };
191
+
192
+ // Collapse the sheet to min height
193
+ const collapseSheet = () => {
194
+ setIsExpanded(false);
195
+ setSheetHeight(getMinHeight());
196
+ };
197
+
198
+ // Toggle expansion when handle is clicked
199
+ const toggleExpansion = () => {
200
+ if (isExpanded) {
201
+ collapseSheet();
202
+ } else {
203
+ expandSheet();
204
+ }
205
+ };
206
+
207
+ // Always show: set initial height and focus on mount
208
+ useEffect(() => {
209
+ setSheetHeight(getMinHeight());
210
+ setIsExpanded(false);
211
+ setTimeout(() => {
212
+ if (inputRef.current) {
213
+ inputRef.current.focus();
214
+ }
215
+ }, 100);
216
+ // eslint-disable-next-line react-hooks/exhaustive-deps
217
+ }, []);
218
+
219
+ // Handle keyboard showing/hiding
220
+ useEffect(() => {
221
+ const keyboardWillShowListener = Keyboard.addListener('keyboardWillShow', (e) => {
222
+ if (!isExpanded) {
223
+ setSheetHeight(getMinHeight());
224
+ }
225
+ });
226
+
227
+ const keyboardWillHideListener = Keyboard.addListener('keyboardWillHide', () => {
228
+ if (!isExpanded) {
229
+ setSheetHeight(getMinHeight());
230
+ }
231
+ });
232
+
233
+ return () => {
234
+ keyboardWillShowListener.remove();
235
+ keyboardWillHideListener.remove();
236
+ };
237
+ }, [isExpanded, selectedImages.length]);
238
+
239
+ return (
240
+ <KeyboardAvoidingView
241
+ style={styles.container}
242
+ behavior={Platform.OS === 'ios' ? 'padding' : undefined}
243
+ keyboardVerticalOffset={Platform.OS === 'ios' ? 120 : 0}
244
+ >
245
+ <View
246
+ style={[
247
+ styles.sheetContainer,
248
+ {
249
+ height: sheetHeight,
250
+ },
251
+ ]}
252
+ onLayout={(event) => {
253
+ if (onHeightChange) {
254
+ onHeightChange(event.nativeEvent.layout.height);
255
+ }
256
+ }}
257
+ >
258
+ {/* Handle for expand/collapse */}
259
+ {isInputFocused && (
260
+ <TouchableOpacity
261
+ style={styles.handleContainer}
262
+ onPress={toggleExpansion}
263
+ accessibilityLabel="Expand or collapse input"
264
+ activeOpacity={0.7}
265
+ >
266
+ <View style={styles.handle} />
267
+ </TouchableOpacity>
268
+ )}
269
+ {/* Main content */}
270
+ <View style={styles.sheetContent}>
271
+ {/* Input area at top - always visible */}
272
+ <View style={styles.inputContainer}>
273
+ <TextInput
274
+ ref={textInputRef || inputRef}
275
+ value={text}
276
+ onChangeText={handleTextChange}
277
+ style={[styles.textInput, isExpanded && styles.textInputExpanded]}
278
+ placeholder="Jot something down"
279
+ placeholderTextColor="#888"
280
+ multiline
281
+ numberOfLines={isExpanded ? 5 : 2}
282
+ autoCapitalize="sentences"
283
+ autoCorrect={true}
284
+ blurOnSubmit={false}
285
+ textAlignVertical="top"
286
+ accessibilityLabel="Message input"
287
+ onFocus={() => setIsInputFocused(true)}
288
+ onBlur={() => setIsInputFocused(false)}
289
+ />
290
+ </View>
291
+ {/* Image preview section */}
292
+ {selectedImages.length > 0 && <ImagePreview images={selectedImages} onRemove={onRemoveImage} />}
293
+ {/* Extra content area - only in expanded mode */}
294
+ {isExpanded && (
295
+ <ScrollView style={styles.extraContentArea} showsVerticalScrollIndicator={false}>
296
+ <View style={styles.expandedContentPlaceholder} />
297
+ </ScrollView>
298
+ )}
299
+ {/* Bottom controls always at bottom */}
300
+ <HStack style={styles.controlsContainer}>
301
+ <View style={styles.leftControls}>
302
+ <TouchableOpacity
303
+ onPress={onSelectImages}
304
+ style={styles.actionButton}
305
+ accessibilityLabel="Add images"
306
+ >
307
+ <MaterialIcons name="add" size={24} color="#888" />
308
+ </TouchableOpacity>
309
+ </View>
310
+ <SendButton onSend={handleSend} disabled={isSendDisabled} loading={loading} />
311
+ </HStack>
312
+ </View>
313
+ </View>
314
+ </KeyboardAvoidingView>
315
+ );
316
+ };
317
+
318
+ const styles = StyleSheet.create({
319
+ container: {
320
+ flex: 1,
321
+ justifyContent: 'flex-end',
322
+ },
323
+ backdrop: {
324
+ position: 'absolute',
325
+ top: 0,
326
+ left: 0,
327
+ right: 0,
328
+ bottom: 0,
329
+ backgroundColor: 'rgba(0,0,0,0.5)',
330
+ },
331
+ sheetContainer: {
332
+ backgroundColor: 'white',
333
+ borderTopLeftRadius: 20,
334
+ borderTopRightRadius: 20,
335
+ overflow: 'hidden',
336
+ paddingBottom: 15,
337
+ elevation: 5, // For Android
338
+ shadowColor: '#000', // For iOS
339
+ shadowOffset: { width: 0, height: -3 },
340
+ shadowOpacity: 0.2,
341
+ shadowRadius: 5,
342
+ width: SCREEN_WIDTH,
343
+ },
344
+ handleContainer: {
345
+ height: HANDLE_HEIGHT,
346
+ width: '100%',
347
+ alignItems: 'center',
348
+ justifyContent: 'center',
349
+ },
350
+ handle: {
351
+ width: 40,
352
+ height: 5,
353
+ borderRadius: 3,
354
+ backgroundColor: '#ddd',
355
+ },
356
+ sheetContent: {
357
+ flex: 1,
358
+ paddingHorizontal: 15,
359
+ paddingTop: 0,
360
+ flexDirection: 'column',
361
+ justifyContent: 'space-between',
362
+ borderTopWidth: 1,
363
+ borderTopColor: colors.gray[200],
364
+ },
365
+ inputContainer: {
366
+ backgroundColor: '#fff',
367
+ borderRadius: 12,
368
+ padding: 12,
369
+ marginTop: 5,
370
+ // marginBottom: 10,
371
+ },
372
+ textInput: {
373
+ backgroundColor: 'transparent',
374
+ borderWidth: 0,
375
+ fontSize: 16,
376
+ color: '#444',
377
+ paddingVertical: 0,
378
+ paddingHorizontal: 0,
379
+ minHeight: 40,
380
+ },
381
+ textInputExpanded: {
382
+ minHeight: 80,
383
+ maxHeight: 200,
384
+ },
385
+ imagePreviewWrapper: {
386
+ marginBottom: 10,
387
+ },
388
+ imagePreviewContainer: {
389
+ height: 65,
390
+ },
391
+ imagePreviewContent: {
392
+ alignItems: 'center',
393
+ paddingRight: 5,
394
+ },
395
+ extraContentArea: {
396
+ flex: 1,
397
+ marginBottom: 10,
398
+ },
399
+ expandedContentPlaceholder: {
400
+ height: 20,
401
+ },
402
+ controlsContainer: {
403
+ height: 45,
404
+ alignItems: 'center',
405
+ justifyContent: 'space-between',
406
+ paddingHorizontal: 0,
407
+ flexDirection: 'row',
408
+ // borderTopWidth: 1,
409
+ // borderTopColor: colors.gray[200],
410
+ // paddingTop: 5,
411
+ paddingBottom: 10,
412
+ },
413
+ leftControls: {
414
+ flexDirection: 'row',
415
+ alignItems: 'center',
416
+ },
417
+ actionButton: {
418
+ width: 40,
419
+ height: 40,
420
+ borderRadius: 20,
421
+ alignItems: 'center',
422
+ justifyContent: 'center',
423
+ marginRight: 8,
424
+ // padding: 6,
425
+ },
426
+ imagePreview: {
427
+ width: 60,
428
+ height: 60,
429
+ marginRight: 8,
430
+ position: 'relative',
431
+ },
432
+ imageBox: {
433
+ width: '100%',
434
+ height: '100%',
435
+ borderRadius: 8,
436
+ overflow: 'hidden',
437
+ backgroundColor: colors.gray[200],
438
+ },
439
+ removeImageButton: {
440
+ position: 'absolute',
441
+ top: -5,
442
+ right: -5,
443
+ backgroundColor: 'rgba(0,0,0,0.6)',
444
+ borderRadius: 12,
445
+ width: 20,
446
+ height: 20,
447
+ alignItems: 'center',
448
+ justifyContent: 'center',
449
+ zIndex: 10,
450
+ },
451
+ sendIconContainer: {
452
+ width: 48,
453
+ height: 48,
454
+ alignItems: 'center',
455
+ justifyContent: 'center',
456
+ // padding: 6,
457
+ },
458
+ });
459
+
460
+ export default ExpandableInput;