@planningcenter/chat-react-native 3.18.0-rc.5 → 3.18.0-rc.7

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 (49) hide show
  1. package/build/components/conversation/message.d.ts.map +1 -1
  2. package/build/components/conversation/message.js +2 -1
  3. package/build/components/conversation/message.js.map +1 -1
  4. package/build/components/conversations/conversations.d.ts.map +1 -1
  5. package/build/components/conversations/conversations.js +2 -3
  6. package/build/components/conversations/conversations.js.map +1 -1
  7. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  8. package/build/hooks/use_conversation_messages_jolt_events.js +23 -70
  9. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  10. package/build/hooks/use_message_create_or_update.d.ts +0 -2
  11. package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
  12. package/build/hooks/use_message_create_or_update.js +10 -8
  13. package/build/hooks/use_message_create_or_update.js.map +1 -1
  14. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  15. package/build/screens/conversation_details_screen.js +3 -4
  16. package/build/screens/conversation_details_screen.js.map +1 -1
  17. package/build/screens/conversation_new/components/form_list.d.ts +2 -2
  18. package/build/screens/conversation_new/components/form_list.d.ts.map +1 -1
  19. package/build/screens/conversation_new/components/form_list.js +2 -3
  20. package/build/screens/conversation_new/components/form_list.js.map +1 -1
  21. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.d.ts.map +1 -1
  22. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js +2 -3
  23. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js.map +1 -1
  24. package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.d.ts.map +1 -1
  25. package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js +2 -3
  26. package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js.map +1 -1
  27. package/build/types/jolt_events/reaction_events.d.ts +1 -0
  28. package/build/types/jolt_events/reaction_events.d.ts.map +1 -1
  29. package/build/types/jolt_events/reaction_events.js.map +1 -1
  30. package/build/utils/cache/messages_cache.d.ts +9 -0
  31. package/build/utils/cache/messages_cache.d.ts.map +1 -0
  32. package/build/utils/cache/messages_cache.js +89 -0
  33. package/build/utils/cache/messages_cache.js.map +1 -0
  34. package/build/utils/cache/optimistically_create_message.d.ts +2 -1
  35. package/build/utils/cache/optimistically_create_message.d.ts.map +1 -1
  36. package/build/utils/cache/optimistically_create_message.js +6 -3
  37. package/build/utils/cache/optimistically_create_message.js.map +1 -1
  38. package/package.json +2 -3
  39. package/src/components/conversation/message.tsx +2 -1
  40. package/src/components/conversations/conversations.tsx +7 -9
  41. package/src/hooks/use_conversation_messages_jolt_events.ts +39 -81
  42. package/src/hooks/use_message_create_or_update.ts +10 -9
  43. package/src/screens/conversation_details_screen.tsx +3 -4
  44. package/src/screens/conversation_new/components/form_list.tsx +3 -5
  45. package/src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx +2 -4
  46. package/src/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.tsx +2 -4
  47. package/src/types/jolt_events/reaction_events.ts +1 -0
  48. package/src/utils/cache/messages_cache.ts +113 -0
  49. package/src/utils/cache/optimistically_create_message.ts +7 -2
@@ -1 +1 @@
1
- {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAA;AASxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAoB7C;;GAEG;AACH,UAAU,YAAa,SAAQ,eAAe;IAC5C,4BAA4B,EAAE,OAAO,CAAA;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,wBAAgB,OAAO,CAAC,EACtB,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,GAAG,OAAO,EACX,EAAE,YAAY,qBAsPd"}
1
+ {"version":3,"file":"message.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"AACA,OAAO,KAAoB,MAAM,OAAO,CAAA;AASxC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAqB7C;;GAEG;AACH,UAAU,YAAa,SAAQ,eAAe;IAC5C,4BAA4B,EAAE,OAAO,CAAA;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,cAAc,CAAC,EAAE,OAAO,CAAA;CACzB;AAED,wBAAgB,OAAO,CAAC,EACtB,4BAA4B,EAC5B,eAAe,EACf,wBAAwB,EACxB,aAAa,EACb,cAAc,EACd,GAAG,OAAO,EACX,EAAE,YAAY,qBAsPd"}
@@ -11,11 +11,12 @@ import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL, MESSAGE_AUTHOR_AVATAR_COL
11
11
  import Animated from 'react-native-reanimated';
12
12
  import { useLiveRelativeTime } from '../../hooks/use_live_relative_time';
13
13
  import { MessageReadReceipts } from './message_read_receipts';
14
- import { isNewMessage, useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update';
14
+ import { useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update';
15
15
  import { Haptic } from '../../utils/native_adapters';
16
16
  import { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from './reply_connectors';
17
17
  import { pluralize } from '../../utils';
18
18
  import { useConversationMessage } from '../../hooks/use_conversation_message';
19
+ import { isNewMessage } from '../../utils/cache/messages_cache';
19
20
  export function Message({ canDeleteNonAuthoredMessages, conversation_id, latestReadMessageSortKey, inReplyScreen, repliesEnabled, ...message }) {
20
21
  const { text, reactionCounts, pending, error } = message;
21
22
  const styles = useMessageStyles(message);
@@ -1 +1 @@
1
- {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport React, { useEffect } from 'react'\nimport { Pressable, StyleSheet, useWindowDimensions, View } from 'react-native'\nimport { MessageReaction } from '../../components/conversation/message_reaction'\nimport { Avatar, Icon, Spinner, Text, TextButton, TextInlineButton } from '../../components/display'\nimport {\n useAnimatedMessageBackgroundColor,\n useInteractionGhostBackgroundColor,\n useTheme,\n} from '../../hooks'\nimport { MessageResource } from '../../types'\nimport { ReactionCountResource } from '../../types/resources/reaction'\nimport { MessageAttachments } from './message_attachments'\nimport ErrorBoundary from '../page/error_boundary'\nimport { MessageMarkdown } from './message_markdown'\nimport { DenormalizedMessageAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n platformFontWeightMedium,\n} from '../../utils/styles'\nimport Animated from 'react-native-reanimated'\nimport { useLiveRelativeTime } from '../../hooks/use_live_relative_time'\nimport { MessageReadReceipts } from './message_read_receipts'\nimport { isNewMessage, useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update'\nimport { Haptic } from '../../utils/native_adapters'\nimport { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from './reply_connectors'\nimport { pluralize } from '../../utils'\nimport { useConversationMessage } from '../../hooks/use_conversation_message'\n\n/** Message\n * Component for display of a message within a conversation list\n */\ninterface MessageProps extends MessageResource {\n canDeleteNonAuthoredMessages: boolean\n conversation_id: number\n latestReadMessageSortKey?: string\n inReplyScreen?: boolean\n repliesEnabled?: boolean\n}\n\nexport function Message({\n canDeleteNonAuthoredMessages,\n conversation_id,\n latestReadMessageSortKey,\n inReplyScreen,\n repliesEnabled,\n ...message\n}: MessageProps) {\n const { text, reactionCounts, pending, error } = message\n const styles = useMessageStyles(message)\n const navigation = useNavigation()\n const { colors } = useTheme()\n const hasReactions = reactionCounts.length > 0\n const [showMessageMetaToggle, setShowMessageMetaToggle] = React.useState(false)\n const showMessageMeta =\n showMessageMetaToggle || message.myLatestInConversation || !!pending || !!error || false\n const timestamp = useLiveRelativeTime(message.createdAt)\n const wasEdited = Boolean(message.textEditedAt)\n const isPersisted = !isNewMessage(message)\n const [temporarilyHidePendingState, setTemporarilyHidePendingState] = React.useState(true)\n const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)\n const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =\n useAnimatedMessageBackgroundColor()\n const { message: replyRootMessage } = useConversationMessage({\n conversation_id,\n messageId: message.replyRootId || '',\n enabled: !!message.replyRootId,\n })\n\n const metaProps = {\n authorName: message.author.name,\n createdAt: message.createdAt,\n }\n\n const renderAuthor = (!message.mine && message.renderAuthor) || false\n const showReplyCountButton =\n !inReplyScreen && message.replyRootId === message.id && repliesEnabled\n const isReplyRootMessage = message.replyRootId === message.id\n const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt\n\n const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text\n const replyCountText = pluralize(message.replyCount, 'reply')\n const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'\n const replyRootAuthorName = message.replyRootId\n ? replyRootMessage?.author.name\n : message.author.name\n\n const messageBottomMargin =\n message.lastInGroup || message.nextIsReplyShadowMessage\n ? 16\n : hasReactions || showMessageMeta || showReplyCountButton\n ? 8\n : 4\n\n useEffect(() => {\n if (pending) {\n const timer = setTimeout(() => {\n setTemporarilyHidePendingState(false)\n }, 2000)\n return () => clearTimeout(timer)\n }\n return () => {}\n }, [pending])\n\n const retryFailedSaveMutation = useMessageCreateOrUpdate({\n conversationId: conversation_id,\n message,\n })\n\n const handleRetry = () => {\n if (text && error) {\n retryFailedSaveMutation.mutateAsync({\n text,\n attachments: message.attachmentsForCreate,\n })\n }\n }\n\n const handleMessageLongPress = () => {\n if (!isPersisted) return\n\n Haptic.impactLight()\n navigation.navigate('MessageActions', {\n message_id: message.id,\n conversation_id,\n canDeleteNonAuthoredMessages,\n inReplyScreen,\n reply_root_author_name: replyRootAuthorName,\n })\n }\n const handleReactionLongPress = (reaction: ReactionCountResource) => {\n Haptic.impactLight()\n navigation.navigate('Reactions', {\n message_id: message.id,\n conversation_id,\n reaction_value: reaction.value,\n })\n }\n\n const handleMessageAttachmentLongPress = (attachment: DenormalizedMessageAttachmentResource) => {\n Haptic.impactLight()\n navigation.navigate('AttachmentActions', {\n attachmentId: attachment?.id,\n attachmentContentType: attachment?.attributes.contentType,\n attachmentUrl: attachment?.attributes.url,\n conversation_id,\n canDeleteNonAuthoredMessages,\n myMessage: message.mine,\n })\n }\n\n const handleNavigateToReplyPress = () => {\n navigation.navigate('ConversationReply', {\n conversation_id,\n reply_root_id: message.id,\n reply_root_author_name: message.author.name,\n })\n }\n\n return (\n <Pressable\n onLongPress={handleMessageLongPress}\n onPress={() => setShowMessageMetaToggle(!showMessageMetaToggle)}\n onPressIn={handleMessagePressIn}\n onPressOut={handleMessagePressOut}\n android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}\n accessibilityHint=\"Long press to view message actions like reacting and copying.\"\n >\n <Animated.View style={[styles.message, animatedBackgroundColor]}>\n {!message.mine && (\n <View>\n {renderAuthor ? (\n <Avatar\n size={'md'}\n sourceUri={message.author.avatar}\n style={styles.avatar}\n maxFontSizeMultiplier={1}\n minFontSizeMultiplier={1}\n fallbackIconName={isDeletedReplyRootMessage ? 'publishing.trash' : 'general.person'}\n showFallback={isDeletedReplyRootMessage}\n />\n ) : (\n <View style={styles.avatarPlaceholder} />\n )}\n {repliesEnabled && (\n <TheirReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </View>\n )}\n <View style={[styles.messageContent, { marginBottom: messageBottomMargin }]}>\n {renderAuthor && (\n <Text variant=\"footnote\" style={styles.authorName}>\n {message.author.name}\n </Text>\n )}\n <View\n style={styles.messageBubble}\n onLayout={e => setMessageBubbleHeight(e.nativeEvent.layout.height)}\n >\n <ErrorBoundary>\n <MessageAttachments\n attachments={message.attachments}\n metaProps={metaProps}\n onMessageAttachmentLongPress={handleMessageAttachmentLongPress}\n onMessageLongPress={handleMessageLongPress}\n />\n </ErrorBoundary>\n {messageText && (\n <View style={styles.messageText}>\n <MessageMarkdown text={messageText} />\n </View>\n )}\n </View>\n {showReplyCountButton && (\n <TextButton\n variant=\"footnote\"\n onPress={handleNavigateToReplyPress}\n style={styles.messageReplyCount}\n accessibilityHint=\"Navigates to reply screen for this message\"\n accessibilityRole=\"link\"\n >\n {replyCountText}\n </TextButton>\n )}\n {hasReactions && (\n <View style={styles.messageReactions}>\n {reactionCounts.map(reaction => (\n <MessageReaction\n key={reaction.value}\n reaction={reaction}\n onLongPress={handleReactionLongPress}\n message={message}\n conversationId={conversation_id}\n />\n ))}\n </View>\n )}\n {showMessageMeta && (\n <View style={styles.messageMeta}>\n {message.mine && !pending && !error && (\n <MessageReadReceipts\n message={message}\n latestReadMessageSortKey={latestReadMessageSortKey}\n />\n )}\n {error ? (\n <View style={styles.errorContainer}>\n {retryFailedSaveMutation.isPending ? (\n <Spinner size={12} />\n ) : (\n <Icon name=\"general.exclamationTriangle\" size={12} style={styles.errorIcon} />\n )}\n <Text variant=\"footnote\" style={styles.errorText}>\n Failed to {isPersisted ? 'edit' : 'send'} |{' '}\n <TextInlineButton\n onPress={handleRetry}\n variant=\"footnote\"\n appearance=\"danger\"\n disabled={retryFailedSaveMutation.isPending}\n >\n Try again\n </TextInlineButton>\n </Text>\n </View>\n ) : pending && (!temporarilyHidePendingState || isPersisted) ? (\n <View style={styles.pendingIndicatorContainer}>\n <Icon\n name=\"general.outlinedClock\"\n size={12}\n color={colors.iconColorDefaultSecondary}\n />\n <Text variant=\"footnote\">{messagePendingLabel}</Text>\n </View>\n ) : isPersisted ? (\n <Text variant=\"footnote\">{timestamp}</Text>\n ) : null}\n {!pending && !error && wasEdited && (\n <Text variant=\"footnote\">\n |{' '}\n <Text variant=\"footnote\" style={styles.editedText}>\n Edited\n </Text>\n </Text>\n )}\n </View>\n )}\n </View>\n {repliesEnabled && message.mine && (\n <MyReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </Animated.View>\n </Pressable>\n )\n}\n\nconst useMessageStyles = ({ mine }: MessageResource) => {\n const { colors } = useTheme()\n const myMessageBackgroundColor = useInteractionGhostBackgroundColor()\n const { width } = useWindowDimensions()\n const tabletWidth = width >= 744 // Smallest iPad Mini's width\n\n const messageBubbleBackgroundColor = mine ? myMessageBackgroundColor : colors.fillColorNeutral070\n\n return StyleSheet.create({\n message: {\n gap: 8,\n flexDirection: mine ? 'row-reverse' : 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n },\n messageContent: {\n flex: 1,\n gap: 4,\n },\n avatar: {\n marginBottom: AVATAR_CONNECTOR_SPACING,\n },\n avatarPlaceholder: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH, // Same width as avatar\n },\n authorName: {\n fontWeight: platformFontWeightMedium,\n },\n messageBubble: {\n backgroundColor: messageBubbleBackgroundColor,\n borderRadius: 8,\n maxWidth: tabletWidth ? 360 : '80%',\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageText: {\n paddingVertical: 6,\n paddingHorizontal: 8,\n },\n messageReactions: {\n flexDirection: 'row',\n gap: 4,\n justifyContent: mine ? 'flex-end' : 'flex-start',\n },\n messageReplyCount: {\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageMeta: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: mine ? 'flex-end' : 'flex-start',\n gap: 4,\n },\n editedText: {\n fontWeight: platformFontWeightMedium,\n },\n pendingIndicatorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorIcon: {\n color: colors.statusErrorIcon,\n },\n errorText: {\n color: colors.statusErrorText,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"message.js","sourceRoot":"","sources":["../../../src/components/conversation/message.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport React, { useEffect } from 'react'\nimport { Pressable, StyleSheet, useWindowDimensions, View } from 'react-native'\nimport { MessageReaction } from '../../components/conversation/message_reaction'\nimport { Avatar, Icon, Spinner, Text, TextButton, TextInlineButton } from '../../components/display'\nimport {\n useAnimatedMessageBackgroundColor,\n useInteractionGhostBackgroundColor,\n useTheme,\n} from '../../hooks'\nimport { MessageResource } from '../../types'\nimport { ReactionCountResource } from '../../types/resources/reaction'\nimport { MessageAttachments } from './message_attachments'\nimport ErrorBoundary from '../page/error_boundary'\nimport { MessageMarkdown } from './message_markdown'\nimport { DenormalizedMessageAttachmentResource } from '../../types/resources/denormalized_attachment_resource'\nimport {\n CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH,\n platformFontWeightMedium,\n} from '../../utils/styles'\nimport Animated from 'react-native-reanimated'\nimport { useLiveRelativeTime } from '../../hooks/use_live_relative_time'\nimport { MessageReadReceipts } from './message_read_receipts'\nimport { useMessageCreateOrUpdate } from '../../hooks/use_message_create_or_update'\nimport { Haptic } from '../../utils/native_adapters'\nimport { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from './reply_connectors'\nimport { pluralize } from '../../utils'\nimport { useConversationMessage } from '../../hooks/use_conversation_message'\nimport { isNewMessage } from '../../utils/cache/messages_cache'\n\n/** Message\n * Component for display of a message within a conversation list\n */\ninterface MessageProps extends MessageResource {\n canDeleteNonAuthoredMessages: boolean\n conversation_id: number\n latestReadMessageSortKey?: string\n inReplyScreen?: boolean\n repliesEnabled?: boolean\n}\n\nexport function Message({\n canDeleteNonAuthoredMessages,\n conversation_id,\n latestReadMessageSortKey,\n inReplyScreen,\n repliesEnabled,\n ...message\n}: MessageProps) {\n const { text, reactionCounts, pending, error } = message\n const styles = useMessageStyles(message)\n const navigation = useNavigation()\n const { colors } = useTheme()\n const hasReactions = reactionCounts.length > 0\n const [showMessageMetaToggle, setShowMessageMetaToggle] = React.useState(false)\n const showMessageMeta =\n showMessageMetaToggle || message.myLatestInConversation || !!pending || !!error || false\n const timestamp = useLiveRelativeTime(message.createdAt)\n const wasEdited = Boolean(message.textEditedAt)\n const isPersisted = !isNewMessage(message)\n const [temporarilyHidePendingState, setTemporarilyHidePendingState] = React.useState(true)\n const [messageBubbleHeight, setMessageBubbleHeight] = React.useState(0)\n const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =\n useAnimatedMessageBackgroundColor()\n const { message: replyRootMessage } = useConversationMessage({\n conversation_id,\n messageId: message.replyRootId || '',\n enabled: !!message.replyRootId,\n })\n\n const metaProps = {\n authorName: message.author.name,\n createdAt: message.createdAt,\n }\n\n const renderAuthor = (!message.mine && message.renderAuthor) || false\n const showReplyCountButton =\n !inReplyScreen && message.replyRootId === message.id && repliesEnabled\n const isReplyRootMessage = message.replyRootId === message.id\n const isDeletedReplyRootMessage = isReplyRootMessage && !!message.deletedAt\n\n const messageText = isDeletedReplyRootMessage ? 'Message deleted' : text\n const replyCountText = pluralize(message.replyCount, 'reply')\n const messagePendingLabel = isPersisted ? 'Saving' : 'Sending'\n const replyRootAuthorName = message.replyRootId\n ? replyRootMessage?.author.name\n : message.author.name\n\n const messageBottomMargin =\n message.lastInGroup || message.nextIsReplyShadowMessage\n ? 16\n : hasReactions || showMessageMeta || showReplyCountButton\n ? 8\n : 4\n\n useEffect(() => {\n if (pending) {\n const timer = setTimeout(() => {\n setTemporarilyHidePendingState(false)\n }, 2000)\n return () => clearTimeout(timer)\n }\n return () => {}\n }, [pending])\n\n const retryFailedSaveMutation = useMessageCreateOrUpdate({\n conversationId: conversation_id,\n message,\n })\n\n const handleRetry = () => {\n if (text && error) {\n retryFailedSaveMutation.mutateAsync({\n text,\n attachments: message.attachmentsForCreate,\n })\n }\n }\n\n const handleMessageLongPress = () => {\n if (!isPersisted) return\n\n Haptic.impactLight()\n navigation.navigate('MessageActions', {\n message_id: message.id,\n conversation_id,\n canDeleteNonAuthoredMessages,\n inReplyScreen,\n reply_root_author_name: replyRootAuthorName,\n })\n }\n const handleReactionLongPress = (reaction: ReactionCountResource) => {\n Haptic.impactLight()\n navigation.navigate('Reactions', {\n message_id: message.id,\n conversation_id,\n reaction_value: reaction.value,\n })\n }\n\n const handleMessageAttachmentLongPress = (attachment: DenormalizedMessageAttachmentResource) => {\n Haptic.impactLight()\n navigation.navigate('AttachmentActions', {\n attachmentId: attachment?.id,\n attachmentContentType: attachment?.attributes.contentType,\n attachmentUrl: attachment?.attributes.url,\n conversation_id,\n canDeleteNonAuthoredMessages,\n myMessage: message.mine,\n })\n }\n\n const handleNavigateToReplyPress = () => {\n navigation.navigate('ConversationReply', {\n conversation_id,\n reply_root_id: message.id,\n reply_root_author_name: message.author.name,\n })\n }\n\n return (\n <Pressable\n onLongPress={handleMessageLongPress}\n onPress={() => setShowMessageMetaToggle(!showMessageMetaToggle)}\n onPressIn={handleMessagePressIn}\n onPressOut={handleMessagePressOut}\n android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}\n accessibilityHint=\"Long press to view message actions like reacting and copying.\"\n >\n <Animated.View style={[styles.message, animatedBackgroundColor]}>\n {!message.mine && (\n <View>\n {renderAuthor ? (\n <Avatar\n size={'md'}\n sourceUri={message.author.avatar}\n style={styles.avatar}\n maxFontSizeMultiplier={1}\n minFontSizeMultiplier={1}\n fallbackIconName={isDeletedReplyRootMessage ? 'publishing.trash' : 'general.person'}\n showFallback={isDeletedReplyRootMessage}\n />\n ) : (\n <View style={styles.avatarPlaceholder} />\n )}\n {repliesEnabled && (\n <TheirReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </View>\n )}\n <View style={[styles.messageContent, { marginBottom: messageBottomMargin }]}>\n {renderAuthor && (\n <Text variant=\"footnote\" style={styles.authorName}>\n {message.author.name}\n </Text>\n )}\n <View\n style={styles.messageBubble}\n onLayout={e => setMessageBubbleHeight(e.nativeEvent.layout.height)}\n >\n <ErrorBoundary>\n <MessageAttachments\n attachments={message.attachments}\n metaProps={metaProps}\n onMessageAttachmentLongPress={handleMessageAttachmentLongPress}\n onMessageLongPress={handleMessageLongPress}\n />\n </ErrorBoundary>\n {messageText && (\n <View style={styles.messageText}>\n <MessageMarkdown text={messageText} />\n </View>\n )}\n </View>\n {showReplyCountButton && (\n <TextButton\n variant=\"footnote\"\n onPress={handleNavigateToReplyPress}\n style={styles.messageReplyCount}\n accessibilityHint=\"Navigates to reply screen for this message\"\n accessibilityRole=\"link\"\n >\n {replyCountText}\n </TextButton>\n )}\n {hasReactions && (\n <View style={styles.messageReactions}>\n {reactionCounts.map(reaction => (\n <MessageReaction\n key={reaction.value}\n reaction={reaction}\n onLongPress={handleReactionLongPress}\n message={message}\n conversationId={conversation_id}\n />\n ))}\n </View>\n )}\n {showMessageMeta && (\n <View style={styles.messageMeta}>\n {message.mine && !pending && !error && (\n <MessageReadReceipts\n message={message}\n latestReadMessageSortKey={latestReadMessageSortKey}\n />\n )}\n {error ? (\n <View style={styles.errorContainer}>\n {retryFailedSaveMutation.isPending ? (\n <Spinner size={12} />\n ) : (\n <Icon name=\"general.exclamationTriangle\" size={12} style={styles.errorIcon} />\n )}\n <Text variant=\"footnote\" style={styles.errorText}>\n Failed to {isPersisted ? 'edit' : 'send'} |{' '}\n <TextInlineButton\n onPress={handleRetry}\n variant=\"footnote\"\n appearance=\"danger\"\n disabled={retryFailedSaveMutation.isPending}\n >\n Try again\n </TextInlineButton>\n </Text>\n </View>\n ) : pending && (!temporarilyHidePendingState || isPersisted) ? (\n <View style={styles.pendingIndicatorContainer}>\n <Icon\n name=\"general.outlinedClock\"\n size={12}\n color={colors.iconColorDefaultSecondary}\n />\n <Text variant=\"footnote\">{messagePendingLabel}</Text>\n </View>\n ) : isPersisted ? (\n <Text variant=\"footnote\">{timestamp}</Text>\n ) : null}\n {!pending && !error && wasEdited && (\n <Text variant=\"footnote\">\n |{' '}\n <Text variant=\"footnote\" style={styles.editedText}>\n Edited\n </Text>\n </Text>\n )}\n </View>\n )}\n </View>\n {repliesEnabled && message.mine && (\n <MyReplyConnector message={message} messageBubbleHeight={messageBubbleHeight} />\n )}\n </Animated.View>\n </Pressable>\n )\n}\n\nconst useMessageStyles = ({ mine }: MessageResource) => {\n const { colors } = useTheme()\n const myMessageBackgroundColor = useInteractionGhostBackgroundColor()\n const { width } = useWindowDimensions()\n const tabletWidth = width >= 744 // Smallest iPad Mini's width\n\n const messageBubbleBackgroundColor = mine ? myMessageBackgroundColor : colors.fillColorNeutral070\n\n return StyleSheet.create({\n message: {\n gap: 8,\n flexDirection: mine ? 'row-reverse' : 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n },\n messageContent: {\n flex: 1,\n gap: 4,\n },\n avatar: {\n marginBottom: AVATAR_CONNECTOR_SPACING,\n },\n avatarPlaceholder: {\n width: MESSAGE_AUTHOR_AVATAR_COLUMN_WIDTH, // Same width as avatar\n },\n authorName: {\n fontWeight: platformFontWeightMedium,\n },\n messageBubble: {\n backgroundColor: messageBubbleBackgroundColor,\n borderRadius: 8,\n maxWidth: tabletWidth ? 360 : '80%',\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageText: {\n paddingVertical: 6,\n paddingHorizontal: 8,\n },\n messageReactions: {\n flexDirection: 'row',\n gap: 4,\n justifyContent: mine ? 'flex-end' : 'flex-start',\n },\n messageReplyCount: {\n alignSelf: mine ? 'flex-end' : 'flex-start',\n },\n messageMeta: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: mine ? 'flex-end' : 'flex-start',\n gap: 4,\n },\n editedText: {\n fontWeight: platformFontWeightMedium,\n },\n pendingIndicatorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorContainer: {\n flexDirection: 'row',\n alignItems: 'center',\n gap: 4,\n },\n errorIcon: {\n color: colors.statusErrorIcon,\n },\n errorText: {\n color: colors.statusErrorText,\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAUtC,UAAU,kBAAkB;IAC1B,mBAAmB,CAAC,EAChB,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GACxB,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAClE,IAAI,GACJ,SAAS,CAAA;CACd;AAED,eAAO,MAAM,aAAa,4BAA6B,kBAAkB,sBA8ExE,CAAA"}
1
+ {"version":3,"file":"conversations.d.ts","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AACA,OAAO,KAAkB,MAAM,OAAO,CAAA;AAUtC,UAAU,kBAAkB;IAC1B,mBAAmB,CAAC,EAChB,KAAK,CAAC,aAAa,CAAC,GAAG,CAAC,GACxB,KAAK,CAAC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,GAClE,IAAI,GACJ,SAAS,CAAA;CACd;AAED,eAAO,MAAM,aAAa,4BAA6B,kBAAkB,sBA6ExE,CAAA"}
@@ -1,7 +1,6 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
- import { FlashList } from '@shopify/flash-list';
3
2
  import React, { useMemo } from 'react';
4
- import { StyleSheet, View } from 'react-native';
3
+ import { FlatList, StyleSheet, View } from 'react-native';
5
4
  import { useConversationsContext } from '../../contexts/conversations_context';
6
5
  import { useTheme } from '../../hooks';
7
6
  import { throwResponseError } from '../../utils/response_error';
@@ -28,7 +27,7 @@ export const Conversations = ({ ListHeaderComponent }) => {
28
27
  }
29
28
  useConversationsJoltEvents();
30
29
  return (<View style={styles.container}>
31
- <FlashList data={data} estimatedItemSize={97} keyExtractor={item => item.id.toString()} contentContainerStyle={styles.contentContainer} onRefresh={refetch} refreshing={!isFetched && isRefetching} ListHeaderComponent={ListHeaderComponent} ListEmptyComponent={<View style={styles.listEmpty}>
30
+ <FlatList data={data} keyExtractor={item => item.id.toString()} contentContainerStyle={styles.contentContainer} onRefresh={refetch} refreshing={!isFetched && isRefetching} ListHeaderComponent={ListHeaderComponent} ListEmptyComponent={<View style={styles.listEmpty}>
32
31
  <BlankState.Root>
33
32
  <BlankState.Imagery name="general.outlinedTextMessage"/>
34
33
  <BlankState.Content>
@@ -1 +1 @@
1
- {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,KAAK,EAAE,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AACtC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAA;AAC9E,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,UAAU,MAAM,oCAAoC,CAAA;AAC3D,OAAO,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAA;AACzF,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAA;AAUtF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,EAAE,mBAAmB,EAAsB,EAAE,EAAE;IAC3E,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EACJ,aAAa,EACb,SAAS,EACT,aAAa,EACb,OAAO,EACP,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,IAAI,EAAE,EAAE,mBAAmB,EAAE,GAC9B,GAAG,uBAAuB,EAAE,CAAA;IAC7B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAElC,MAAM,UAAU,GAAG,CAAC,mBAAmB,CAAA;IAEvC,MAAM,IAAI,GAAoB,OAAO,CAAC,GAAG,EAAE;QACzC,IAAI,SAAS,EAAE,CAAC;YACd,OAAO,kBAAkB,CAAA;QAC3B,CAAC;QACD,OAAO,aAAa,CAAC,GAAG,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;YACxC,IAAI,EAAE,cAAuB;YAC7B,EAAE,EAAE,YAAY,CAAC,EAAE;YACnB,QAAQ,EAAE,YAAY;SACvB,CAAC,CAAC,CAAA;IACL,CAAC,EAAE,CAAC,aAAa,EAAE,SAAS,CAAC,CAAC,CAAA;IAE9B,IAAI,OAAO,EAAE,CAAC;QACZ,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,0BAA0B,EAAE,CAAA;IAE5B,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,SAAS,CACR,IAAI,CAAC,CAAC,IAAI,CAAC,CACX,iBAAiB,CAAC,CAAC,EAAE,CAAC,CACtB,YAAY,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CACzC,qBAAqB,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CAC/C,SAAS,CAAC,CAAC,OAAO,CAAC,CACnB,UAAU,CAAC,CAAC,CAAC,SAAS,IAAI,YAAY,CAAC,CACvC,mBAAmB,CAAC,CAAC,mBAAmB,CAAC,CACzC,kBAAkB,CAAC,CACjB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;YAAA,CAAC,UAAU,CAAC,IAAI,CACd;cAAA,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,6BAA6B,EACtD;cAAA,CAAC,UAAU,CAAC,OAAO,CACjB;gBAAA,CAAC,UAAU,CAAC,OAAO,CAAC,gBAAgB,EAAE,UAAU,CAAC,OAAO,CAC1D;cAAA,EAAE,UAAU,CAAC,OAAO,CACtB;YAAA,EAAE,UAAU,CAAC,IAAI,CACnB;UAAA,EAAE,IAAI,CACR,CAAC,CACD,UAAU,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE;YACvB,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC5B,OAAO,CAAC,2BAA2B,CAAC,AAAD,EAAG,CAAA;YACxC,CAAC;iBAAM,CAAC;gBACN,OAAO,CACL,CAAC,mBAAmB,CAClB,YAAY,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAC5B,OAAO,CAAC,CAAC,GAAG,EAAE,CACZ,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE;wBAClC,eAAe,EAAE,IAAI,CAAC,QAAQ,CAAC,EAAE;wBACjC,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,KAAK;wBAC1B,KAAK,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;wBAChC,OAAO,EAAE,IAAI,CAAC,QAAQ,CAAC,OAAO;qBAC/B,CACH,CAAC,CACD,UAAU,CAAC,CAAC,UAAU,CAAC,EACvB,CACH,CAAA;YACH,CAAC;QACH,CAAC,CAAC,CACF,YAAY,CAAC,CAAC,GAAG,EAAE,CAAC,aAAa,EAAE,CAAC,EAExC;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC,CAAA;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE;QACtB,gBAAgB,EAAE,EAAE,eAAe,EAAE,EAAE,EAAE;QACzC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,CAAC,mBAAmB,EAAE;QAC/C,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,cAAc,EAAE,QAAQ;YACxB,UAAU,EAAE,QAAQ;YACpB,eAAe,EAAE,EAAE;SACpB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA;AAaD,MAAM,kBAAkB,GAAoB,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;IAC/E,IAAI,EAAE,SAAS;IACf,EAAE,EAAE,UAAU,CAAC,EAAE;CAClB,CAAC,CAAC,CAAA","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport { FlashList } from '@shopify/flash-list'\nimport React, { useMemo } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useConversationsContext } from '../../contexts/conversations_context'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types'\nimport { throwResponseError } from '../../utils/response_error'\nimport BlankState from '../primitive/blank_state_primitive'\nimport { ConversationPreview, ConversationPreviewSkeleton } from './conversation_preview'\nimport { useConversationsJoltEvents } from '../../hooks/use_conversations_jolt_events'\n\ninterface ConversationsProps {\n ListHeaderComponent?:\n | React.ComponentType<any>\n | React.ReactElement<any, string | React.JSXElementConstructor<any>>\n | null\n | undefined\n}\n\nexport const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {\n const styles = useStyles()\n const {\n conversations,\n isLoading,\n fetchNextPage,\n refetch,\n isRefetching,\n isFetched,\n isError,\n error,\n args: { chat_group_graph_id },\n } = useConversationsContext()\n const navigation = useNavigation()\n\n const showBadges = !chat_group_graph_id\n\n const data: FlashListItem[] = useMemo(() => {\n if (isLoading) {\n return loadingPlaceholder\n }\n return conversations.map(conversation => ({\n type: 'conversation' as const,\n id: conversation.id,\n resource: conversation,\n }))\n }, [conversations, isLoading])\n\n if (isError) {\n throwResponseError(error)\n }\n\n useConversationsJoltEvents()\n\n return (\n <View style={styles.container}>\n <FlashList\n data={data}\n estimatedItemSize={97}\n keyExtractor={item => item.id.toString()}\n contentContainerStyle={styles.contentContainer}\n onRefresh={refetch}\n refreshing={!isFetched && isRefetching}\n ListHeaderComponent={ListHeaderComponent}\n ListEmptyComponent={\n <View style={styles.listEmpty}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>No conversations</BlankState.Heading>\n </BlankState.Content>\n </BlankState.Root>\n </View>\n }\n renderItem={({ item }) => {\n if (item.type === 'loading') {\n return <ConversationPreviewSkeleton />\n } else {\n return (\n <ConversationPreview\n conversation={item.resource}\n onPress={() =>\n navigation.navigate('Conversation', {\n conversation_id: item.resource.id,\n title: item.resource.title,\n badge: item.resource.badges?.[0],\n deleted: item.resource.deleted,\n })\n }\n showBadges={showBadges}\n />\n )\n }\n }}\n onEndReached={() => fetchNextPage()}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: { flex: 1 },\n contentContainer: { paddingVertical: 16 },\n listItem: { color: colors.fillColorNeutral020 },\n listEmpty: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n paddingVertical: 32,\n },\n })\n}\n\ninterface FlashListLoadingItem {\n type: 'loading'\n id: string\n}\ninterface FlashListConversationItem {\n type: 'conversation'\n resource: ConversationResource\n id: number\n}\ntype FlashListItem = FlashListLoadingItem | FlashListConversationItem\n\nconst loadingPlaceholder: FlashListItem[] = Array.from({ length: 5 }, (_, i) => ({\n type: 'loading',\n id: `loading${i}`,\n}))\n"]}
1
+ {"version":3,"file":"conversations.js","sourceRoot":"","sources":["../../../src/components/conversations/conversations.tsx"],"names":[],"mappings":"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","sourcesContent":["import { useNavigation } from '@react-navigation/native'\nimport React, { useMemo } from 'react'\nimport { FlatList, StyleSheet, View } from 'react-native'\nimport { useConversationsContext } from '../../contexts/conversations_context'\nimport { useTheme } from '../../hooks'\nimport { ConversationResource } from '../../types'\nimport { throwResponseError } from '../../utils/response_error'\nimport BlankState from '../primitive/blank_state_primitive'\nimport { ConversationPreview, ConversationPreviewSkeleton } from './conversation_preview'\nimport { useConversationsJoltEvents } from '../../hooks/use_conversations_jolt_events'\n\ninterface ConversationsProps {\n ListHeaderComponent?:\n | React.ComponentType<any>\n | React.ReactElement<any, string | React.JSXElementConstructor<any>>\n | null\n | undefined\n}\n\nexport const Conversations = ({ ListHeaderComponent }: ConversationsProps) => {\n const styles = useStyles()\n const {\n conversations,\n isLoading,\n fetchNextPage,\n refetch,\n isRefetching,\n isFetched,\n isError,\n error,\n args: { chat_group_graph_id },\n } = useConversationsContext()\n const navigation = useNavigation()\n\n const showBadges = !chat_group_graph_id\n\n const data: FlatListItem[] = useMemo(() => {\n if (isLoading) {\n return loadingPlaceholder\n }\n return conversations.map(conversation => ({\n type: 'conversation' as const,\n id: conversation.id,\n resource: conversation,\n }))\n }, [conversations, isLoading])\n\n if (isError) {\n throwResponseError(error)\n }\n\n useConversationsJoltEvents()\n\n return (\n <View style={styles.container}>\n <FlatList\n data={data}\n keyExtractor={item => item.id.toString()}\n contentContainerStyle={styles.contentContainer}\n onRefresh={refetch}\n refreshing={!isFetched && isRefetching}\n ListHeaderComponent={ListHeaderComponent}\n ListEmptyComponent={\n <View style={styles.listEmpty}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>No conversations</BlankState.Heading>\n </BlankState.Content>\n </BlankState.Root>\n </View>\n }\n renderItem={({ item }) => {\n if (item.type === 'loading') {\n return <ConversationPreviewSkeleton />\n } else {\n return (\n <ConversationPreview\n conversation={item.resource}\n onPress={() =>\n navigation.navigate('Conversation', {\n conversation_id: item.resource.id,\n title: item.resource.title,\n badge: item.resource.badges?.[0],\n deleted: item.resource.deleted,\n })\n }\n showBadges={showBadges}\n />\n )\n }\n }}\n onEndReached={() => fetchNextPage()}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: { flex: 1 },\n contentContainer: { paddingVertical: 16 },\n listItem: { color: colors.fillColorNeutral020 },\n listEmpty: {\n flex: 1,\n justifyContent: 'center',\n alignItems: 'center',\n paddingVertical: 32,\n },\n })\n}\n\ninterface FlatListLoadingItem {\n type: 'loading'\n id: string\n}\ninterface FlatListConversationItem {\n type: 'conversation'\n resource: ConversationResource\n id: number\n}\ntype FlatListItem = FlatListLoadingItem | FlatListConversationItem\n\nconst loadingPlaceholder: FlatListItem[] = Array.from({ length: 5 }, (_, i) => ({\n type: 'loading',\n id: `loading${i}`,\n}))\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AAoBA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,iCAAiC,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,QA+H1E"}
1
+ {"version":3,"file":"use_conversation_messages_jolt_events.d.ts","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AAmBA,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,wBAAgB,iCAAiC,CAAC,EAAE,cAAc,EAAE,EAAE,KAAK,QAsF1E"}
@@ -1,15 +1,14 @@
1
1
  import { useJoltChannel, useJoltEvent } from './use_jolt';
2
- import { deleteRecordInPagesData, updateOrCreateRecordInPagesData, updateRecordInPagesData, } from '../utils';
2
+ import { deleteRecordInPagesData } from '../utils';
3
3
  import { useQueryClient } from '@tanstack/react-query';
4
4
  import { useCurrentPerson } from './use_current_person';
5
5
  import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource';
6
6
  import { getRequestQueryKey } from './use_suspense_api';
7
- import { transformReactionEventDataToReactionCountResource } from '../utils/jolt/transform_reaction_event_data_to_reaction_count_resource';
8
7
  import { getMessagesRequestArgs } from '../utils/request/get_messages';
9
8
  import { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache';
10
- import { isTemporaryMessageId } from './use_message_create_or_update';
11
9
  import { completeMessageCreationTracking } from '../utils/performance_tracking';
12
10
  import { useApiClient } from './use_api_client';
11
+ import { updateCacheWithMessage, updateCacheWithReaction, getThreadedMessagesQueryKey, } from '../utils/cache/messages_cache';
13
12
  export function useConversationMessagesJoltEvents({ conversationId }) {
14
13
  const queryClient = useQueryClient();
15
14
  const currentPerson = useCurrentPerson();
@@ -30,40 +29,13 @@ export function useConversationMessagesJoltEvents({ conversationId }) {
30
29
  completeMessageCreationTracking({ apiClient, idempotentKey: data.idempotent_key });
31
30
  }
32
31
  }
33
- queryClient.setQueryData(messagesQueryKey, prev => {
34
- if (e.event === 'message.created') {
35
- // Before adding the new message, remove any pending temporary messages
36
- // with matching text to prevent duplicates from race conditions
37
- let dataAfterTempRemoval = prev;
38
- if (prev && message.text && message.mine) {
39
- dataAfterTempRemoval = deleteRecordInPagesData({
40
- data: prev,
41
- record: message,
42
- matchFn: (existingMessage, _record) => {
43
- return (isTemporaryMessageId(existingMessage.id) &&
44
- existingMessage.text === message.text &&
45
- existingMessage.mine);
46
- },
47
- });
48
- }
49
- return updateOrCreateRecordInPagesData({
50
- data: dataAfterTempRemoval,
51
- record: message,
52
- processRecord: (record, current) => {
53
- return { ...current, ...record };
54
- },
55
- });
56
- }
57
- else {
58
- return updateRecordInPagesData({
59
- data: prev,
60
- record: message,
61
- processRecord: (record, current) => {
62
- return { ...current, ...record };
63
- },
64
- });
65
- }
66
- });
32
+ // Update the main conversation cache
33
+ updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event);
34
+ // If message has a reply_root_id, also update the threaded cache
35
+ if (data.reply_root_id) {
36
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, data.reply_root_id);
37
+ updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event);
38
+ }
67
39
  };
68
40
  const handleMessageDeleted = async (e) => {
69
41
  const { data } = e.data;
@@ -71,42 +43,23 @@ export function useConversationMessagesJoltEvents({ conversationId }) {
71
43
  data,
72
44
  currentPersonId: currentPerson.id,
73
45
  });
46
+ // Update the main conversation cache
74
47
  queryClient.setQueryData(messagesQueryKey, prev => deleteRecordInPagesData({ data: prev, record: message }));
48
+ // If message has a reply_root_id, also update the threaded cache
49
+ if (data.reply_root_id) {
50
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, data.reply_root_id);
51
+ queryClient.setQueryData(threadedMessagesQueryKey, prev => deleteRecordInPagesData({ data: prev, record: message }));
52
+ }
75
53
  };
76
54
  const handleReactionJoltEvent = async (e) => {
77
- const { data } = e.data;
78
- const message = { id: data.message_sort_key };
79
- queryClient.setQueryData(messagesQueryKey, prev => updateRecordInPagesData({
80
- data: prev,
81
- record: message,
82
- processRecord: (record, oldMessage) => {
83
- const reactionCounts = oldMessage.reactionCounts || [];
84
- let foundMatch = false;
85
- let newReactionCounts = reactionCounts.map(reactionCount => {
86
- if (reactionCount.value === data.value) {
87
- foundMatch = true;
88
- return transformReactionEventDataToReactionCountResource({
89
- data,
90
- oldData: reactionCount,
91
- event: e.event,
92
- currentPersonId: currentPerson.id,
93
- });
94
- }
95
- return reactionCount;
96
- });
97
- if (!foundMatch) {
98
- const newReactionCount = transformReactionEventDataToReactionCountResource({
99
- data,
100
- event: e.event,
101
- currentPersonId: currentPerson.id,
102
- });
103
- if (newReactionCount?.count) {
104
- newReactionCounts = [...newReactionCounts, newReactionCount];
105
- }
106
- }
107
- return { ...oldMessage, reactionCounts: newReactionCounts };
108
- },
109
- }));
55
+ // Update the main conversation cache and capture the reply_root_id if present
56
+ updateCacheWithReaction(queryClient, messagesQueryKey, e, currentPerson.id);
57
+ const replyRootId = e.data.data.reply_root_id;
58
+ // If the message has a reply_root_id, also update the threaded cache
59
+ if (replyRootId) {
60
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, replyRootId);
61
+ updateCacheWithReaction(queryClient, threadedMessagesQueryKey, e, currentPerson.id);
62
+ }
110
63
  };
111
64
  const handleTypingEvent = async (e) => {
112
65
  const { data } = e.data;
@@ -1 +1 @@
1
- {"version":3,"file":"use_conversation_messages_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AACzD,OAAO,EACL,uBAAuB,EACvB,+BAA+B,EAC/B,uBAAuB,GACxB,MAAM,UAAU,CAAA;AAEjB,OAAO,EAAgB,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACpE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvD,OAAO,EAAE,0CAA0C,EAAE,MAAM,gEAAgE,CAAA;AAC3H,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAEvD,OAAO,EAAE,iDAAiD,EAAE,MAAM,wEAAwE,CAAA;AAC1I,OAAO,EAAE,sBAAsB,EAAE,MAAM,+BAA+B,CAAA;AACtE,OAAO,EAAE,uBAAuB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AACzF,OAAO,EAAE,oBAAoB,EAAE,MAAM,gCAAgC,CAAA;AACrE,OAAO,EAAE,+BAA+B,EAAE,MAAM,+BAA+B,CAAA;AAC/E,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAM/C,MAAM,UAAU,iCAAiC,CAAC,EAAE,cAAc,EAAS;IACzE,MAAM,WAAW,GAAG,cAAc,EAAE,CAAA;IACpC,MAAM,aAAa,GAAG,gBAAgB,EAAE,CAAA;IACxC,MAAM,WAAW,GAAG,cAAc,CAAC,sBAAsB,cAAc,EAAE,CAAC,CAAA;IAC1E,MAAM,mBAAmB,GAAG,sBAAsB,CAAC,EAAE,eAAe,EAAE,cAAc,EAAE,CAAC,CAAA;IACvF,MAAM,gBAAgB,GAAG,kBAAkB,CAAC,mBAAmB,CAAC,CAAA;IAChE,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,MAAM,EAAE,cAAc,EAAE,qBAAqB,EAAE,+BAA+B,EAAE,GAC9E,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAEtC,MAAM,2BAA2B,GAAG,KAAK,EAAE,CAAsB,EAAE,EAAE;QACnE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,MAAM,OAAO,GAAG,0CAA0C,CAAC;YACzD,IAAI;YACJ,eAAe,EAAE,aAAa,CAAC,EAAE;SAClC,CAAC,CAAA;QAEF,IAAI,CAAC,CAAC,KAAK,KAAK,iBAAiB,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;YACpD,+BAA+B,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC/C,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,SAAS,KAAK,aAAa,CAAC,EAAE,EAAE,CAAC;gBAC/D,+BAA+B,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA;YACpF,CAAC;QACH,CAAC;QAED,WAAW,CAAC,YAAY,CAAY,gBAAgB,EAAE,IAAI,CAAC,EAAE;YAC3D,IAAI,CAAC,CAAC,KAAK,KAAK,iBAAiB,EAAE,CAAC;gBAClC,uEAAuE;gBACvE,gEAAgE;gBAChE,IAAI,oBAAoB,GAAG,IAAI,CAAA;gBAC/B,IAAI,IAAI,IAAI,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC;oBACzC,oBAAoB,GAAG,uBAAuB,CAAC;wBAC7C,IAAI,EAAE,IAAI;wBACV,MAAM,EAAE,OAAO;wBACf,OAAO,EAAE,CAAC,eAAe,EAAE,OAAO,EAAE,EAAE;4BACpC,OAAO,CACL,oBAAoB,CAAC,eAAe,CAAC,EAAE,CAAC;gCACxC,eAAe,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI;gCACrC,eAAe,CAAC,IAAI,CACrB,CAAA;wBACH,CAAC;qBACF,CAAC,CAAA;gBACJ,CAAC;gBAED,OAAO,+BAA+B,CAAC;oBACrC,IAAI,EAAE,oBAAoB;oBAC1B,MAAM,EAAE,OAAO;oBACf,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;wBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;oBAClC,CAAC;iBACF,CAAC,CAAA;YACJ,CAAC;iBAAM,CAAC;gBACN,OAAO,uBAAuB,CAAC;oBAC7B,IAAI,EAAE,IAAI;oBACV,MAAM,EAAE,OAAO;oBACf,aAAa,EAAE,CAAC,MAAM,EAAE,OAAO,EAAE,EAAE;wBACjC,OAAO,EAAE,GAAG,OAAO,EAAE,GAAG,MAAM,EAAE,CAAA;oBAClC,CAAC;iBACF,CAAC,CAAA;YACJ,CAAC;QACH,CAAC,CAAC,CAAA;IACJ,CAAC,CAAA;IAED,MAAM,oBAAoB,GAAG,KAAK,EAAE,CAAsB,EAAE,EAAE;QAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,MAAM,OAAO,GAAG,0CAA0C,CAAC;YACzD,IAAI;YACJ,eAAe,EAAE,aAAa,CAAC,EAAE;SAClC,CAAC,CAAA;QAEF,WAAW,CAAC,YAAY,CAAY,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAC3D,uBAAuB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CACzD,CAAA;IACH,CAAC,CAAA;IAED,MAAM,uBAAuB,GAAG,KAAK,EAAE,CAAoB,EAAE,EAAE;QAC7D,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,MAAM,OAAO,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,gBAAgB,EAAqB,CAAA;QAChE,WAAW,CAAC,YAAY,CAAY,gBAAgB,EAAE,IAAI,CAAC,EAAE,CAC3D,uBAAuB,CAAC;YACtB,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,OAAO;YACf,aAAa,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,EAAE;gBACpC,MAAM,cAAc,GAAG,UAAU,CAAC,cAAc,IAAI,EAAE,CAAA;gBACtD,IAAI,UAAU,GAAG,KAAK,CAAA;gBACtB,IAAI,iBAAiB,GAAG,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE;oBACzD,IAAI,aAAa,CAAC,KAAK,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;wBACvC,UAAU,GAAG,IAAI,CAAA;wBACjB,OAAO,iDAAiD,CAAC;4BACvD,IAAI;4BACJ,OAAO,EAAE,aAAa;4BACtB,KAAK,EAAE,CAAC,CAAC,KAAK;4BACd,eAAe,EAAE,aAAa,CAAC,EAAE;yBAClC,CAAC,CAAA;oBACJ,CAAC;oBACD,OAAO,aAAa,CAAA;gBACtB,CAAC,CAAC,CAAA;gBAEF,IAAI,CAAC,UAAU,EAAE,CAAC;oBAChB,MAAM,gBAAgB,GAAG,iDAAiD,CAAC;wBACzE,IAAI;wBACJ,KAAK,EAAE,CAAC,CAAC,KAAK;wBACd,eAAe,EAAE,aAAa,CAAC,EAAE;qBAClC,CAAC,CAAA;oBAEF,IAAI,gBAAgB,EAAE,KAAK,EAAE,CAAC;wBAC5B,iBAAiB,GAAG,CAAC,GAAG,iBAAiB,EAAE,gBAAgB,CAAC,CAAA;oBAC9D,CAAC;gBACH,CAAC;gBAED,OAAO,EAAE,GAAG,UAAU,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAA;YAC7D,CAAC;SACF,CAAC,CACH,CAAA;IACH,CAAC,CAAA;IAED,MAAM,iBAAiB,GAAG,KAAK,EAAE,CAAkB,EAAE,EAAE;QACrD,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC,IAAI,CAAA;QACvB,cAAc,CAAC,IAAI,CAAC,CAAA;QACpB,UAAU,CAAC,GAAG,EAAE,CAAC,qBAAqB,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,uBAAuB,CAAC,CAAA;IAC3E,CAAC,CAAA;IAED,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,2BAA2B,CAAC,CAAA;IACzE,YAAY,CAAC,WAAW,EAAE,iBAAiB,EAAE,2BAA2B,CAAC,CAAA;IACzE,YAAY,CAAC,WAAW,EAAE,mBAAmB,EAAE,oBAAoB,CAAC,CAAA;IACpE,YAAY,CAAC,WAAW,EAAE,YAAY,EAAE,uBAAuB,CAAC,CAAA;IAChE,YAAY,CAAC,WAAW,EAAE,kBAAkB,EAAE,iBAAiB,CAAC,CAAA;AAClE,CAAC","sourcesContent":["import { ApiCollection, MessageResource } from '../types'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport {\n deleteRecordInPagesData,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { MessageCreatedEvent, MessageDeletedEvent } from '../types/jolt_events/message_events'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { useCurrentPerson } from './use_current_person'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { getRequestQueryKey } from './use_suspense_api'\nimport { JoltReactionEvent, JoltTypingEvent } from '../types/jolt_events'\nimport { transformReactionEventDataToReactionCountResource } from '../utils/jolt/transform_reaction_event_data_to_reaction_count_resource'\nimport { getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache'\nimport { isTemporaryMessageId } from './use_message_create_or_update'\nimport { completeMessageCreationTracking } from '../utils/performance_tracking'\nimport { useApiClient } from './use_api_client'\n\ninterface Props {\n conversationId: number\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n const apiClient = useApiClient()\n\n const { addTypingEvent, removeTypingEventById, removeAllTypingEventsByAuthorId } =\n useTypingStatusCache(conversationId)\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n if (e.event === 'message.created' && data.author_id) {\n removeAllTypingEventsByAuthorId(data.author_id)\n if (data.idempotent_key && data.author_id === currentPerson.id) {\n completeMessageCreationTracking({ apiClient, idempotentKey: data.idempotent_key })\n }\n }\n\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev => {\n if (e.event === 'message.created') {\n // Before adding the new message, remove any pending temporary messages\n // with matching text to prevent duplicates from race conditions\n let dataAfterTempRemoval = prev\n if (prev && message.text && message.mine) {\n dataAfterTempRemoval = deleteRecordInPagesData({\n data: prev,\n record: message,\n matchFn: (existingMessage, _record) => {\n return (\n isTemporaryMessageId(existingMessage.id) &&\n existingMessage.text === message.text &&\n existingMessage.mine\n )\n },\n })\n }\n\n return updateOrCreateRecordInPagesData({\n data: dataAfterTempRemoval,\n record: message,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n } else {\n return updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, current) => {\n return { ...current, ...record }\n },\n })\n }\n })\n }\n\n const handleMessageDeleted = async (e: MessageDeletedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n }\n\n const handleReactionJoltEvent = async (e: JoltReactionEvent) => {\n const { data } = e.data\n const message = { id: data.message_sort_key } as MessageResource\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n updateRecordInPagesData({\n data: prev,\n record: message,\n processRecord: (record, oldMessage) => {\n const reactionCounts = oldMessage.reactionCounts || []\n let foundMatch = false\n let newReactionCounts = reactionCounts.map(reactionCount => {\n if (reactionCount.value === data.value) {\n foundMatch = true\n return transformReactionEventDataToReactionCountResource({\n data,\n oldData: reactionCount,\n event: e.event,\n currentPersonId: currentPerson.id,\n })\n }\n return reactionCount\n })\n\n if (!foundMatch) {\n const newReactionCount = transformReactionEventDataToReactionCountResource({\n data,\n event: e.event,\n currentPersonId: currentPerson.id,\n })\n\n if (newReactionCount?.count) {\n newReactionCounts = [...newReactionCounts, newReactionCount]\n }\n }\n\n return { ...oldMessage, reactionCounts: newReactionCounts }\n },\n })\n )\n }\n\n const handleTypingEvent = async (e: JoltTypingEvent) => {\n const { data } = e.data\n addTypingEvent(data)\n setTimeout(() => removeTypingEventById(data.id), TYPING_TIMEOUT_INTERVAL)\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n useJoltEvent(joltChannel, 'typing.broadcast', handleTypingEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"]}
1
+ {"version":3,"file":"use_conversation_messages_jolt_events.js","sourceRoot":"","sources":["../../src/hooks/use_conversation_messages_jolt_events.ts"],"names":[],"mappings":"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","sourcesContent":["import { ApiCollection, MessageResource } from '../types'\nimport { useJoltChannel, useJoltEvent } from './use_jolt'\nimport { deleteRecordInPagesData } from '../utils'\nimport { MessageCreatedEvent, MessageDeletedEvent } from '../types/jolt_events/message_events'\nimport { InfiniteData, useQueryClient } from '@tanstack/react-query'\nimport { useCurrentPerson } from './use_current_person'\nimport { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'\nimport { getRequestQueryKey } from './use_suspense_api'\nimport { JoltReactionEvent, JoltTypingEvent } from '../types/jolt_events'\nimport { getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache'\nimport { completeMessageCreationTracking } from '../utils/performance_tracking'\nimport { useApiClient } from './use_api_client'\nimport {\n updateCacheWithMessage,\n updateCacheWithReaction,\n getThreadedMessagesQueryKey,\n} from '../utils/cache/messages_cache'\n\ninterface Props {\n conversationId: number\n}\n\nexport function useConversationMessagesJoltEvents({ conversationId }: Props) {\n const queryClient = useQueryClient()\n const currentPerson = useCurrentPerson()\n const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)\n const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })\n const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)\n const apiClient = useApiClient()\n\n const { addTypingEvent, removeTypingEventById, removeAllTypingEventsByAuthorId } =\n useTypingStatusCache(conversationId)\n\n const handleMessageUpdateOrCreate = async (e: MessageCreatedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n if (e.event === 'message.created' && data.author_id) {\n removeAllTypingEventsByAuthorId(data.author_id)\n if (data.idempotent_key && data.author_id === currentPerson.id) {\n completeMessageCreationTracking({ apiClient, idempotentKey: data.idempotent_key })\n }\n }\n\n // Update the main conversation cache\n updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event)\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event)\n }\n }\n\n const handleMessageDeleted = async (e: MessageDeletedEvent) => {\n const { data } = e.data\n const message = transformMessageEventDataToMessageResource({\n data,\n currentPersonId: currentPerson.id,\n })\n\n // Update the main conversation cache\n queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n\n // If message has a reply_root_id, also update the threaded cache\n if (data.reply_root_id) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(\n conversationId,\n data.reply_root_id\n )\n queryClient.setQueryData<QueryData>(threadedMessagesQueryKey, prev =>\n deleteRecordInPagesData({ data: prev, record: message })\n )\n }\n }\n\n const handleReactionJoltEvent = async (e: JoltReactionEvent) => {\n // Update the main conversation cache and capture the reply_root_id if present\n updateCacheWithReaction(queryClient, messagesQueryKey, e, currentPerson.id)\n\n const replyRootId = e.data.data.reply_root_id\n\n // If the message has a reply_root_id, also update the threaded cache\n if (replyRootId) {\n const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, replyRootId)\n updateCacheWithReaction(queryClient, threadedMessagesQueryKey, e, currentPerson.id)\n }\n }\n\n const handleTypingEvent = async (e: JoltTypingEvent) => {\n const { data } = e.data\n addTypingEvent(data)\n setTimeout(() => removeTypingEventById(data.id), TYPING_TIMEOUT_INTERVAL)\n }\n\n useJoltEvent(joltChannel, 'message.created', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.updated', handleMessageUpdateOrCreate)\n useJoltEvent(joltChannel, 'message.destroyed', handleMessageDeleted)\n useJoltEvent(joltChannel, 'reaction.*', handleReactionJoltEvent)\n useJoltEvent(joltChannel, 'typing.broadcast', handleTypingEvent)\n}\n\ntype QueryData = InfiniteData<ApiCollection<MessageResource>>\n"]}
@@ -11,7 +11,5 @@ export declare function useMessageCreateOrUpdate({ conversationId, message, repl
11
11
  }, {
12
12
  message: MessageResource;
13
13
  }>;
14
- export declare function isTemporaryMessageId(messageId?: string | null): boolean;
15
- export declare function isNewMessage(message?: MessageResource): boolean;
16
14
  export {};
17
15
  //# sourceMappingURL=use_message_create_or_update.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_message_create_or_update.d.ts","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAQtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,gEAAgE,CAAA;AAMxH,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK;UAqD5E,MAAM;kBACE,uCAAuC,EAAE;;;GAuE5D;AAED,wBAAgB,oBAAoB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAEvE;AACD,wBAAgB,YAAY,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAE/D"}
1
+ {"version":3,"file":"use_message_create_or_update.d.ts","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"AAGA,OAAO,EAAiB,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAQtE,OAAO,EAAE,uCAAuC,EAAE,MAAM,gEAAgE,CAAA;AAOxH,UAAU,KAAK;IACb,cAAc,EAAE,MAAM,CAAA;IACtB,OAAO,CAAC,EAAE,eAAe,CAAA;IACzB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,cAAc,EAAE,OAAO,EAAE,WAAW,EAAE,EAAE,KAAK;UAqD5E,MAAM;kBACE,uCAAuC,EAAE;;;GA8E5D"}
@@ -7,6 +7,7 @@ import { useCurrentPerson } from './use_current_person';
7
7
  import { optimisticallyUpdateMessage } from '../utils/cache/optimistically_update_message';
8
8
  import { optimisticallyCreateMessage } from '../utils/cache/optimistically_create_message';
9
9
  import { startMessageCreationTracking } from '../utils/performance_tracking';
10
+ import { isNewMessage } from '../utils/cache/messages_cache';
10
11
  export function useMessageCreateOrUpdate({ conversationId, message, replyRootId }) {
11
12
  const messageId = message?.id || null;
12
13
  const isEditing = !isNewMessage(message);
@@ -62,6 +63,7 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
62
63
  text,
63
64
  attachments,
64
65
  currentPerson,
66
+ replyRootId,
65
67
  });
66
68
  return { message: optimisticMessage };
67
69
  },
@@ -70,7 +72,10 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
70
72
  Haptic.notificationError();
71
73
  // Add error to the optimistic message from the cache on error
72
74
  if (optimisticMessage) {
73
- const queryKey = getMessagesQueryKey({ conversation_id: conversationId });
75
+ const queryKey = getMessagesQueryKey({
76
+ conversation_id: conversationId,
77
+ reply_root_id: replyRootId,
78
+ });
74
79
  chatQueryClient.setQueryData(queryKey, (data) => updateRecordInPagesData({
75
80
  data,
76
81
  record: optimisticMessage,
@@ -85,7 +90,10 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
85
90
  onSuccess: (result, variables, context) => {
86
91
  const { message: optimisticMessage } = context || {};
87
92
  const updatedMessage = result.data;
88
- const queryKey = getMessagesQueryKey({ conversation_id: conversationId });
93
+ const queryKey = getMessagesQueryKey({
94
+ conversation_id: conversationId,
95
+ reply_root_id: replyRootId,
96
+ });
89
97
  // First remove the optimistic message if it exists
90
98
  if (optimisticMessage) {
91
99
  chatQueryClient.setQueryData(queryKey, data => deleteRecordInPagesData({
@@ -102,12 +110,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
102
110
  });
103
111
  return mutation;
104
112
  }
105
- export function isTemporaryMessageId(messageId) {
106
- return !!messageId && messageId.endsWith('-temp');
107
- }
108
- export function isNewMessage(message) {
109
- return !message?.id || isTemporaryMessageId(message.id);
110
- }
111
113
  /**
112
114
  * Generate a random UUID (v4) for idempotent keys.
113
115
  * Uses Math.random, which is not cryptographically secure.
@@ -1 +1 @@
1
- {"version":3,"file":"use_message_create_or_update.js","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"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","sourcesContent":["import { InfiniteData, useMutation } from '@tanstack/react-query'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { ApiCollection, ApiResource, MessageResource } from '../types'\nimport { chatQueryClient } from '../contexts/api_provider'\nimport {\n deleteRecordInPagesData,\n Haptic,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'\nimport { useCurrentPerson } from './use_current_person'\nimport { optimisticallyUpdateMessage } from '../utils/cache/optimistically_update_message'\nimport { optimisticallyCreateMessage } from '../utils/cache/optimistically_create_message'\nimport { startMessageCreationTracking } from '../utils/performance_tracking'\n\ninterface Props {\n conversationId: number\n message?: MessageResource\n replyRootId?: string | null\n}\n\nexport function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props) {\n const messageId = message?.id || null\n const isEditing = !isNewMessage(message)\n const apiClient = useApiClient()\n const currentPerson = useCurrentPerson()\n\n const mutation = useMutation({\n mutationFn: ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversationId })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n let attributes: any = {\n text,\n ...(attachments ? { attachments } : {}),\n ...(replyRootId ? { reply_root: { id: replyRootId } } : {}),\n }\n if (!isEditing) {\n const idempotentKey = insecureUUID()\n attributes.idempotent_key = idempotentKey\n startMessageCreationTracking(idempotentKey)\n }\n const data = {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes,\n },\n fields: fieldsWithValueJoined,\n }\n\n if (isEditing) {\n return apiClient.chat.patch<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages/${messageId}`,\n data,\n })\n } else {\n return apiClient.chat.post<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages`,\n data,\n })\n }\n },\n onMutate: async ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n if (message && isEditing) {\n const optimisticMessage = optimisticallyUpdateMessage({\n conversationId,\n message,\n text,\n })\n\n return { message: optimisticMessage }\n }\n\n const optimisticMessage = optimisticallyCreateMessage({\n conversationId,\n message,\n text,\n attachments,\n currentPerson,\n })\n\n return { message: optimisticMessage }\n },\n onError: (error, variables, context) => {\n const { message: optimisticMessage } = context || {}\n Haptic.notificationError()\n\n // Add error to the optimistic message from the cache on error\n if (optimisticMessage) {\n const queryKey = getMessagesQueryKey({ conversation_id: conversationId })\n chatQueryClient.setQueryData(\n queryKey,\n (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>\n updateRecordInPagesData({\n data,\n record: optimisticMessage,\n processRecord: (_next, prev) => ({\n ...prev,\n error: error.message || 'Failed to send message',\n pending: false, // Mark as no longer pending\n }),\n })\n )\n }\n },\n onSuccess: (result: ApiResource<MessageResource>, variables, context) => {\n const { message: optimisticMessage } = context || {}\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({ conversation_id: conversationId })\n\n // First remove the optimistic message if it exists\n if (optimisticMessage) {\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n deleteRecordInPagesData({\n data,\n record: optimisticMessage,\n })\n )\n }\n\n // Then add the real message\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: updatedMessage,\n })\n )\n },\n })\n\n return mutation\n}\n\nexport function isTemporaryMessageId(messageId?: string | null): boolean {\n return !!messageId && messageId.endsWith('-temp')\n}\nexport function isNewMessage(message?: MessageResource): boolean {\n return !message?.id || isTemporaryMessageId(message.id)\n}\n\n/**\n * Generate a random UUID (v4) for idempotent keys.\n * Uses Math.random, which is not cryptographically secure.\n * An actual crypto library requires native dependencies.\n * This is OK for now since idempotent keys are not security-sensitive\n * or need to be guaranteed unique.\n * They are short lived and we use it in combination with the message's creator_id so\n * their impact is scoped only the current user.\n */\nfunction insecureUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-Nxxx-xxxxxxxxxxxx'\n .replace(/x/g, () => Math.floor(Math.random() * 16).toString(16))\n .replace(/N/g, () => (Math.floor(Math.random() * 4) + 8).toString(16))\n}\n"]}
1
+ {"version":3,"file":"use_message_create_or_update.js","sourceRoot":"","sources":["../../src/hooks/use_message_create_or_update.ts"],"names":[],"mappings":"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","sourcesContent":["import { InfiniteData, useMutation } from '@tanstack/react-query'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { ApiCollection, ApiResource, MessageResource } from '../types'\nimport { chatQueryClient } from '../contexts/api_provider'\nimport {\n deleteRecordInPagesData,\n Haptic,\n updateOrCreateRecordInPagesData,\n updateRecordInPagesData,\n} from '../utils'\nimport { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'\nimport { useCurrentPerson } from './use_current_person'\nimport { optimisticallyUpdateMessage } from '../utils/cache/optimistically_update_message'\nimport { optimisticallyCreateMessage } from '../utils/cache/optimistically_create_message'\nimport { startMessageCreationTracking } from '../utils/performance_tracking'\nimport { isNewMessage } from '../utils/cache/messages_cache'\n\ninterface Props {\n conversationId: number\n message?: MessageResource\n replyRootId?: string | null\n}\n\nexport function useMessageCreateOrUpdate({ conversationId, message, replyRootId }: Props) {\n const messageId = message?.id || null\n const isEditing = !isNewMessage(message)\n const apiClient = useApiClient()\n const currentPerson = useCurrentPerson()\n\n const mutation = useMutation({\n mutationFn: ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n const requestParams = getMessagesRequestArgs({ conversation_id: conversationId })\n const fieldsWithValueJoined = Object.fromEntries(\n Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])\n )\n let attributes: any = {\n text,\n ...(attachments ? { attachments } : {}),\n ...(replyRootId ? { reply_root: { id: replyRootId } } : {}),\n }\n if (!isEditing) {\n const idempotentKey = insecureUUID()\n attributes.idempotent_key = idempotentKey\n startMessageCreationTracking(idempotentKey)\n }\n const data = {\n ...requestParams.data,\n data: {\n type: 'Message',\n attributes,\n },\n fields: fieldsWithValueJoined,\n }\n\n if (isEditing) {\n return apiClient.chat.patch<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages/${messageId}`,\n data,\n })\n } else {\n return apiClient.chat.post<ApiResource<MessageResource>>({\n url: `/me/conversations/${conversationId}/messages`,\n data,\n })\n }\n },\n onMutate: async ({\n text,\n attachments,\n }: {\n text: string\n attachments?: DenormalizedAttachmentResourceForCreate[]\n }) => {\n if (message && isEditing) {\n const optimisticMessage = optimisticallyUpdateMessage({\n conversationId,\n message,\n text,\n })\n\n return { message: optimisticMessage }\n }\n\n const optimisticMessage = optimisticallyCreateMessage({\n conversationId,\n message,\n text,\n attachments,\n currentPerson,\n replyRootId,\n })\n\n return { message: optimisticMessage }\n },\n onError: (error, variables, context) => {\n const { message: optimisticMessage } = context || {}\n Haptic.notificationError()\n\n // Add error to the optimistic message from the cache on error\n if (optimisticMessage) {\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n chatQueryClient.setQueryData(\n queryKey,\n (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>\n updateRecordInPagesData({\n data,\n record: optimisticMessage,\n processRecord: (_next, prev) => ({\n ...prev,\n error: error.message || 'Failed to send message',\n pending: false, // Mark as no longer pending\n }),\n })\n )\n }\n },\n onSuccess: (result: ApiResource<MessageResource>, variables, context) => {\n const { message: optimisticMessage } = context || {}\n const updatedMessage = result.data\n type QueryData = InfiniteData<ApiCollection<MessageResource>>\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: replyRootId,\n })\n\n // First remove the optimistic message if it exists\n if (optimisticMessage) {\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n deleteRecordInPagesData({\n data,\n record: optimisticMessage,\n })\n )\n }\n\n // Then add the real message\n chatQueryClient.setQueryData<QueryData>(queryKey, data =>\n updateOrCreateRecordInPagesData({\n data,\n record: updatedMessage,\n })\n )\n },\n })\n\n return mutation\n}\n\n/**\n * Generate a random UUID (v4) for idempotent keys.\n * Uses Math.random, which is not cryptographically secure.\n * An actual crypto library requires native dependencies.\n * This is OK for now since idempotent keys are not security-sensitive\n * or need to be guaranteed unique.\n * They are short lived and we use it in combination with the message's creator_id so\n * their impact is scoped only the current user.\n */\nfunction insecureUUID(): string {\n return 'xxxxxxxx-xxxx-4xxx-Nxxx-xxxxxxxxxxxx'\n .replace(/x/g, () => Math.floor(Math.random() * 16).toString(16))\n .replace(/N/g, () => (Math.floor(Math.random() * 4) + 8).toString(16))\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_details_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_details_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AACzF,OAAO,KAQN,MAAM,OAAO,CAAA;AAwEd,MAAM,MAAM,8BAA8B,GAAG,iBAAiB,CAAC;IAC7D,eAAe,EAAE,MAAM,CAAA;CACxB,CAAC,CAAA;AAEF,wBAAgB,yBAAyB,CAAC,EAAE,KAAK,EAAE,EAAE,8BAA8B,qBAwSlF"}
1
+ {"version":3,"file":"conversation_details_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_details_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAgB,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AACzF,OAAO,KAQN,MAAM,OAAO,CAAA;AAwEd,MAAM,MAAM,8BAA8B,GAAG,iBAAiB,CAAC;IAC7D,eAAe,EAAE,MAAM,CAAA;CACxB,CAAC,CAAA;AAEF,wBAAgB,yBAAyB,CAAC,EAAE,KAAK,EAAE,EAAE,8BAA8B,qBAuSlF"}
@@ -1,13 +1,12 @@
1
1
  import { StackActions, useNavigation } from '@react-navigation/native';
2
2
  import React, { useCallback, useEffect, useState, useRef, } from 'react';
3
- import { StyleSheet, TextInput, View, Pressable, Alert, Platform, } from 'react-native';
3
+ import { FlatList, StyleSheet, TextInput, View, Pressable, Alert, Platform, } from 'react-native';
4
4
  import { HeaderTitle as ElementsHeaderTitle } from '@react-navigation/elements';
5
5
  import { Badge, ChildNotice, Heading, Icon, Person, Switch, Text, TextButton, } from '../components';
6
6
  import { useSuspensePaginator, useTheme } from '../hooks';
7
7
  import { useConversation, useConversationDelete, useConversationDisableReplies, useConversationMute, useConversationUpdate, } from '../hooks/use_conversation';
8
8
  import { isDefined } from '../types';
9
9
  import { HeaderTextButton } from '../components/display/platform_modal_header_buttons';
10
- import { FlashList } from '@shopify/flash-list';
11
10
  import { tokens } from '../vendor/tapestry/tokens';
12
11
  // =========================================
13
12
  // ====== Factory Constants & Types ========
@@ -184,7 +183,7 @@ export function ConversationDetailsScreen({ route }) {
184
183
  .map(({ type }, index) => (type === SectionTypes.header ? index : undefined))
185
184
  .filter(isDefined);
186
185
  return (<View style={styles.listContainer}>
187
- <FlashList data={listData} estimatedItemSize={52} contentContainerStyle={styles.contentContainer} renderItem={({ item, index }) => {
186
+ <FlatList data={listData} contentContainerStyle={styles.contentContainer} renderItem={({ item, index }) => {
188
187
  const [isStart, isEnd] = [
189
188
  index === 0 || headerIndices.includes(index),
190
189
  index === listData.length - 1 || headerIndices.includes(index + 1),
@@ -213,7 +212,7 @@ export function ConversationDetailsScreen({ route }) {
213
212
  default:
214
213
  return null;
215
214
  }
216
- }} onEndReached={fetchNextPageOfMembers}/>
215
+ }} onEndReached={() => fetchNextPageOfMembers()}/>
217
216
  </View>);
218
217
  }
219
218
  function ListSection({ isStart, isEnd, showBottomBorder, outerStyle, innerStyle, children, }) {