@messenger-box/platform-mobile 10.0.3-alpha.34 → 10.0.3-alpha.36

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@messenger-box/platform-mobile",
3
- "version": "10.0.3-alpha.34",
3
+ "version": "10.0.3-alpha.36",
4
4
  "description": "Sample core for higher packages to depend on",
5
5
  "license": "ISC",
6
6
  "author": "CDMBase LLC",
@@ -22,8 +22,8 @@
22
22
  "watch-ts": "tsc --watch"
23
23
  },
24
24
  "dependencies": {
25
- "@messenger-box/core": "10.0.3-alpha.34",
26
- "@messenger-box/platform-client": "10.0.3-alpha.34",
25
+ "@messenger-box/core": "10.0.3-alpha.36",
26
+ "@messenger-box/platform-client": "10.0.3-alpha.36",
27
27
  "base-64": "1.0.0",
28
28
  "react-native-gifted-chat": "1.0.4"
29
29
  },
@@ -43,5 +43,5 @@
43
43
  "typescript": {
44
44
  "definition": "lib/index.d.ts"
45
45
  },
46
- "gitHead": "33c7bdb4f36c40b6368a5c96fe6312de009188a1"
46
+ "gitHead": "c19b436784fffe67a8d77d89959a9ac898ab76c4"
47
47
  }
@@ -689,6 +689,37 @@ export const DialogsListItemComponent: React.FC<IDialogListItemProps> = function
689
689
  });
690
690
  }, [channel?.id, lastMessage, safeContextProperty]);
691
691
 
692
+ // Optimize update logic for messages from channel-level subscription
693
+ const handleChannelMessage = (channel, newMessage) => {
694
+ // Check if we already have this message
695
+ if (state.context.messages.some((msg) => msg.id === newMessage.id)) {
696
+ console.log('Message already in local state, skipping update:', newMessage.id);
697
+ return;
698
+ }
699
+
700
+ console.log('Handling subscription message update at channel level:', newMessage.id);
701
+
702
+ // Always update with latest message to ensure dialog list stays current
703
+ safeSend({
704
+ type: Actions.UPDATE_MESSAGES,
705
+ data: {
706
+ // Use the directLastMessage option to force immediate UI update
707
+ directLastMessage: newMessage,
708
+ // Also update the messages array
709
+ messages: [...state.context.messages, newMessage],
710
+ },
711
+ });
712
+ };
713
+
714
+ // Create listener for channel property updates
715
+ useEffect(() => {
716
+ // Check if channel has a lastMessage property (set by parent Dialogs component)
717
+ if (channel?.lastMessage && channel.lastMessage.id) {
718
+ console.log('Channel has lastMessage property:', channel.lastMessage.id);
719
+ handleChannelMessage(channel, channel.lastMessage);
720
+ }
721
+ }, [channel?.lastMessage?.id]);
722
+
692
723
  return (
693
724
  <Pressable
694
725
  onPress={() => onOpen(channel?.id, title)}
@@ -286,74 +286,100 @@ function useSafeMachine(machine) {
286
286
  return [stateWithMatches, send] as const;
287
287
  }
288
288
 
289
- const ServiceChannelWithLastMessage = React.memo(({ channel, lastMessage, subscribeToNewMessages }: any) => {
290
- React.useEffect(() => {
291
- // Subscribe and store the unsubscribe function
292
- const unsubscribe = subscribeToNewMessages();
293
- return () => {
294
- // Cleanup subscription on unmount
295
- if (unsubscribe && typeof unsubscribe === 'function') {
296
- unsubscribe();
289
+ const ServiceChannelWithLastMessage = React.memo(
290
+ ({ channel, lastMessage, subscribeToNewMessages, subscribeToChatMessages }: any) => {
291
+ React.useEffect(() => {
292
+ console.log(`Setting up subscriptions for channel ${channel?.id}`);
293
+ // Subscribe and store the unsubscribe functions
294
+ let threadUnsubscribe;
295
+ let chatUnsubscribe;
296
+
297
+ try {
298
+ threadUnsubscribe = subscribeToNewMessages();
299
+ chatUnsubscribe = subscribeToChatMessages();
300
+ } catch (error) {
301
+ console.error(`Error setting up subscriptions for channel ${channel?.id}:`, error);
297
302
  }
298
- };
299
- }, [subscribeToNewMessages]);
300
303
 
301
- // Debug output for component rendering
302
- React.useEffect(() => {
303
- console.log(`ServiceChannelWithLastMessage rendered for channel ${channel?.id}:`, {
304
- hasLastMessage: !!lastMessage,
305
- messageId: lastMessage?.id,
306
- messageText: lastMessage?.message?.substring(0, 20) + (lastMessage?.message?.length > 20 ? '...' : ''),
307
- date: lastMessage?.createdAt ? safeDate(lastMessage.createdAt)?.toISOString() : 'none',
308
- });
309
- }, [lastMessage, channel?.id]);
310
-
311
- const count = 30;
312
- const title = channel?.title.slice(0, count) + (channel?.title.length > count ? '...' : '');
313
-
314
- // Define message display text
315
- let displayMessage = 'No messages yet';
316
-
317
- if (lastMessage) {
318
- // Check for file attachments
319
- const hasFileAttachments = lastMessage.files?.data?.length > 0;
320
-
321
- // Check if the message appears to be an image
322
- const isImageMessage =
323
- lastMessage.message?.includes('<img') ||
324
- lastMessage.message?.includes('[Image]') ||
325
- lastMessage.message?.includes('![') ||
326
- (/\.(jpeg|jpg|gif|png|bmp|webp)/i.test(lastMessage.message || '') &&
327
- ((lastMessage.message || '').includes('http') || (lastMessage.message || '').includes('/images/')));
328
-
329
- if (hasFileAttachments) {
330
- displayMessage = '📎 File attachment';
331
- } else if (isImageMessage) {
332
- displayMessage = '[Image]';
333
- } else if (lastMessage.message && lastMessage.message.trim() !== '') {
334
- displayMessage = lastMessage.message;
335
- } else {
336
- displayMessage = '(Empty message)';
304
+ return () => {
305
+ // Cleanup subscriptions on unmount
306
+ if (threadUnsubscribe && typeof threadUnsubscribe === 'function') {
307
+ try {
308
+ console.log(`Cleaning up thread subscription for channel ${channel?.id}`);
309
+ threadUnsubscribe();
310
+ } catch (error) {
311
+ console.error(`Error cleaning up thread subscription for channel ${channel?.id}:`, error);
312
+ }
313
+ }
314
+
315
+ if (chatUnsubscribe && typeof chatUnsubscribe === 'function') {
316
+ try {
317
+ console.log(`Cleaning up chat subscription for channel ${channel?.id}`);
318
+ chatUnsubscribe();
319
+ } catch (error) {
320
+ console.error(`Error cleaning up chat subscription for channel ${channel?.id}:`, error);
321
+ }
322
+ }
323
+ };
324
+ }, [subscribeToNewMessages, subscribeToChatMessages, channel?.id]);
325
+
326
+ // Debug output for component rendering
327
+ React.useEffect(() => {
328
+ console.log(`ServiceChannelWithLastMessage rendered for channel ${channel?.id}:`, {
329
+ hasLastMessage: !!lastMessage,
330
+ messageId: lastMessage?.id,
331
+ messageText: lastMessage?.message?.substring(0, 20) + (lastMessage?.message?.length > 20 ? '...' : ''),
332
+ date: lastMessage?.createdAt ? safeDate(lastMessage.createdAt)?.toISOString() : 'none',
333
+ });
334
+ }, [lastMessage, channel?.id]);
335
+
336
+ const count = 30;
337
+ const title = channel?.title.slice(0, count) + (channel?.title.length > count ? '...' : '');
338
+
339
+ // Define message display text
340
+ let displayMessage = 'No messages yet';
341
+
342
+ if (lastMessage) {
343
+ // Check for file attachments
344
+ const hasFileAttachments = lastMessage.files?.data?.length > 0;
345
+
346
+ // Check if the message appears to be an image
347
+ const isImageMessage =
348
+ lastMessage.message?.includes('<img') ||
349
+ lastMessage.message?.includes('[Image]') ||
350
+ lastMessage.message?.includes('![') ||
351
+ (/\.(jpeg|jpg|gif|png|bmp|webp)/i.test(lastMessage.message || '') &&
352
+ ((lastMessage.message || '').includes('http') || (lastMessage.message || '').includes('/images/')));
353
+
354
+ if (hasFileAttachments) {
355
+ displayMessage = '📎 File attachment';
356
+ } else if (isImageMessage) {
357
+ displayMessage = '[Image]';
358
+ } else if (lastMessage.message && lastMessage.message.trim() !== '') {
359
+ displayMessage = lastMessage.message;
360
+ } else {
361
+ displayMessage = '(Empty message)';
362
+ }
337
363
  }
338
- }
339
364
 
340
- return (
341
- <HStack space={'sm'} className="flex-1 justify-between">
342
- <Box className="flex-[0.8]">
343
- <Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
344
- {title}
345
- </Text>
346
- <Text color={colors.gray[600]} numberOfLines={1}>
347
- {displayMessage}
348
- </Text>
349
- </Box>
350
-
351
- <Box className="flex-[0.2]">
352
- <Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
353
- </Box>
354
- </HStack>
355
- );
356
- });
365
+ return (
366
+ <HStack space={'sm'} className="flex-1 justify-between">
367
+ <Box className="flex-[0.8]">
368
+ <Text color={colors.gray[600]} className="text-base text-wrap flex-wrap font-semibold">
369
+ {title}
370
+ </Text>
371
+ <Text color={colors.gray[600]} numberOfLines={1}>
372
+ {displayMessage}
373
+ </Text>
374
+ </Box>
375
+
376
+ <Box className="flex-[0.2]">
377
+ <Text color={colors.gray[500]}>{lastMessage ? createdAtText(lastMessage?.createdAt) : ''}</Text>
378
+ </Box>
379
+ </HStack>
380
+ );
381
+ },
382
+ );
357
383
 
358
384
  /**
359
385
  * TODO:
@@ -472,14 +498,19 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
472
498
  React.useEffect(() => {
473
499
  if (lastMessage) {
474
500
  const sParentId = lastMessage?.parentId ? lastMessage?.parentId : lastMessage?.id;
475
- safeSend({
476
- type: Actions.SET_SERVICE_POST_PARENT_ID,
477
- data: {
478
- servicePostParentId: sParentId,
479
- },
480
- });
501
+
502
+ if (sParentId !== safeContextProperty('servicePostParentId')) {
503
+ console.log(`Updating servicePostParentId for channel ${channel?.id} to:`, sParentId);
504
+
505
+ safeSend({
506
+ type: Actions.SET_SERVICE_POST_PARENT_ID,
507
+ data: {
508
+ servicePostParentId: sParentId,
509
+ },
510
+ });
511
+ }
481
512
  }
482
- }, [lastMessage, safeSend]);
513
+ }, [lastMessage, safeSend, channel?.id, safeContextProperty]);
483
514
 
484
515
  const creatorAndMembersId = React.useMemo(() => {
485
516
  if (!channel?.members) return null;
@@ -536,9 +567,16 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
536
567
  }
537
568
  }, [channel?.id, refetchThreadMessages, safeSend, isMountedRef, role]);
538
569
 
539
- // Refetch messages when screen is focused or refreshing
570
+ // Add a timestamp to track when subscriptions were last set up
571
+ const [subscriptionsTimestamp, setSubscriptionsTimestamp] = useState(Date.now());
572
+
573
+ // Reset subscriptions when the component gains focus
540
574
  useFocusEffect(
541
575
  React.useCallback(() => {
576
+ // Force subscription refresh
577
+ setSubscriptionsTimestamp(Date.now());
578
+
579
+ // Existing focus effect logic...
542
580
  if (!channel?.id) return;
543
581
 
544
582
  console.log('ServiceDialogsListItem focused for channel:', channel?.id);
@@ -613,6 +651,7 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
613
651
  </Box>
614
652
  <Box className="flex-1">
615
653
  <ServiceChannelWithLastMessage
654
+ key={`channel-${channel?.id}-${subscriptionsTimestamp}`}
616
655
  channel={channel}
617
656
  lastMessage={lastMessage}
618
657
  subscribeToNewMessages={() =>
@@ -620,52 +659,200 @@ export const ServiceDialogsListItemComponent: React.FC<IDialogListItemProps> = f
620
659
  document: THREAD_CHAT_ADDED,
621
660
  variables: {
622
661
  channelId: channel?.id?.toString(),
623
- postParentId: postParentId ? servicePostParentId : null,
662
+ postParentId: postParentId || servicePostParentId || null,
624
663
  },
625
664
  updateQuery: (prev, { subscriptionData }: any) => {
626
- if (!subscriptionData.data) return prev;
627
-
628
- const newPostThreadData: any = subscriptionData?.data?.threadCreatedUpdated?.data;
629
- const newMessage: any = subscriptionData?.data?.threadCreatedUpdated?.lastMessage;
630
-
631
- console.log('New thread message subscription update:', {
632
- channelId: channel?.id,
633
- threadId: newPostThreadData?.id,
634
- hasMessage: !!newMessage,
635
- message: newMessage?.message?.substring(0, 20) + '...',
636
- });
637
-
638
- const data =
639
- prev?.threadMessages?.data?.map((t: any) =>
640
- t.id === newPostThreadData?.id
641
- ? {
642
- ...t,
643
- replies: [...t?.replies, newMessage],
644
- replyCount: newPostThreadData?.replyCount,
645
- lastReplyAt: newPostThreadData?.lastReplyAt,
646
- updatedAt: newPostThreadData?.updatedAt,
647
- }
648
- : t,
649
- ) ?? [];
650
-
651
- // Use the safe state update function
652
- if (isMountedRef.current) {
653
- safeSend({
654
- type: Actions.UPDATE_THREAD_MESSAGES,
655
- data: {
656
- threadMessages: data?.length > 0 ? data : [newPostThreadData],
657
- directLastMessage: newMessage, // Directly set the new message
658
- },
665
+ if (!subscriptionData?.data) {
666
+ console.log(`No subscription data for channel ${channel?.id}`);
667
+ return prev;
668
+ }
669
+
670
+ try {
671
+ const newPostThreadData: any =
672
+ subscriptionData?.data?.threadCreatedUpdated?.data;
673
+ const newMessage: any =
674
+ subscriptionData?.data?.threadCreatedUpdated?.lastMessage;
675
+
676
+ if (!newPostThreadData || !newMessage) {
677
+ console.log(`Missing data in subscription for channel ${channel?.id}`);
678
+ return prev;
679
+ }
680
+
681
+ console.log('New thread message subscription update:', {
682
+ channelId: channel?.id,
683
+ threadId: newPostThreadData?.id,
684
+ hasMessage: !!newMessage,
685
+ message: newMessage?.message?.substring(0, 20) + '...',
659
686
  });
687
+
688
+ // Create a safe copy of the previous data
689
+ const prevThreads = prev?.threadMessages?.data || [];
690
+
691
+ // Check if this thread already exists
692
+ const threadExists = prevThreads.some(
693
+ (t: any) => t.id === newPostThreadData?.id,
694
+ );
695
+
696
+ let updatedThreads;
697
+ if (threadExists) {
698
+ // Update existing thread
699
+ updatedThreads = prevThreads.map((t: any) =>
700
+ t.id === newPostThreadData?.id
701
+ ? {
702
+ ...t,
703
+ replies: [...(t?.replies || []), newMessage],
704
+ replyCount: newPostThreadData?.replyCount,
705
+ lastReplyAt: newPostThreadData?.lastReplyAt,
706
+ updatedAt: newPostThreadData?.updatedAt,
707
+ }
708
+ : t,
709
+ );
710
+ } else {
711
+ // Add new thread
712
+ updatedThreads = [...prevThreads, newPostThreadData];
713
+ }
714
+
715
+ // Use the safe state update function
716
+ if (isMountedRef.current) {
717
+ safeSend({
718
+ type: Actions.UPDATE_THREAD_MESSAGES,
719
+ data: {
720
+ threadMessages: updatedThreads,
721
+ directLastMessage: newMessage, // Directly set the new message
722
+ },
723
+ });
724
+ }
725
+
726
+ return {
727
+ ...prev,
728
+ threadMessages: {
729
+ ...prev?.threadMessages,
730
+ totalCount:
731
+ newPostThreadData?.totalCount ??
732
+ prev?.threadMessages?.totalCount ??
733
+ 0,
734
+ data: updatedThreads,
735
+ },
736
+ };
737
+ } catch (error) {
738
+ console.error(
739
+ `Error processing subscription data for channel ${channel?.id}:`,
740
+ error,
741
+ );
742
+ return prev;
743
+ }
744
+ },
745
+ onError: (error) => {
746
+ console.error(`Thread subscription error for channel ${channel?.id}:`, error);
747
+ },
748
+ })
749
+ }
750
+ subscribeToChatMessages={() =>
751
+ subscribeToMore({
752
+ document: CHAT_MESSAGE_ADDED,
753
+ variables: {
754
+ channelId: channel?.id?.toString(),
755
+ postParentId: postParentId || servicePostParentId || null,
756
+ },
757
+ updateQuery: (prev, { subscriptionData }: any) => {
758
+ if (!subscriptionData?.data) {
759
+ console.log(`No chat message subscription data for channel ${channel?.id}`);
760
+ return prev;
660
761
  }
661
762
 
662
- return Object.assign({}, prev, {
663
- threadMessages: {
664
- ...prev?.threadMessages,
665
- totalCount: newPostThreadData?.totalCount ?? 0,
666
- data: data?.length > 0 ? data : [newPostThreadData],
667
- },
668
- });
763
+ try {
764
+ const newMessage = subscriptionData?.data?.chatMessageAdded;
765
+
766
+ if (!newMessage) {
767
+ console.log(
768
+ `Missing chat message data in subscription for channel ${channel?.id}`,
769
+ );
770
+ return prev;
771
+ }
772
+
773
+ console.log('New chat message subscription update:', {
774
+ channelId: channel?.id,
775
+ messageId: newMessage?.id,
776
+ message: newMessage?.message?.substring(0, 20) + '...',
777
+ });
778
+
779
+ // Find the thread this message belongs to
780
+ const prevThreads = prev?.threadMessages?.data || [];
781
+ const threadIndex = prevThreads.findIndex((t: any) => {
782
+ // Check if this message belongs to this thread
783
+ if (newMessage.parentId && t.post?.id === newMessage.parentId) {
784
+ return true;
785
+ }
786
+ // Check replies
787
+ if (t.replies && t.replies.some((r: any) => r.id === newMessage.parentId)) {
788
+ return true;
789
+ }
790
+ return false;
791
+ });
792
+
793
+ if (threadIndex === -1) {
794
+ console.log(
795
+ `Cannot find thread for chat message in channel ${channel?.id}`,
796
+ );
797
+
798
+ // Even if we can't find the thread, update the UI with the new message
799
+ if (isMountedRef.current) {
800
+ safeSend({
801
+ type: Actions.UPDATE_THREAD_MESSAGES,
802
+ data: {
803
+ directLastMessage: newMessage,
804
+ },
805
+ });
806
+ }
807
+
808
+ return prev;
809
+ }
810
+
811
+ // Update the thread with the new message
812
+ const updatedThreads = [...prevThreads];
813
+ const thread = { ...updatedThreads[threadIndex] };
814
+
815
+ // Add message to replies
816
+ thread.replies = [...(thread.replies || []), newMessage];
817
+
818
+ // Fix for arithmetic operation type error
819
+ const currentReplyCount =
820
+ typeof thread.replyCount === 'number' ? thread.replyCount : 0;
821
+ thread.replyCount = currentReplyCount + 1;
822
+
823
+ thread.lastReplyAt = newMessage.createdAt;
824
+ thread.updatedAt = newMessage.createdAt;
825
+
826
+ updatedThreads[threadIndex] = thread;
827
+
828
+ // Use the safe state update function
829
+ if (isMountedRef.current) {
830
+ safeSend({
831
+ type: Actions.UPDATE_THREAD_MESSAGES,
832
+ data: {
833
+ threadMessages: updatedThreads,
834
+ directLastMessage: newMessage,
835
+ },
836
+ });
837
+ }
838
+
839
+ return {
840
+ ...prev,
841
+ threadMessages: {
842
+ ...prev?.threadMessages,
843
+ data: updatedThreads,
844
+ },
845
+ };
846
+ } catch (error) {
847
+ console.error(
848
+ `Error processing chat message subscription for channel ${channel?.id}:`,
849
+ error,
850
+ );
851
+ return prev;
852
+ }
853
+ },
854
+ onError: (error) => {
855
+ console.error(`Chat message subscription error for channel ${channel?.id}:`, error);
669
856
  },
670
857
  })
671
858
  }