@planningcenter/chat-react-native 4.2.1-qa-staging.0 → 4.2.1-qa-staging.2

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 (50) hide show
  1. package/build/components/conversation/anchor_not_found_boundary.d.ts +18 -0
  2. package/build/components/conversation/anchor_not_found_boundary.d.ts.map +1 -0
  3. package/build/components/conversation/anchor_not_found_boundary.js +20 -0
  4. package/build/components/conversation/anchor_not_found_boundary.js.map +1 -0
  5. package/build/components/conversation/message_list.d.ts +3 -2
  6. package/build/components/conversation/message_list.d.ts.map +1 -1
  7. package/build/components/conversation/message_list.js +149 -66
  8. package/build/components/conversation/message_list.js.map +1 -1
  9. package/build/hooks/use_conversation_messages.d.ts +8 -2
  10. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  11. package/build/hooks/use_conversation_messages.js +77 -45
  12. package/build/hooks/use_conversation_messages.js.map +1 -1
  13. package/build/hooks/use_fetch_newer_on_foreground.d.ts +8 -0
  14. package/build/hooks/use_fetch_newer_on_foreground.d.ts.map +1 -0
  15. package/build/hooks/use_fetch_newer_on_foreground.js +41 -0
  16. package/build/hooks/use_fetch_newer_on_foreground.js.map +1 -0
  17. package/build/hooks/use_mark_latest_message_read.d.ts +2 -1
  18. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  19. package/build/hooks/use_mark_latest_message_read.js +4 -3
  20. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  21. package/build/screens/conversation_screen.d.ts +1 -0
  22. package/build/screens/conversation_screen.d.ts.map +1 -1
  23. package/build/screens/conversation_screen.js +119 -48
  24. package/build/screens/conversation_screen.js.map +1 -1
  25. package/build/utils/generate_placeholder_ulid.d.ts +0 -6
  26. package/build/utils/generate_placeholder_ulid.d.ts.map +1 -1
  27. package/build/utils/generate_placeholder_ulid.js +2 -2
  28. package/build/utils/generate_placeholder_ulid.js.map +1 -1
  29. package/build/utils/request/get_messages.d.ts +18 -6
  30. package/build/utils/request/get_messages.d.ts.map +1 -1
  31. package/build/utils/request/get_messages.js +10 -12
  32. package/build/utils/request/get_messages.js.map +1 -1
  33. package/build/utils/ulid.d.ts +3 -0
  34. package/build/utils/ulid.d.ts.map +1 -0
  35. package/build/utils/ulid.js +7 -0
  36. package/build/utils/ulid.js.map +1 -0
  37. package/package.json +3 -3
  38. package/src/__tests__/utils/request/get_messages.test.ts +24 -0
  39. package/src/__tests__/utils/ulid.test.ts +15 -0
  40. package/src/components/conversation/__tests__/anchor_not_found_boundary.test.tsx +51 -0
  41. package/src/components/conversation/__tests__/message_list.test.tsx +42 -0
  42. package/src/components/conversation/anchor_not_found_boundary.tsx +21 -0
  43. package/src/components/conversation/message_list.tsx +50 -3
  44. package/src/hooks/use_conversation_messages.ts +43 -11
  45. package/src/hooks/use_fetch_newer_on_foreground.ts +25 -0
  46. package/src/hooks/use_mark_latest_message_read.ts +4 -3
  47. package/src/screens/conversation_screen.tsx +92 -21
  48. package/src/utils/generate_placeholder_ulid.ts +2 -2
  49. package/src/utils/request/get_messages.ts +12 -14
  50. package/src/utils/ulid.ts +11 -0
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_screen.js","names":["HeaderTitle","PlatformPressable","CommonActions","useNavigation","useTheme","useNavigationTheme","useRoute","React","useCallback","useEffect","useRef","useState","Platform","StyleSheet","useWindowDimensions","View","useSafeAreaInsets","Badge","Icon","ConversationStartBanner","JumpToBottomButton","MessageForm","MessageList","ConversationDisabledBanner","LeaderMessagesDisabledBanner","MemberMessagesDisabledBanner","TypingIndicator","KeyboardView","useHeaderSlotReserve","BlankState","ConversationContextProvider","useMessageAvailableMembersAction","useConversation","useConversationJoltEvents","useConversationMessages","useConversationMessagesJoltEvents","useFetchNewerMessages","useMarkLatestMessageRead","analyticsEvents","normalizeAnalyticsMetadata","usePublishProductAnalyticsEvent","useRestAwayFromDismissEdge","useVideoModerationJoltEvents","gatedMessageCache","jsx","_jsx","jsxs","_jsxs","ConversationScreen","t0","$","_c","route","conversation_id","reply_root_id","params","t1","data","conversation","t2","t3","conversation_show_opened","t4","t5","ConversationScreenContent","t6","currentPageReplyRootId","children","styles","useStyles","navigation","editing_message_id","reply_root_author_name","messages","fetchNextPage","hasNextPage","queryKey","showJumpToBottomButton","setShowJumpToBottomButton","readingHistory","skippedNewMessages","messageCaches","acceptNewMessages","onSkippedNewMessage","current","newestMessageId","id","conversationId","markHandledByMessageForm","useEnsureConversationsRouteExists","fetchNewer","noMessages","length","repliesDisabled","memberAbility","badges","title","canReply","showLeaderDisabledReplyBanner","currentlyEditingMessage","find","m","String","replyRootAuthorFirstName","split","replyHeaderTitle","muted","conversationMembership","listRef","trackScroll","event","offsetY","nativeEvent","contentOffset","y","restOffset","onLayout","onContentSizeChange","onMomentumScrollEnd","onScrollEndDrag","enabled","OS","handleReturnToBottom","scrollToOffset","offset","jumpToLatest","setParams","badge","deleted","style","container","Root","Imagery","name","Content","Heading","Button","onPress","goBack","accessibilityHint","accessibilityRole","emptyState","hasMessages","replyRootId","onEndReached","onScroll","maintainVisibleContentPosition","minIndexForVisible","undefined","visible","ConversationBottomBar","onFlaggedInMessageForm","onBeforeSubmit","messageLink","disabled","disabledMessage","message","Symbol","for","AttachmentPicker","Commands","TextInput","SubmitButton","ConversationScreenTitle","usePressableHeaderStyle","resourceType","pcoResourceType","productName","appName","text","navigate","maxFontSizeMultiplier","titleTextContainer","size","titleWrapper","t7","variant","t8","testID","width","slotReserve","headerContainerStyle","maxWidth","create","alignItems","select","android","default","flex","columnGap","flexDirection","flexShrink","minWidth","alignSelf","marginTop","navigationTheme","bottom","colors","card","justifyContent","backgroundColor","paddingBottom","chat_group_graph_id","navigationState","getState","routes","conversationsRoute","_temp","dispatch","state","reset","index","r"],"sources":["../../src/screens/conversation_screen.tsx"],"sourcesContent":["import { HeaderTitle, HeaderTitleProps, PlatformPressable } from '@react-navigation/elements'\nimport {\n CommonActions,\n RouteProp,\n StaticScreenProps,\n useNavigation,\n useTheme as useNavigationTheme,\n useRoute,\n} from '@react-navigation/native'\nimport React, { useCallback, useEffect, useRef, useState } from 'react'\nimport { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Badge, Icon } from '../components'\nimport { ConversationStartBanner } from '../components/conversation/conversation_start_banner'\nimport { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'\nimport { MessageForm } from '../components/conversation/message_form'\nimport { MessageList } from '../components/conversation/message_list'\nimport {\n ConversationDisabledBanner,\n LeaderMessagesDisabledBanner,\n MemberMessagesDisabledBanner,\n} from '../components/conversation/messages_disabled_banners'\nimport { TypingIndicator } from '../components/conversation/typing_indicator'\nimport { KeyboardView } from '../components/display/keyboard_view'\nimport { useHeaderSlotReserve } from '../components/display/platform_modal_header_buttons'\nimport BlankState from '../components/primitive/blank_state_primitive'\nimport { ConversationContextProvider } from '../contexts/conversation_context'\nimport { useMessageAvailableMembersAction } from '../hooks/direct_messages/use_message_available_members_action'\nimport { useConversation } from '../hooks/use_conversation'\nimport { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'\nimport { useConversationMessages } from '../hooks/use_conversation_messages'\nimport { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'\nimport { useFetchNewerMessages } from '../hooks/use_fetch_newer_messages'\nimport { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'\nimport {\n analyticsEvents,\n normalizeAnalyticsMetadata,\n usePublishProductAnalyticsEvent,\n} from '../hooks/use_product_analytics'\nimport { useRestAwayFromDismissEdge } from '../hooks/use_rest_away_from_dismiss_edge'\nimport { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt_events'\nimport { ConversationResource } from '../types/resources/conversation'\nimport { ConversationBadgeResource } from '../types/resources/conversation_badge'\nimport { MessageResource } from '../types/resources/message'\nimport { gatedMessageCache } from '../utils/gated_message_cache'\n\nexport type ConversationRouteProps = {\n conversation_id: number\n reply_root_id?: string | null\n reply_root_author_name?: string\n chat_group_graph_id?: string\n clear_input?: boolean\n editing_message_id?: number | null\n title?: string\n subtitle?: string\n badge?: ConversationBadgeResource\n deleted?: boolean\n muted?: boolean\n}\n\nexport type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>\n\nexport function ConversationScreen({ route }: ConversationScreenProps) {\n const { conversation_id, reply_root_id } = route.params\n\n const { data: conversation } = useConversation({ conversation_id })\n\n usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, {\n reply_root_id,\n ...normalizeAnalyticsMetadata(conversation),\n })\n\n return (\n <ConversationContextProvider\n conversationId={conversation_id}\n currentPageReplyRootId={reply_root_id ?? null}\n >\n <ConversationScreenContent route={route} />\n </ConversationContextProvider>\n )\n}\n\nfunction ConversationScreenContent({ route }: ConversationScreenProps) {\n const styles = useStyles()\n const navigation = useNavigation()\n const { conversation_id, editing_message_id, reply_root_id, reply_root_author_name } =\n route.params\n const { data: conversation } = useConversation(route.params)\n const { messages, fetchNextPage, hasNextPage, queryKey } = useConversationMessages({\n conversation_id,\n reply_root_id,\n })\n const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)\n const readingHistory = showJumpToBottomButton\n const skippedNewMessages = useRef(false)\n const messageCaches = [\n gatedMessageCache({\n queryKey,\n acceptNewMessages: !readingHistory,\n onSkippedNewMessage: () => {\n skippedNewMessages.current = true\n },\n }),\n ]\n const newestMessageId = messages[0]?.id\n useConversationJoltEvents({ conversationId: conversation_id })\n useConversationMessagesJoltEvents({ conversationId: conversation_id, messageCaches })\n const { markHandledByMessageForm } = useVideoModerationJoltEvents()\n useEnsureConversationsRouteExists()\n useMarkLatestMessageRead({ conversation, messages })\n const fetchNewer = useFetchNewerMessages({ conversation_id, reply_root_id, queryKey })\n const noMessages = messages.length === 0\n\n const { repliesDisabled, memberAbility, badges, title } = conversation\n const canReply = memberAbility?.canReply\n const showLeaderDisabledReplyBanner = canReply && repliesDisabled\n const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id))\n const replyRootAuthorFirstName = reply_root_author_name?.split(' ')[0]\n const replyHeaderTitle = replyRootAuthorFirstName\n ? `Reply to ${replyRootAuthorFirstName}`\n : 'Reply'\n // Prefer the membership for optimistic updates.\n const muted = conversation.conversationMembership?.muted ?? conversation.muted\n\n const listRef = useRef<FlatList>(null)\n\n const trackScroll = (event: any) => {\n const offsetY = event.nativeEvent.contentOffset.y\n setShowJumpToBottomButton(offsetY > 200)\n }\n\n const { restOffset, onLayout, onContentSizeChange, onMomentumScrollEnd, onScrollEndDrag } =\n useRestAwayFromDismissEdge({\n listRef,\n enabled: Platform.OS === 'ios',\n })\n\n const handleReturnToBottom = useCallback(() => {\n listRef.current?.scrollToOffset({\n offset: restOffset,\n })\n }, [restOffset])\n\n const jumpToLatest = useCallback(() => {\n setShowJumpToBottomButton(false)\n handleReturnToBottom()\n }, [handleReturnToBottom])\n\n useEffect(() => {\n if (readingHistory || !newestMessageId || !skippedNewMessages.current) return\n\n skippedNewMessages.current = false\n fetchNewer(newestMessageId)\n }, [fetchNewer, newestMessageId, readingHistory])\n\n useEffect(() => {\n if (reply_root_id) {\n navigation.setParams({\n title: replyHeaderTitle,\n })\n } else {\n navigation.setParams({\n title: title,\n badge: badges?.[0],\n deleted: conversation?.deleted,\n muted,\n })\n }\n }, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle, muted])\n\n if (!conversation || conversation.deleted) {\n return (\n <View style={styles.container}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>This conversation has been deleted</BlankState.Heading>\n </BlankState.Content>\n <BlankState.Button\n onPress={navigation.goBack}\n title=\"Back to conversations\"\n accessibilityHint=\"Navigates back to the conversations list\"\n accessibilityRole=\"link\"\n />\n </BlankState.Root>\n </View>\n )\n }\n\n return (\n <View style={styles.container}>\n <KeyboardView>\n {noMessages ? (\n <View style={styles.emptyState}>\n <ConversationStartBanner conversation={conversation} hasMessages={false} />\n </View>\n ) : (\n <MessageList\n listRef={listRef}\n conversation={conversation}\n conversationId={conversation_id}\n messages={messages}\n replyRootId={reply_root_id}\n hasNextPage={hasNextPage}\n onEndReached={() => fetchNextPage()}\n onScroll={trackScroll}\n onLayout={onLayout}\n onContentSizeChange={onContentSizeChange}\n onScrollEndDrag={onScrollEndDrag}\n onMomentumScrollEnd={onMomentumScrollEnd}\n maintainVisibleContentPosition={readingHistory ? { minIndexForVisible: 0 } : undefined}\n />\n )}\n <JumpToBottomButton onPress={jumpToLatest} visible={showJumpToBottomButton} />\n {!noMessages && <TypingIndicator />}\n {showLeaderDisabledReplyBanner && <LeaderMessagesDisabledBanner />}\n <ConversationBottomBar\n conversation={conversation}\n canReply={canReply}\n replyRootAuthorFirstName={replyRootAuthorFirstName}\n replyRootId={reply_root_id}\n currentlyEditingMessage={currentlyEditingMessage}\n onFlaggedInMessageForm={markHandledByMessageForm}\n onBeforeSubmit={jumpToLatest}\n />\n </KeyboardView>\n </View>\n )\n}\n\ninterface ConversationBottomBarProps {\n conversation: ConversationResource\n canReply: boolean | undefined\n replyRootAuthorFirstName: string | undefined\n replyRootId: string | null | undefined\n currentlyEditingMessage: MessageResource | undefined\n onFlaggedInMessageForm?: (id: string) => void\n onBeforeSubmit?: () => void\n}\n\nfunction ConversationBottomBar({\n conversation,\n canReply,\n replyRootAuthorFirstName,\n replyRootId,\n currentlyEditingMessage,\n onFlaggedInMessageForm,\n onBeforeSubmit,\n}: ConversationBottomBarProps) {\n const messageLink = useMessageAvailableMembersAction(conversation)\n\n if (conversation.disabled)\n return (\n <ConversationDisabledBanner\n message={conversation.disabledMessage ?? null}\n messageLink={messageLink}\n />\n )\n if (!canReply) return <MemberMessagesDisabledBanner />\n return (\n <MessageForm.Root\n replyRootAuthorFirstName={replyRootAuthorFirstName}\n conversation={conversation}\n replyRootId={replyRootId}\n currentlyEditingMessage={currentlyEditingMessage}\n onFlaggedInMessageForm={onFlaggedInMessageForm}\n onBeforeSubmit={onBeforeSubmit}\n key={\n currentlyEditingMessage\n ? `edit-message-form-${currentlyEditingMessage.id}`\n : 'new-message-form'\n }\n >\n <MessageForm.AttachmentPicker />\n <MessageForm.Commands />\n <MessageForm.TextInput />\n <MessageForm.SubmitButton />\n </MessageForm.Root>\n )\n}\n\ninterface ConversationScreenTitleProps extends HeaderTitleProps {\n conversation_id: number\n badge?: ConversationBadgeResource\n deleted?: boolean\n muted?: boolean\n}\n\nexport const ConversationScreenTitle = ({\n conversation_id,\n badge,\n children,\n style,\n deleted,\n muted,\n}: ConversationScreenTitleProps) => {\n const styles = usePressableHeaderStyle()\n const navigation = useNavigation()\n const resourceType = badge?.pcoResourceType || ''\n const productName = badge?.appName\n const name = badge?.text || undefined\n\n return (\n <PlatformPressable\n testID=\"conversation-details-button\"\n accessibilityHint=\"Opens details about members and settings\"\n style={styles.container}\n onPress={() => {\n if (deleted) return\n\n navigation.navigate('ConversationDetails', { conversation_id })\n }}\n >\n <View style={styles.titleWrapper}>\n <View style={styles.titleTextContainer}>\n <HeaderTitle maxFontSizeMultiplier={1} style={style}>\n {children}\n </HeaderTitle>\n </View>\n {muted && <Icon name=\"general.bellMuted\" size={12} />}\n {!deleted && <Icon name=\"general.downChevron\" size={12} />}\n </View>\n <Badge\n variant=\"metaSubtle\"\n productLogoName={productName}\n label={resourceType}\n metaLabel={name}\n style={styles.badge}\n maxFontSizeMultiplier={1}\n />\n </PlatformPressable>\n )\n}\n\nconst usePressableHeaderStyle = () => {\n const { width } = useWindowDimensions()\n const slotReserve = useHeaderSlotReserve()\n const headerContainerStyle = { maxWidth: width - slotReserve * 2 }\n\n return StyleSheet.create({\n container: {\n alignItems: Platform.select({ android: 'flex-start', default: 'center' }),\n flex: 1,\n ...headerContainerStyle,\n },\n titleWrapper: {\n alignItems: 'center',\n columnGap: 4,\n flexDirection: 'row',\n flexShrink: 1,\n },\n titleTextContainer: {\n flexShrink: 1,\n minWidth: 0,\n },\n badge: {\n alignSelf: Platform.select({ android: 'flex-start', default: 'center' }),\n marginTop: 2,\n },\n })\n}\n\nconst useStyles = () => {\n const navigationTheme = useNavigationTheme()\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n backgroundColor: navigationTheme.colors.card,\n paddingBottom: bottom,\n },\n emptyState: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n\n/**\n * useEnsureConversationsRouteExists\n */\nconst useEnsureConversationsRouteExists = () => {\n const navigation = useNavigation()\n const { params } = useRoute<RouteProp<ConversationScreenProps['route']>>()\n\n useEffect(() => {\n const navigationState = navigation.getState()\n const routes = navigationState?.routes || []\n const conversationsRoute = routes.find(r => r.name === 'Conversations')\n\n if (conversationsRoute) return\n\n navigation.dispatch(state => {\n return CommonActions.reset({\n ...state,\n routes: [\n { name: 'Conversations', params: { chat_group_graph_id: params?.chat_group_graph_id } },\n ...routes,\n ],\n index: state.index + 1,\n })\n })\n }, [navigation, params?.chat_group_graph_id])\n}\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"conversation_screen.js","names":["HeaderTitle","PlatformPressable","CommonActions","useNavigation","useTheme","useNavigationTheme","useRoute","React","startTransition","useCallback","useEffect","useRef","useState","Platform","StyleSheet","useWindowDimensions","View","useSafeAreaInsets","Badge","Icon","AnchorNotFoundBoundary","ConversationStartBanner","JumpToBottomButton","MessageForm","MessageList","ConversationDisabledBanner","LeaderMessagesDisabledBanner","MemberMessagesDisabledBanner","TypingIndicator","KeyboardView","useHeaderSlotReserve","BlankState","ConversationContextProvider","useMessageAvailableMembersAction","useConversation","useConversationJoltEvents","useConversationMessages","useConversationMessagesJoltEvents","useFetchNewerMessages","useFetchNewerOnForeground","useMarkLatestMessageRead","analyticsEvents","normalizeAnalyticsMetadata","usePublishProductAnalyticsEvent","useRestAwayFromDismissEdge","useVideoModerationJoltEvents","gatedMessageCache","decodeUlidTime","jsx","_jsx","jsxs","_jsxs","ConversationScreen","t0","$","_c","route","conversation_id","reply_root_id","initial_message_id","params","t1","data","conversation","t2","lastMessageCreatedAt","isBeforeLatestMessage","anchor","setAnchor","t3","Symbol","for","exitAnchoredMode","t4","dropAnchor","t5","t6","conversation_show_opened","t7","t8","children","ConversationScreenContent","t9","currentPageReplyRootId","onExitAnchoredMode","styles","useStyles","navigation","editing_message_id","reply_root_author_name","anchored","messages","fetchNextPage","hasNextPage","fetchPreviousPage","hasPreviousPage","isFetchingPreviousPage","queryKey","behindLatest","caughtUp","showJumpToBottomButton","setShowJumpToBottomButton","readingHistory","skippedNewMessages","messageCaches","acceptNewMessages","onSkippedNewMessage","current","newestMessageId","id","conversationId","markHandledByMessageForm","useEnsureConversationsRouteExists","enabled","fetchNewer","noMessages","length","repliesDisabled","memberAbility","badges","title","canReply","showLeaderDisabledReplyBanner","currentlyEditingMessage","find","m","String","replyRootAuthorFirstName","split","replyHeaderTitle","muted","conversationMembership","listRef","hasDragged","setHasDragged","holdListPosition","restOffset","onLayout","onContentSizeChange","onMomentumScrollEnd","onScrollEndDrag","OS","handleReturnToBottom","scrollToOffset","offset","jumpToLatest","trackScroll","event","offsetY","nativeEvent","contentOffset","y","loadNewerMessages","setParams","badge","deleted","style","container","Root","Imagery","name","Content","Heading","Button","onPress","goBack","accessibilityHint","accessibilityRole","emptyState","hasMessages","replyRootId","anchorMessageId","onEndReached","onScroll","onScrollBeginDrag","undefined","onStartReached","onStartReachedThreshold","maintainVisibleContentPosition","minIndexForVisible","visible","ConversationBottomBar","onFlaggedInMessageForm","onBeforeSubmit","messageLink","disabled","disabledMessage","message","AttachmentPicker","Commands","TextInput","SubmitButton","latestMessageCreatedAt","Date","parse","ConversationScreenTitle","usePressableHeaderStyle","resourceType","pcoResourceType","productName","appName","text","navigate","maxFontSizeMultiplier","titleTextContainer","size","titleWrapper","variant","testID","width","slotReserve","headerContainerStyle","maxWidth","create","alignItems","select","android","default","flex","columnGap","flexDirection","flexShrink","minWidth","alignSelf","marginTop","navigationTheme","bottom","colors","card","justifyContent","backgroundColor","paddingBottom","chat_group_graph_id","navigationState","getState","routes","conversationsRoute","_temp","dispatch","state","reset","index","r"],"sources":["../../src/screens/conversation_screen.tsx"],"sourcesContent":["import { HeaderTitle, HeaderTitleProps, PlatformPressable } from '@react-navigation/elements'\nimport {\n CommonActions,\n RouteProp,\n StaticScreenProps,\n useNavigation,\n useTheme as useNavigationTheme,\n useRoute,\n} from '@react-navigation/native'\nimport React, { startTransition, useCallback, useEffect, useRef, useState } from 'react'\nimport { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { Badge, Icon } from '../components'\nimport { AnchorNotFoundBoundary } from '../components/conversation/anchor_not_found_boundary'\nimport { ConversationStartBanner } from '../components/conversation/conversation_start_banner'\nimport { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'\nimport { MessageForm } from '../components/conversation/message_form'\nimport { MessageList } from '../components/conversation/message_list'\nimport {\n ConversationDisabledBanner,\n LeaderMessagesDisabledBanner,\n MemberMessagesDisabledBanner,\n} from '../components/conversation/messages_disabled_banners'\nimport { TypingIndicator } from '../components/conversation/typing_indicator'\nimport { KeyboardView } from '../components/display/keyboard_view'\nimport { useHeaderSlotReserve } from '../components/display/platform_modal_header_buttons'\nimport BlankState from '../components/primitive/blank_state_primitive'\nimport { ConversationContextProvider } from '../contexts/conversation_context'\nimport { useMessageAvailableMembersAction } from '../hooks/direct_messages/use_message_available_members_action'\nimport { useConversation } from '../hooks/use_conversation'\nimport { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'\nimport { useConversationMessages } from '../hooks/use_conversation_messages'\nimport { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'\nimport { useFetchNewerMessages } from '../hooks/use_fetch_newer_messages'\nimport { useFetchNewerOnForeground } from '../hooks/use_fetch_newer_on_foreground'\nimport { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'\nimport {\n analyticsEvents,\n normalizeAnalyticsMetadata,\n usePublishProductAnalyticsEvent,\n} from '../hooks/use_product_analytics'\nimport { useRestAwayFromDismissEdge } from '../hooks/use_rest_away_from_dismiss_edge'\nimport { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt_events'\nimport { ConversationResource } from '../types/resources/conversation'\nimport { ConversationBadgeResource } from '../types/resources/conversation_badge'\nimport { MessageResource } from '../types/resources/message'\nimport { gatedMessageCache } from '../utils/gated_message_cache'\nimport { decodeUlidTime } from '../utils/ulid'\n\nexport type ConversationRouteProps = {\n conversation_id: number\n reply_root_id?: string | null\n reply_root_author_name?: string\n chat_group_graph_id?: string\n clear_input?: boolean\n editing_message_id?: number | null\n initial_message_id?: string | null\n title?: string\n subtitle?: string\n badge?: ConversationBadgeResource\n deleted?: boolean\n muted?: boolean\n}\n\nexport type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>\n\nexport function ConversationScreen({ route }: ConversationScreenProps) {\n const { conversation_id, reply_root_id, initial_message_id } = route.params\n\n const { data: conversation } = useConversation({ conversation_id })\n const [anchor, setAnchor] = useState(() =>\n isBeforeLatestMessage(initial_message_id, conversation?.lastMessageCreatedAt)\n ? initial_message_id\n : null\n )\n const exitAnchoredMode = useCallback(() => startTransition(() => setAnchor(null)), [])\n const dropAnchor = useCallback(() => setAnchor(null), [])\n\n usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, {\n reply_root_id,\n ...normalizeAnalyticsMetadata(conversation),\n })\n\n return (\n <ConversationContextProvider\n conversationId={conversation_id}\n currentPageReplyRootId={reply_root_id ?? null}\n >\n {anchor ? (\n <AnchorNotFoundBoundary onAnchorNotFound={dropAnchor}>\n <ConversationScreenContent\n route={route}\n anchor={anchor}\n onExitAnchoredMode={exitAnchoredMode}\n />\n </AnchorNotFoundBoundary>\n ) : (\n <ConversationScreenContent\n route={route}\n anchor={null}\n onExitAnchoredMode={exitAnchoredMode}\n />\n )}\n </ConversationContextProvider>\n )\n}\n\ninterface ConversationScreenContentProps extends ConversationScreenProps {\n anchor: string | null | undefined\n onExitAnchoredMode: () => void\n}\n\nfunction ConversationScreenContent({\n route,\n anchor,\n onExitAnchoredMode,\n}: ConversationScreenContentProps) {\n const styles = useStyles()\n const navigation = useNavigation()\n const { conversation_id, editing_message_id, reply_root_id, reply_root_author_name } =\n route.params\n const { data: conversation } = useConversation(route.params)\n const anchored = !!anchor\n const {\n messages,\n fetchNextPage,\n hasNextPage,\n fetchPreviousPage,\n hasPreviousPage,\n isFetchingPreviousPage,\n queryKey,\n } = useConversationMessages({ conversation_id, reply_root_id, anchor })\n const behindLatest = anchored && hasPreviousPage\n const caughtUp = !hasPreviousPage\n const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)\n const readingHistory = showJumpToBottomButton\n const skippedNewMessages = useRef(false)\n const messageCaches = [\n gatedMessageCache({\n queryKey,\n acceptNewMessages: caughtUp && !readingHistory,\n onSkippedNewMessage: () => {\n skippedNewMessages.current = true\n },\n }),\n ]\n const newestMessageId = messages[0]?.id\n useConversationJoltEvents({ conversationId: conversation_id })\n useConversationMessagesJoltEvents({ conversationId: conversation_id, messageCaches })\n const { markHandledByMessageForm } = useVideoModerationJoltEvents()\n useEnsureConversationsRouteExists()\n useMarkLatestMessageRead({ conversation, messages, enabled: !behindLatest })\n const fetchNewer = useFetchNewerMessages({ conversation_id, reply_root_id, queryKey })\n useFetchNewerOnForeground({ fetchNewer, newestMessageId, enabled: anchored && caughtUp })\n const noMessages = messages.length === 0\n\n const { repliesDisabled, memberAbility, badges, title } = conversation\n const canReply = memberAbility?.canReply\n const showLeaderDisabledReplyBanner = canReply && repliesDisabled\n const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id))\n const replyRootAuthorFirstName = reply_root_author_name?.split(' ')[0]\n const replyHeaderTitle = replyRootAuthorFirstName\n ? `Reply to ${replyRootAuthorFirstName}`\n : 'Reply'\n // Prefer the membership for optimistic updates.\n const muted = conversation.conversationMembership?.muted ?? conversation.muted\n\n const listRef = useRef<FlatList>(null)\n const [hasDragged, setHasDragged] = useState(false)\n const holdListPosition = behindLatest || readingHistory\n\n const { restOffset, onLayout, onContentSizeChange, onMomentumScrollEnd, onScrollEndDrag } =\n useRestAwayFromDismissEdge({\n listRef,\n enabled: Platform.OS === 'ios',\n })\n\n const handleReturnToBottom = useCallback(() => {\n listRef.current?.scrollToOffset({\n offset: restOffset,\n })\n }, [restOffset])\n\n const exitAnchoredMode = useCallback(() => {\n onExitAnchoredMode()\n handleReturnToBottom()\n }, [handleReturnToBottom, onExitAnchoredMode])\n const jumpToLatest = useCallback(() => {\n setShowJumpToBottomButton(false)\n if (behindLatest) exitAnchoredMode()\n else handleReturnToBottom()\n }, [behindLatest, exitAnchoredMode, handleReturnToBottom])\n\n const trackScroll = (event: any) => {\n const offsetY = event.nativeEvent.contentOffset.y\n setShowJumpToBottomButton(offsetY > 200)\n }\n\n const loadNewerMessages = () => {\n if (!hasPreviousPage || isFetchingPreviousPage) return\n\n setHasDragged(false)\n fetchPreviousPage()\n }\n\n useEffect(() => {\n if (readingHistory || !caughtUp || !newestMessageId || !skippedNewMessages.current) return\n\n skippedNewMessages.current = false\n fetchNewer(newestMessageId)\n }, [caughtUp, fetchNewer, newestMessageId, readingHistory])\n\n useEffect(() => {\n if (reply_root_id) {\n navigation.setParams({\n title: replyHeaderTitle,\n })\n } else {\n navigation.setParams({\n title: title,\n badge: badges?.[0],\n deleted: conversation?.deleted,\n muted,\n })\n }\n }, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle, muted])\n\n if (!conversation || conversation.deleted) {\n return (\n <View style={styles.container}>\n <BlankState.Root>\n <BlankState.Imagery name=\"general.outlinedTextMessage\" />\n <BlankState.Content>\n <BlankState.Heading>This conversation has been deleted</BlankState.Heading>\n </BlankState.Content>\n <BlankState.Button\n onPress={navigation.goBack}\n title=\"Back to conversations\"\n accessibilityHint=\"Navigates back to the conversations list\"\n accessibilityRole=\"link\"\n />\n </BlankState.Root>\n </View>\n )\n }\n\n return (\n <View style={styles.container}>\n <KeyboardView>\n {noMessages ? (\n <View style={styles.emptyState}>\n <ConversationStartBanner conversation={conversation} hasMessages={false} />\n </View>\n ) : (\n <MessageList\n listRef={listRef}\n conversation={conversation}\n conversationId={conversation_id}\n messages={messages}\n replyRootId={reply_root_id}\n anchorMessageId={anchor}\n hasNextPage={hasNextPage}\n onEndReached={() => fetchNextPage()}\n onScroll={trackScroll}\n onLayout={onLayout}\n onContentSizeChange={onContentSizeChange}\n onScrollEndDrag={onScrollEndDrag}\n onMomentumScrollEnd={onMomentumScrollEnd}\n onScrollBeginDrag={anchored ? () => setHasDragged(true) : undefined}\n onStartReached={anchored && hasDragged ? loadNewerMessages : undefined}\n onStartReachedThreshold={anchored ? 0.5 : undefined}\n maintainVisibleContentPosition={\n holdListPosition ? { minIndexForVisible: 0 } : undefined\n }\n />\n )}\n <JumpToBottomButton\n onPress={jumpToLatest}\n visible={behindLatest || showJumpToBottomButton}\n />\n {!noMessages && <TypingIndicator />}\n {showLeaderDisabledReplyBanner && <LeaderMessagesDisabledBanner />}\n <ConversationBottomBar\n conversation={conversation}\n canReply={canReply}\n replyRootAuthorFirstName={replyRootAuthorFirstName}\n replyRootId={reply_root_id}\n currentlyEditingMessage={currentlyEditingMessage}\n onFlaggedInMessageForm={markHandledByMessageForm}\n onBeforeSubmit={jumpToLatest}\n />\n </KeyboardView>\n </View>\n )\n}\n\ninterface ConversationBottomBarProps {\n conversation: ConversationResource\n canReply: boolean | undefined\n replyRootAuthorFirstName: string | undefined\n replyRootId: string | null | undefined\n currentlyEditingMessage: MessageResource | undefined\n onFlaggedInMessageForm?: (id: string) => void\n onBeforeSubmit?: () => void\n}\n\nfunction ConversationBottomBar({\n conversation,\n canReply,\n replyRootAuthorFirstName,\n replyRootId,\n currentlyEditingMessage,\n onFlaggedInMessageForm,\n onBeforeSubmit,\n}: ConversationBottomBarProps) {\n const messageLink = useMessageAvailableMembersAction(conversation)\n\n if (conversation.disabled)\n return (\n <ConversationDisabledBanner\n message={conversation.disabledMessage ?? null}\n messageLink={messageLink}\n />\n )\n if (!canReply) return <MemberMessagesDisabledBanner />\n return (\n <MessageForm.Root\n replyRootAuthorFirstName={replyRootAuthorFirstName}\n conversation={conversation}\n replyRootId={replyRootId}\n currentlyEditingMessage={currentlyEditingMessage}\n onFlaggedInMessageForm={onFlaggedInMessageForm}\n onBeforeSubmit={onBeforeSubmit}\n key={\n currentlyEditingMessage\n ? `edit-message-form-${currentlyEditingMessage.id}`\n : 'new-message-form'\n }\n >\n <MessageForm.AttachmentPicker />\n <MessageForm.Commands />\n <MessageForm.TextInput />\n <MessageForm.SubmitButton />\n </MessageForm.Root>\n )\n}\n\nconst isBeforeLatestMessage = (anchor?: string | null, latestMessageCreatedAt?: string) =>\n !!anchor &&\n !!latestMessageCreatedAt &&\n decodeUlidTime(anchor) < Date.parse(latestMessageCreatedAt)\n\ninterface ConversationScreenTitleProps extends HeaderTitleProps {\n conversation_id: number\n badge?: ConversationBadgeResource\n deleted?: boolean\n muted?: boolean\n}\n\nexport const ConversationScreenTitle = ({\n conversation_id,\n badge,\n children,\n style,\n deleted,\n muted,\n}: ConversationScreenTitleProps) => {\n const styles = usePressableHeaderStyle()\n const navigation = useNavigation()\n const resourceType = badge?.pcoResourceType || ''\n const productName = badge?.appName\n const name = badge?.text || undefined\n\n return (\n <PlatformPressable\n testID=\"conversation-details-button\"\n accessibilityHint=\"Opens details about members and settings\"\n style={styles.container}\n onPress={() => {\n if (deleted) return\n\n navigation.navigate('ConversationDetails', { conversation_id })\n }}\n >\n <View style={styles.titleWrapper}>\n <View style={styles.titleTextContainer}>\n <HeaderTitle maxFontSizeMultiplier={1} style={style}>\n {children}\n </HeaderTitle>\n </View>\n {muted && <Icon name=\"general.bellMuted\" size={12} />}\n {!deleted && <Icon name=\"general.downChevron\" size={12} />}\n </View>\n <Badge\n variant=\"metaSubtle\"\n productLogoName={productName}\n label={resourceType}\n metaLabel={name}\n style={styles.badge}\n maxFontSizeMultiplier={1}\n />\n </PlatformPressable>\n )\n}\n\nconst usePressableHeaderStyle = () => {\n const { width } = useWindowDimensions()\n const slotReserve = useHeaderSlotReserve()\n const headerContainerStyle = { maxWidth: width - slotReserve * 2 }\n\n return StyleSheet.create({\n container: {\n alignItems: Platform.select({ android: 'flex-start', default: 'center' }),\n flex: 1,\n ...headerContainerStyle,\n },\n titleWrapper: {\n alignItems: 'center',\n columnGap: 4,\n flexDirection: 'row',\n flexShrink: 1,\n },\n titleTextContainer: {\n flexShrink: 1,\n minWidth: 0,\n },\n badge: {\n alignSelf: Platform.select({ android: 'flex-start', default: 'center' }),\n marginTop: 2,\n },\n })\n}\n\nconst useStyles = () => {\n const navigationTheme = useNavigationTheme()\n const { bottom } = useSafeAreaInsets()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n justifyContent: 'center',\n backgroundColor: navigationTheme.colors.card,\n paddingBottom: bottom,\n },\n emptyState: {\n flex: 1,\n justifyContent: 'center',\n },\n })\n}\n\n/**\n * useEnsureConversationsRouteExists\n */\nconst useEnsureConversationsRouteExists = () => {\n const navigation = useNavigation()\n const { params } = useRoute<RouteProp<ConversationScreenProps['route']>>()\n\n useEffect(() => {\n const navigationState = navigation.getState()\n const routes = navigationState?.routes || []\n const conversationsRoute = routes.find(r => r.name === 'Conversations')\n\n if (conversationsRoute) return\n\n navigation.dispatch(state => {\n return CommonActions.reset({\n ...state,\n routes: [\n { name: 'Conversations', params: { chat_group_graph_id: params?.chat_group_graph_id } },\n ...routes,\n ],\n index: state.index + 1,\n })\n })\n }, [navigation, params?.chat_group_graph_id])\n}\n"],"mappings":"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","ignoreList":[]}
@@ -1,9 +1,3 @@
1
- /**
2
- * The actual `ulid` library depends on a secure random number generator, which looks like it
3
- * may require a native dependency to polyfill in React Native.
4
- * Since this is only used as a local temporary ID, I think we can get away with a simpler
5
- * implementation that doesn't require any native dependencies.
6
- */
7
1
  export declare function generatePlaceholderUlid({ offsetMs }?: {
8
2
  offsetMs?: number;
9
3
  }): string;
@@ -1 +1 @@
1
- {"version":3,"file":"generate_placeholder_ulid.d.ts","sourceRoot":"","sources":["../../src/utils/generate_placeholder_ulid.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAaH,wBAAgB,uBAAuB,CAAC,EAAE,QAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAa5F"}
1
+ {"version":3,"file":"generate_placeholder_ulid.d.ts","sourceRoot":"","sources":["../../src/utils/generate_placeholder_ulid.ts"],"names":[],"mappings":"AAkBA,wBAAgB,uBAAuB,CAAC,EAAE,QAAY,EAAE,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAO,GAAG,MAAM,CAa5F"}
@@ -1,3 +1,5 @@
1
+ import { ULID_CHARS } from './ulid';
2
+
1
3
  /**
2
4
  * The actual `ulid` library depends on a secure random number generator, which looks like it
3
5
  * may require a native dependency to polyfill in React Native.
@@ -5,8 +7,6 @@
5
7
  * implementation that doesn't require any native dependencies.
6
8
  */
7
9
 
8
- const ULID_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
9
-
10
10
  function encodeBase32(value, length) {
11
11
  let result = '';
12
12
  for (let i = 0; i < length; i++) {
@@ -1 +1 @@
1
- {"version":3,"file":"generate_placeholder_ulid.js","names":["ULID_CHARS","encodeBase32","value","length","result","i","Math","floor","generatePlaceholderUlid","offsetMs","timestamp","Date","now","timeComponent","randomComponent","random"],"sources":["../../src/utils/generate_placeholder_ulid.ts"],"sourcesContent":["/**\n * The actual `ulid` library depends on a secure random number generator, which looks like it\n * may require a native dependency to polyfill in React Native.\n * Since this is only used as a local temporary ID, I think we can get away with a simpler\n * implementation that doesn't require any native dependencies.\n */\n\nconst ULID_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' // Crockford's Base32\n\nfunction encodeBase32(value: number, length: number) {\n let result = ''\n for (let i = 0; i < length; i++) {\n result = ULID_CHARS[value % 32] + result\n value = Math.floor(value / 32)\n }\n return result\n}\n\nexport function generatePlaceholderUlid({ offsetMs = 0 }: { offsetMs?: number } = {}): string {\n const timestamp = Date.now() + offsetMs // Milliseconds since epoch\n // 48 bits for timestamp (6 Base32 characters)\n const timeComponent = encodeBase32(timestamp, 10) // 48 bits = 6 bytes = 10 Base32 characters (approx, needs more precise bit shifting)\n\n // 80 bits for randomness (16 Base32 characters)\n let randomComponent = ''\n for (let i = 0; i < 16; i++) {\n // Generate 16 random Base32 chars\n randomComponent += ULID_CHARS[Math.floor(Math.random() * 32)]\n }\n\n return timeComponent + randomComponent\n}\n"],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAMA,UAAU,GAAG,kCAAkC,EAAC;;AAEtD,SAASC,YAAYA,CAACC,KAAa,EAAEC,MAAc,EAAE;EACnD,IAAIC,MAAM,GAAG,EAAE;EACf,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,MAAM,EAAEE,CAAC,EAAE,EAAE;IAC/BD,MAAM,GAAGJ,UAAU,CAACE,KAAK,GAAG,EAAE,CAAC,GAAGE,MAAM;IACxCF,KAAK,GAAGI,IAAI,CAACC,KAAK,CAACL,KAAK,GAAG,EAAE,CAAC;EAChC;EACA,OAAOE,MAAM;AACf;AAEA,OAAO,SAASI,uBAAuBA,CAAC;EAAEC,QAAQ,GAAG;AAAyB,CAAC,GAAG,CAAC,CAAC,EAAU;EAC5F,MAAMC,SAAS,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAGH,QAAQ,EAAC;EACxC;EACA,MAAMI,aAAa,GAAGZ,YAAY,CAACS,SAAS,EAAE,EAAE,CAAC,EAAC;;EAElD;EACA,IAAII,eAAe,GAAG,EAAE;EACxB,KAAK,IAAIT,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG,EAAE,EAAEA,CAAC,EAAE,EAAE;IAC3B;IACAS,eAAe,IAAId,UAAU,CAACM,IAAI,CAACC,KAAK,CAACD,IAAI,CAACS,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;EAC/D;EAEA,OAAOF,aAAa,GAAGC,eAAe;AACxC","ignoreList":[]}
1
+ {"version":3,"file":"generate_placeholder_ulid.js","names":["ULID_CHARS","encodeBase32","value","length","result","i","Math","floor","generatePlaceholderUlid","offsetMs","timestamp","Date","now","timeComponent","randomComponent","random"],"sources":["../../src/utils/generate_placeholder_ulid.ts"],"sourcesContent":["import { ULID_CHARS } from './ulid'\n\n/**\n * The actual `ulid` library depends on a secure random number generator, which looks like it\n * may require a native dependency to polyfill in React Native.\n * Since this is only used as a local temporary ID, I think we can get away with a simpler\n * implementation that doesn't require any native dependencies.\n */\n\nfunction encodeBase32(value: number, length: number) {\n let result = ''\n for (let i = 0; i < length; i++) {\n result = ULID_CHARS[value % 32] + result\n value = Math.floor(value / 32)\n }\n return result\n}\n\nexport function generatePlaceholderUlid({ offsetMs = 0 }: { offsetMs?: number } = {}): string {\n const timestamp = Date.now() + offsetMs // Milliseconds since epoch\n // 48 bits for timestamp (6 Base32 characters)\n const timeComponent = encodeBase32(timestamp, 10) // 48 bits = 6 bytes = 10 Base32 characters (approx, needs more precise bit shifting)\n\n // 80 bits for randomness (16 Base32 characters)\n let randomComponent = ''\n for (let i = 0; i < 16; i++) {\n // Generate 16 random Base32 chars\n randomComponent += ULID_CHARS[Math.floor(Math.random() * 32)]\n }\n\n return timeComponent + randomComponent\n}\n"],"mappings":"AAAA,SAASA,UAAU,QAAQ,QAAQ;;AAEnC;AACA;AACA;AACA;AACA;AACA;;AAEA,SAASC,YAAYA,CAACC,KAAa,EAAEC,MAAc,EAAE;EACnD,IAAIC,MAAM,GAAG,EAAE;EACf,KAAK,IAAIC,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGF,MAAM,EAAEE,CAAC,EAAE,EAAE;IAC/BD,MAAM,GAAGJ,UAAU,CAACE,KAAK,GAAG,EAAE,CAAC,GAAGE,MAAM;IACxCF,KAAK,GAAGI,IAAI,CAACC,KAAK,CAACL,KAAK,GAAG,EAAE,CAAC;EAChC;EACA,OAAOE,MAAM;AACf;AAEA,OAAO,SAASI,uBAAuBA,CAAC;EAAEC,QAAQ,GAAG;AAAyB,CAAC,GAAG,CAAC,CAAC,EAAU;EAC5F,MAAMC,SAAS,GAAGC,IAAI,CAACC,GAAG,CAAC,CAAC,GAAGH,QAAQ,EAAC;EACxC;EACA,MAAMI,aAAa,GAAGZ,YAAY,CAACS,SAAS,EAAE,EAAE,CAAC,EAAC;;EAElD;EACA,IAAII,eAAe,GAAG,EAAE;EACxB,KAAK,IAAIT,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG,EAAE,EAAEA,CAAC,EAAE,EAAE;IAC3B;IACAS,eAAe,IAAId,UAAU,CAACM,IAAI,CAACC,KAAK,CAACD,IAAI,CAACS,MAAM,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;EAC/D;EAEA,OAAOF,aAAa,GAAGC,eAAe;AACxC","ignoreList":[]}
@@ -1,9 +1,23 @@
1
- export declare const getMessagesRequestArgs: ({ conversation_id, reply_root_id, }: {
1
+ type MessagesRequestOptions = {
2
2
  conversation_id: number;
3
3
  reply_root_id?: string | null;
4
- }) => {
4
+ anchor?: string | null;
5
+ };
6
+ export declare const getMessagesRequestArgs: ({ conversation_id, reply_root_id, anchor, }: MessagesRequestOptions) => {
5
7
  url: string;
6
8
  data: {
9
+ where: {
10
+ id_around: string;
11
+ };
12
+ perPage: number;
13
+ fields: {
14
+ Message: string[];
15
+ Person: string[];
16
+ ReactionCount: string[];
17
+ };
18
+ include: string[];
19
+ } | {
20
+ where?: undefined;
7
21
  perPage: number;
8
22
  fields: {
9
23
  Message: string[];
@@ -14,8 +28,6 @@ export declare const getMessagesRequestArgs: ({ conversation_id, reply_root_id,
14
28
  };
15
29
  reply_root_id: string | null;
16
30
  };
17
- export declare const getMessagesQueryKey: ({ conversation_id, reply_root_id, }: {
18
- conversation_id: number;
19
- reply_root_id?: string | null;
20
- }) => import("../..").RequestQueryKey;
31
+ export declare const getMessagesQueryKey: (options: MessagesRequestOptions) => import("../..").RequestQueryKey;
32
+ export {};
21
33
  //# sourceMappingURL=get_messages.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"get_messages.d.ts","sourceRoot":"","sources":["../../../src/utils/request/get_messages.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,sBAAsB,GAAI,qCAGpC;IACD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;;;;;;;;;;;;CAeA,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,qCAGjC;IACD,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B,oCAGA,CAAA"}
1
+ {"version":3,"file":"get_messages.d.ts","sourceRoot":"","sources":["../../../src/utils/request/get_messages.ts"],"names":[],"mappings":"AAGA,KAAK,sBAAsB,GAAG;IAC5B,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,sBAAsB,GAAI,6CAIpC,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;CAiBxB,CAAA;AAED,eAAO,MAAM,mBAAmB,GAAI,SAAS,sBAAsB,oCACd,CAAA"}
@@ -2,28 +2,26 @@ import { getRequestQueryKey } from '../../hooks/use_suspense_api';
2
2
  import { getMessageFields, getMessagesInclude } from './messages_data_options';
3
3
  export const getMessagesRequestArgs = ({
4
4
  conversation_id,
5
- reply_root_id
5
+ reply_root_id,
6
+ anchor
6
7
  }) => {
7
8
  const normalizedReplyRootId = reply_root_id ?? null;
8
9
  const url = normalizedReplyRootId ? `/me/conversations/${conversation_id}/messages/${normalizedReplyRootId}/replies` : `/me/conversations/${conversation_id}/messages`;
10
+ const anchored = anchor ? {
11
+ where: {
12
+ id_around: anchor
13
+ }
14
+ } : {};
9
15
  return {
10
16
  url,
11
17
  data: {
12
18
  perPage: 25,
13
19
  fields: getMessageFields,
14
- include: getMessagesInclude
20
+ include: getMessagesInclude,
21
+ ...anchored
15
22
  },
16
23
  reply_root_id: normalizedReplyRootId
17
24
  };
18
25
  };
19
- export const getMessagesQueryKey = ({
20
- conversation_id,
21
- reply_root_id
22
- }) => {
23
- const requestArgs = getMessagesRequestArgs({
24
- conversation_id,
25
- reply_root_id
26
- });
27
- return getRequestQueryKey(requestArgs);
28
- };
26
+ export const getMessagesQueryKey = options => getRequestQueryKey(getMessagesRequestArgs(options));
29
27
  //# sourceMappingURL=get_messages.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"get_messages.js","names":["getRequestQueryKey","getMessageFields","getMessagesInclude","getMessagesRequestArgs","conversation_id","reply_root_id","normalizedReplyRootId","url","data","perPage","fields","include","getMessagesQueryKey","requestArgs"],"sources":["../../../src/utils/request/get_messages.ts"],"sourcesContent":["import { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { getMessageFields, getMessagesInclude } from './messages_data_options'\n\nexport const getMessagesRequestArgs = ({\n conversation_id,\n reply_root_id,\n}: {\n conversation_id: number\n reply_root_id?: string | null\n}) => {\n const normalizedReplyRootId = reply_root_id ?? null\n const url = normalizedReplyRootId\n ? `/me/conversations/${conversation_id}/messages/${normalizedReplyRootId}/replies`\n : `/me/conversations/${conversation_id}/messages`\n\n return {\n url,\n data: {\n perPage: 25,\n fields: getMessageFields,\n include: getMessagesInclude,\n },\n reply_root_id: normalizedReplyRootId,\n }\n}\n\nexport const getMessagesQueryKey = ({\n conversation_id,\n reply_root_id,\n}: {\n conversation_id: number\n reply_root_id?: string | null\n}) => {\n const requestArgs = getMessagesRequestArgs({ conversation_id, reply_root_id })\n return getRequestQueryKey(requestArgs)\n}\n"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,8BAA8B;AACjE,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,yBAAyB;AAE9E,OAAO,MAAMC,sBAAsB,GAAGA,CAAC;EACrCC,eAAe;EACfC;AAIF,CAAC,KAAK;EACJ,MAAMC,qBAAqB,GAAGD,aAAa,IAAI,IAAI;EACnD,MAAME,GAAG,GAAGD,qBAAqB,GAC7B,qBAAqBF,eAAe,aAAaE,qBAAqB,UAAU,GAChF,qBAAqBF,eAAe,WAAW;EAEnD,OAAO;IACLG,GAAG;IACHC,IAAI,EAAE;MACJC,OAAO,EAAE,EAAE;MACXC,MAAM,EAAET,gBAAgB;MACxBU,OAAO,EAAET;IACX,CAAC;IACDG,aAAa,EAAEC;EACjB,CAAC;AACH,CAAC;AAED,OAAO,MAAMM,mBAAmB,GAAGA,CAAC;EAClCR,eAAe;EACfC;AAIF,CAAC,KAAK;EACJ,MAAMQ,WAAW,GAAGV,sBAAsB,CAAC;IAAEC,eAAe;IAAEC;EAAc,CAAC,CAAC;EAC9E,OAAOL,kBAAkB,CAACa,WAAW,CAAC;AACxC,CAAC","ignoreList":[]}
1
+ {"version":3,"file":"get_messages.js","names":["getRequestQueryKey","getMessageFields","getMessagesInclude","getMessagesRequestArgs","conversation_id","reply_root_id","anchor","normalizedReplyRootId","url","anchored","where","id_around","data","perPage","fields","include","getMessagesQueryKey","options"],"sources":["../../../src/utils/request/get_messages.ts"],"sourcesContent":["import { getRequestQueryKey } from '../../hooks/use_suspense_api'\nimport { getMessageFields, getMessagesInclude } from './messages_data_options'\n\ntype MessagesRequestOptions = {\n conversation_id: number\n reply_root_id?: string | null\n anchor?: string | null\n}\n\nexport const getMessagesRequestArgs = ({\n conversation_id,\n reply_root_id,\n anchor,\n}: MessagesRequestOptions) => {\n const normalizedReplyRootId = reply_root_id ?? null\n const url = normalizedReplyRootId\n ? `/me/conversations/${conversation_id}/messages/${normalizedReplyRootId}/replies`\n : `/me/conversations/${conversation_id}/messages`\n const anchored = anchor ? { where: { id_around: anchor } } : {}\n\n return {\n url,\n data: {\n perPage: 25,\n fields: getMessageFields,\n include: getMessagesInclude,\n ...anchored,\n },\n reply_root_id: normalizedReplyRootId,\n }\n}\n\nexport const getMessagesQueryKey = (options: MessagesRequestOptions) =>\n getRequestQueryKey(getMessagesRequestArgs(options))\n"],"mappings":"AAAA,SAASA,kBAAkB,QAAQ,8BAA8B;AACjE,SAASC,gBAAgB,EAAEC,kBAAkB,QAAQ,yBAAyB;AAQ9E,OAAO,MAAMC,sBAAsB,GAAGA,CAAC;EACrCC,eAAe;EACfC,aAAa;EACbC;AACsB,CAAC,KAAK;EAC5B,MAAMC,qBAAqB,GAAGF,aAAa,IAAI,IAAI;EACnD,MAAMG,GAAG,GAAGD,qBAAqB,GAC7B,qBAAqBH,eAAe,aAAaG,qBAAqB,UAAU,GAChF,qBAAqBH,eAAe,WAAW;EACnD,MAAMK,QAAQ,GAAGH,MAAM,GAAG;IAAEI,KAAK,EAAE;MAAEC,SAAS,EAAEL;IAAO;EAAE,CAAC,GAAG,CAAC,CAAC;EAE/D,OAAO;IACLE,GAAG;IACHI,IAAI,EAAE;MACJC,OAAO,EAAE,EAAE;MACXC,MAAM,EAAEb,gBAAgB;MACxBc,OAAO,EAAEb,kBAAkB;MAC3B,GAAGO;IACL,CAAC;IACDJ,aAAa,EAAEE;EACjB,CAAC;AACH,CAAC;AAED,OAAO,MAAMS,mBAAmB,GAAIC,OAA+B,IACjEjB,kBAAkB,CAACG,sBAAsB,CAACc,OAAO,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,3 @@
1
+ export declare const ULID_CHARS = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
2
+ export declare function decodeUlidTime(ulid: string): number;
3
+ //# sourceMappingURL=ulid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ulid.d.ts","sourceRoot":"","sources":["../../src/utils/ulid.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,UAAU,qCAAqC,CAAA;AAI5D,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnD"}
@@ -0,0 +1,7 @@
1
+ export const ULID_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; // Crockford's Base32
2
+
3
+ const TIME_LENGTH = 10;
4
+ export function decodeUlidTime(ulid) {
5
+ return ulid.slice(0, TIME_LENGTH).toUpperCase().split('').reduce((time, char) => time * 32 + ULID_CHARS.indexOf(char), 0);
6
+ }
7
+ //# sourceMappingURL=ulid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ulid.js","names":["ULID_CHARS","TIME_LENGTH","decodeUlidTime","ulid","slice","toUpperCase","split","reduce","time","char","indexOf"],"sources":["../../src/utils/ulid.ts"],"sourcesContent":["export const ULID_CHARS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' // Crockford's Base32\n\nconst TIME_LENGTH = 10\n\nexport function decodeUlidTime(ulid: string): number {\n return ulid\n .slice(0, TIME_LENGTH)\n .toUpperCase()\n .split('')\n .reduce((time, char) => time * 32 + ULID_CHARS.indexOf(char), 0)\n}\n"],"mappings":"AAAA,OAAO,MAAMA,UAAU,GAAG,kCAAkC,EAAC;;AAE7D,MAAMC,WAAW,GAAG,EAAE;AAEtB,OAAO,SAASC,cAAcA,CAACC,IAAY,EAAU;EACnD,OAAOA,IAAI,CACRC,KAAK,CAAC,CAAC,EAAEH,WAAW,CAAC,CACrBI,WAAW,CAAC,CAAC,CACbC,KAAK,CAAC,EAAE,CAAC,CACTC,MAAM,CAAC,CAACC,IAAI,EAAEC,IAAI,KAAKD,IAAI,GAAG,EAAE,GAAGR,UAAU,CAACU,OAAO,CAACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACpE","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "4.2.1-qa-staging.0",
3
+ "version": "4.2.1-qa-staging.2",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@fortawesome/fontawesome-svg-core": "^7.2.0",
35
35
  "@fortawesome/react-native-fontawesome": "^0.3.2",
36
- "@planningcenter/emoji-keyboard": "4.2.1-qa-staging.0",
36
+ "@planningcenter/emoji-keyboard": "4.2.1-qa-staging.2",
37
37
  "lodash-inflection": "^1.5.0"
38
38
  },
39
39
  "peerDependencies": {
@@ -84,5 +84,5 @@
84
84
  "sf-symbols-typescript": "^2.2.0",
85
85
  "typescript": "~6.0.3"
86
86
  },
87
- "gitHead": "d00bef90b0009a11eb586815d32a57b08ab52ed5"
87
+ "gitHead": "c5e62783ef9da7bf5ecbae701318df69b9686608"
88
88
  }
@@ -0,0 +1,24 @@
1
+ import { getMessagesQueryKey, getMessagesRequestArgs } from '../../../utils/request/get_messages'
2
+
3
+ describe('getMessagesRequestArgs', () => {
4
+ it('requests the newest page by default', () => {
5
+ const { data } = getMessagesRequestArgs({ conversation_id: 1 })
6
+
7
+ expect(data).not.toHaveProperty('where')
8
+ expect(data).not.toHaveProperty('order')
9
+ })
10
+
11
+ it('opens around the anchor when one is given', () => {
12
+ const { data } = getMessagesRequestArgs({ conversation_id: 1, anchor: '01ANCHOR' })
13
+
14
+ expect(data).toMatchObject({ where: { id_around: '01ANCHOR' } })
15
+ expect(data).not.toHaveProperty('order')
16
+ })
17
+
18
+ it('keeps anchored and live queries in separate cache entries', () => {
19
+ const live = getMessagesQueryKey({ conversation_id: 1 })
20
+ const anchored = getMessagesQueryKey({ conversation_id: 1, anchor: '01ANCHOR' })
21
+
22
+ expect(anchored).not.toEqual(live)
23
+ })
24
+ })
@@ -0,0 +1,15 @@
1
+ import { generatePlaceholderUlid } from '../../utils/generate_placeholder_ulid'
2
+ import { decodeUlidTime } from '../../utils/ulid'
3
+
4
+ describe('decodeUlidTime', () => {
5
+ it('decodes the spec example', () => {
6
+ expect(decodeUlidTime('01ARYZ6S41TSV4RRFFQ69G5FAV')).toBe(1469918176385)
7
+ })
8
+
9
+ it('round-trips a placeholder ulid', () => {
10
+ const now = Date.now()
11
+ jest.spyOn(Date, 'now').mockReturnValue(now)
12
+
13
+ expect(decodeUlidTime(generatePlaceholderUlid())).toBe(now)
14
+ })
15
+ })
@@ -0,0 +1,51 @@
1
+ import { render, screen } from '@testing-library/react-native'
2
+ import React from 'react'
3
+ import { Text } from 'react-native'
4
+ import { FailedResponse } from '../../../types/api_primitives'
5
+ import { ResponseError } from '../../../utils/response_error'
6
+ import { AnchorNotFoundBoundary } from '../anchor_not_found_boundary'
7
+
8
+ const responseError = (status: number) =>
9
+ new ResponseError({ status, statusText: 'nope' } as unknown as FailedResponse)
10
+
11
+ function Thrower({ error }: { error: Error | null }) {
12
+ if (error) throw error
13
+ return <Text>content</Text>
14
+ }
15
+
16
+ describe('AnchorNotFoundBoundary', () => {
17
+ beforeEach(() => jest.spyOn(console, 'error').mockImplementation(() => {}))
18
+
19
+ it('reports a missing anchor and renders nothing while the parent drops it', () => {
20
+ const onAnchorNotFound = jest.fn()
21
+
22
+ render(
23
+ <AnchorNotFoundBoundary onAnchorNotFound={onAnchorNotFound}>
24
+ <Thrower error={responseError(404)} />
25
+ </AnchorNotFoundBoundary>
26
+ )
27
+
28
+ expect(onAnchorNotFound).toHaveBeenCalledTimes(1)
29
+ expect(screen.queryByText('content')).toBeNull()
30
+ })
31
+
32
+ it('lets every other error through untouched', () => {
33
+ const onAnchorNotFound = jest.fn()
34
+
35
+ expect(() =>
36
+ render(
37
+ <AnchorNotFoundBoundary onAnchorNotFound={onAnchorNotFound}>
38
+ <Thrower error={responseError(403)} />
39
+ </AnchorNotFoundBoundary>
40
+ )
41
+ ).toThrow()
42
+ expect(() =>
43
+ render(
44
+ <AnchorNotFoundBoundary onAnchorNotFound={onAnchorNotFound}>
45
+ <Thrower error={new Error('render blew up')} />
46
+ </AnchorNotFoundBoundary>
47
+ )
48
+ ).toThrow('render blew up')
49
+ expect(onAnchorNotFound).not.toHaveBeenCalled()
50
+ })
51
+ })
@@ -104,6 +104,7 @@ let queryClient: QueryClient
104
104
 
105
105
  // A top-level rerender would rebuild the wrapper context and redraw every row.
106
106
  let setHarnessConversation: (next: ConversationResource) => void = () => {}
107
+ let harnessAnchorMessageId: string | null = null
107
108
 
108
109
  function Harness() {
109
110
  const [current, setCurrent] = React.useState(conversation)
@@ -117,6 +118,7 @@ function Harness() {
117
118
  conversation={current}
118
119
  conversationId={CONVERSATION_ID}
119
120
  messages={loaded}
121
+ anchorMessageId={harnessAnchorMessageId}
120
122
  hasNextPage
121
123
  onEndReached={() => {}}
122
124
  />
@@ -176,9 +178,49 @@ beforeEach(() => {
176
178
  afterEach(() => {
177
179
  queryClient.clear()
178
180
  jest.clearAllMocks()
181
+ harnessAnchorMessageId = null
179
182
  })
180
183
 
181
184
  describe('MessageList', () => {
185
+ it('pins the anchor row to the bottom edge as content lays out, until the user drags', () => {
186
+ const scrollToIndex = jest.spyOn(FlatList.prototype, 'scrollToIndex').mockImplementation()
187
+ harnessAnchorMessageId = messages[3].id
188
+ renderList()
189
+ const list = screen.UNSAFE_getByType(FlatList)
190
+ const anchorIndex = list.props.data.findIndex(
191
+ (item: { id: string }) => item.id === messages[3].id
192
+ )
193
+
194
+ act(() => list.props.onLayout({ nativeEvent: { layout: { height: 600 } } }))
195
+ act(() => list.props.onContentSizeChange(0, 400))
196
+ expect(scrollToIndex).not.toHaveBeenCalled()
197
+
198
+ act(() => list.props.onContentSizeChange(0, 1000))
199
+ act(() => list.props.onContentSizeChange(0, 2000))
200
+ expect(anchorIndex).toBeGreaterThan(0)
201
+ expect(scrollToIndex).toHaveBeenCalledTimes(2)
202
+ expect(scrollToIndex).toHaveBeenLastCalledWith({
203
+ index: anchorIndex,
204
+ viewPosition: 0,
205
+ animated: false,
206
+ })
207
+
208
+ act(() => list.props.onScrollBeginDrag({ nativeEvent: {} }))
209
+ act(() => list.props.onContentSizeChange(0, 3000))
210
+ expect(scrollToIndex).toHaveBeenCalledTimes(2)
211
+ })
212
+
213
+ it('leaves the offset alone when there is no anchor', () => {
214
+ const scrollToIndex = jest.spyOn(FlatList.prototype, 'scrollToIndex').mockImplementation()
215
+ renderList()
216
+ const list = screen.UNSAFE_getByType(FlatList)
217
+
218
+ act(() => list.props.onLayout({ nativeEvent: { layout: { height: 600 } } }))
219
+ act(() => list.props.onContentSizeChange(0, 1000))
220
+
221
+ expect(scrollToIndex).not.toHaveBeenCalled()
222
+ })
223
+
182
224
  it('redraws only the reacted row when a reaction arrives', () => {
183
225
  renderList()
184
226
  const target = messages[3]
@@ -0,0 +1,21 @@
1
+ import React, { PropsWithChildren } from 'react'
2
+ import { ResponseError } from '../../utils/response_error'
3
+
4
+ type Props = PropsWithChildren<{ onAnchorNotFound: () => void }>
5
+
6
+ export class AnchorNotFoundBoundary extends React.Component<Props, { recovering: boolean }> {
7
+ state = { recovering: false }
8
+
9
+ static getDerivedStateFromError(error: Error) {
10
+ if (error instanceof ResponseError && error.status === 404) return { recovering: true }
11
+ throw error
12
+ }
13
+
14
+ componentDidCatch() {
15
+ this.props.onAnchorNotFound()
16
+ }
17
+
18
+ render() {
19
+ return this.state.recovering ? null : this.props.children
20
+ }
21
+ }