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

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 (87) hide show
  1. package/build/components/conversation/message_form.d.ts.map +1 -1
  2. package/build/components/conversation/message_form.js +1 -1
  3. package/build/components/conversation/message_form.js.map +1 -1
  4. package/build/contexts/conversation_context.d.ts +3 -1
  5. package/build/contexts/conversation_context.d.ts.map +1 -1
  6. package/build/contexts/conversation_context.js +23 -18
  7. package/build/contexts/conversation_context.js.map +1 -1
  8. package/build/hooks/use_conversation_message_lookup.d.ts +7 -0
  9. package/build/hooks/use_conversation_message_lookup.d.ts.map +1 -0
  10. package/build/hooks/use_conversation_message_lookup.js +52 -0
  11. package/build/hooks/use_conversation_message_lookup.js.map +1 -0
  12. package/build/hooks/use_conversation_messages.d.ts +1 -0
  13. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  14. package/build/hooks/use_conversation_messages.js +8 -1
  15. package/build/hooks/use_conversation_messages.js.map +1 -1
  16. package/build/hooks/use_conversation_messages_jolt_events.d.ts +12 -4
  17. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  18. package/build/hooks/use_conversation_messages_jolt_events.js +82 -88
  19. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  20. package/build/hooks/use_fetch_newer_messages.d.ts.map +1 -1
  21. package/build/hooks/use_fetch_newer_messages.js +27 -21
  22. package/build/hooks/use_fetch_newer_messages.js.map +1 -1
  23. package/build/hooks/use_fetch_newer_on_foreground.d.ts +1 -1
  24. package/build/hooks/use_fetch_newer_on_foreground.d.ts.map +1 -1
  25. package/build/hooks/use_fetch_newer_on_foreground.js +2 -1
  26. package/build/hooks/use_fetch_newer_on_foreground.js.map +1 -1
  27. package/build/hooks/use_held_back_messages.d.ts +11 -0
  28. package/build/hooks/use_held_back_messages.d.ts.map +1 -0
  29. package/build/hooks/use_held_back_messages.js +24 -0
  30. package/build/hooks/use_held_back_messages.js.map +1 -0
  31. package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
  32. package/build/hooks/use_message_create_or_update.js +91 -80
  33. package/build/hooks/use_message_create_or_update.js.map +1 -1
  34. package/build/hooks/use_message_reaction_toggle.d.ts.map +1 -1
  35. package/build/hooks/use_message_reaction_toggle.js +45 -40
  36. package/build/hooks/use_message_reaction_toggle.js.map +1 -1
  37. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  38. package/build/screens/conversation_screen.d.ts.map +1 -1
  39. package/build/screens/conversation_screen.js +485 -156
  40. package/build/screens/conversation_screen.js.map +1 -1
  41. package/build/screens/message_actions_screen.d.ts.map +1 -1
  42. package/build/screens/message_actions_screen.js +21 -26
  43. package/build/screens/message_actions_screen.js.map +1 -1
  44. package/build/screens/message_report_screen.d.ts.map +1 -1
  45. package/build/screens/message_report_screen.js +17 -44
  46. package/build/screens/message_report_screen.js.map +1 -1
  47. package/build/screens/reactions_screen.d.ts.map +1 -1
  48. package/build/screens/reactions_screen.js +70 -88
  49. package/build/screens/reactions_screen.js.map +1 -1
  50. package/build/utils/cache/find_message_in_caches.d.ts +4 -0
  51. package/build/utils/cache/find_message_in_caches.d.ts.map +1 -0
  52. package/build/utils/cache/find_message_in_caches.js +16 -0
  53. package/build/utils/cache/find_message_in_caches.js.map +1 -0
  54. package/build/utils/cache/optimistically_update_message.d.ts +2 -1
  55. package/build/utils/cache/optimistically_update_message.d.ts.map +1 -1
  56. package/build/utils/cache/optimistically_update_message.js +4 -4
  57. package/build/utils/cache/optimistically_update_message.js.map +1 -1
  58. package/build/utils/cache/prepend_newer_page.d.ts +1 -1
  59. package/build/utils/cache/prepend_newer_page.d.ts.map +1 -1
  60. package/build/utils/cache/prepend_newer_page.js +10 -9
  61. package/build/utils/cache/prepend_newer_page.js.map +1 -1
  62. package/package.json +3 -3
  63. package/src/__tests__/hooks/use_conversation_messages.test.ts +22 -0
  64. package/src/__tests__/hooks/use_conversation_messages_jolt_events.test.ts +22 -25
  65. package/src/components/conversation/message_form.tsx +1 -2
  66. package/src/contexts/conversation_context.tsx +6 -1
  67. package/src/hooks/__tests__/use_fetch_newer_messages.test.tsx +68 -0
  68. package/src/hooks/__tests__/use_held_back_messages.test.tsx +60 -0
  69. package/src/hooks/__tests__/use_message_reaction_toggle.test.tsx +73 -0
  70. package/src/hooks/use_conversation_message_lookup.ts +29 -0
  71. package/src/hooks/use_conversation_messages.ts +9 -0
  72. package/src/hooks/use_conversation_messages_jolt_events.ts +43 -41
  73. package/src/hooks/use_fetch_newer_messages.ts +19 -12
  74. package/src/hooks/use_fetch_newer_on_foreground.ts +2 -2
  75. package/src/hooks/use_held_back_messages.ts +33 -0
  76. package/src/hooks/use_message_create_or_update.ts +8 -8
  77. package/src/hooks/use_message_reaction_toggle.ts +3 -1
  78. package/src/screens/conversation_new/components/services_form.tsx +1 -1
  79. package/src/screens/conversation_screen.tsx +20 -20
  80. package/src/screens/message_actions_screen.tsx +3 -5
  81. package/src/screens/message_report_screen.tsx +2 -3
  82. package/src/screens/reactions_screen.tsx +2 -4
  83. package/src/utils/cache/__tests__/find_message_in_caches.test.ts +37 -0
  84. package/src/utils/cache/__tests__/prepend_newer_page.test.ts +13 -14
  85. package/src/utils/cache/find_message_in_caches.ts +20 -0
  86. package/src/utils/cache/optimistically_update_message.ts +2 -5
  87. package/src/utils/cache/prepend_newer_page.ts +7 -10
@@ -1,5 +1,6 @@
1
1
  import { InfiniteData, useMutation } from '@tanstack/react-query'
2
2
  import { chatQueryClient } from '../contexts/api_provider'
3
+ import { useConversationContext } from '../contexts/conversation_context'
3
4
  import { ApiCollection, ApiResource, MessageResource } from '../types'
4
5
  import { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'
5
6
  import {
@@ -35,6 +36,12 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
35
36
  const isEditing = !isNewMessage(message)
36
37
  const apiClient = useApiClient()
37
38
  const currentPerson = useCurrentPerson()
39
+ const { messagesQueryKey } = useConversationContext()
40
+ const liveQueryKey = getMessagesQueryKey({
41
+ conversation_id: conversationId,
42
+ reply_root_id: replyRootId,
43
+ })
44
+ const queryKey = isEditing ? (messagesQueryKey ?? liveQueryKey) : liveQueryKey
38
45
 
39
46
  const mutation = useMutation({
40
47
  mutationFn: ({ text, attachments, idempotentKey }: ResolvedMessageMutationVariables) => {
@@ -79,6 +86,7 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
79
86
  message,
80
87
  text,
81
88
  replyRootId,
89
+ queryKey,
82
90
  })
83
91
 
84
92
  return { message: optimisticMessage }
@@ -102,10 +110,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
102
110
 
103
111
  // Add error to the optimistic message from the cache on error
104
112
  if (optimisticMessage) {
105
- const queryKey = getMessagesQueryKey({
106
- conversation_id: conversationId,
107
- reply_root_id: replyRootId,
108
- })
109
113
  chatQueryClient.setQueryData(
110
114
  queryKey,
111
115
  (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>
@@ -125,10 +129,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
125
129
  const { message: optimisticMessage } = context || {}
126
130
  const updatedMessage = result.data
127
131
  type QueryData = InfiniteData<ApiCollection<MessageResource>>
128
- const queryKey = getMessagesQueryKey({
129
- conversation_id: conversationId,
130
- reply_root_id: replyRootId,
131
- })
132
132
 
133
133
  // First remove the optimistic message if it exists
134
134
  if (optimisticMessage) {
@@ -1,6 +1,7 @@
1
1
  import { InfiniteData, useMutation, useQueryClient } from '@tanstack/react-query'
2
2
  import { useCallback } from 'react'
3
3
  import { Alert } from 'react-native'
4
+ import { useConversationContext } from '../contexts/conversation_context'
4
5
  import { ApiCollection, ApiResource, MessageResource } from '../types'
5
6
  import { ReactionCountResource } from '../types/resources/reaction'
6
7
  import { updateRecordInPagesData, REACTION_EMOJIS } from '../utils'
@@ -30,7 +31,8 @@ export function useMessageReactionToggle({
30
31
  }: UseMessageReactionToggleProps) {
31
32
  const apiClient = useApiClient()
32
33
  const queryClient = useQueryClient()
33
- const queryKey = getMessagesQueryKey({ conversation_id })
34
+ const { messagesQueryKey } = useConversationContext()
35
+ const queryKey = messagesQueryKey ?? getMessagesQueryKey({ conversation_id })
34
36
  const message_id = message.id
35
37
 
36
38
  const toggleReaction = useCallback(
@@ -45,7 +45,7 @@ export const ServicesForm = ({
45
45
  const customAvatarsEnabled = featureEnabled(availableFeatures.custom_conversation_avatars)
46
46
  const safetyLockEnabled = featureEnabled(availableFeatures.conversation_safety_lock)
47
47
  const [selectedPlanId, setSelectedPlanId] = useState<number | undefined>(initialPlanId)
48
- const [filterByPlan, setFilterByPlan] = useState(!!initialPlanId)
48
+ const [filterByPlan, setFilterByPlan] = useState<boolean>(!!initialPlanId)
49
49
  const initialState = useMemo(() => uniq(initialTeamIds) || [], [initialTeamIds]) // Uniq here because services can send duplicates in the teams_i_lead response.
50
50
  const [selectedTeamIds, setSelectedTeamIds] = useState<number[]>(initialState)
51
51
 
@@ -33,6 +33,7 @@ import { useConversationMessages } from '../hooks/use_conversation_messages'
33
33
  import { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'
34
34
  import { useFetchNewerMessages } from '../hooks/use_fetch_newer_messages'
35
35
  import { useFetchNewerOnForeground } from '../hooks/use_fetch_newer_on_foreground'
36
+ import { useHeldBackMessages } from '../hooks/use_held_back_messages'
36
37
  import { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'
37
38
  import {
38
39
  analyticsEvents,
@@ -45,6 +46,7 @@ import { ConversationResource } from '../types/resources/conversation'
45
46
  import { ConversationBadgeResource } from '../types/resources/conversation_badge'
46
47
  import { MessageResource } from '../types/resources/message'
47
48
  import { gatedMessageCache } from '../utils/gated_message_cache'
49
+ import { getMessagesQueryKey } from '../utils/request/get_messages'
48
50
  import { decodeUlidTime } from '../utils/ulid'
49
51
 
50
52
  export type ConversationRouteProps = {
@@ -85,6 +87,7 @@ export function ConversationScreen({ route }: ConversationScreenProps) {
85
87
  <ConversationContextProvider
86
88
  conversationId={conversation_id}
87
89
  currentPageReplyRootId={reply_root_id ?? null}
90
+ messagesQueryKey={getMessagesQueryKey({ conversation_id, reply_root_id, anchor })}
88
91
  >
89
92
  {anchor ? (
90
93
  <AnchorNotFoundBoundary onAnchorNotFound={dropAnchor}>
@@ -134,23 +137,27 @@ function ConversationScreenContent({
134
137
  const caughtUp = !hasPreviousPage
135
138
  const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)
136
139
  const readingHistory = showJumpToBottomButton
137
- const skippedNewMessages = useRef(false)
138
- const messageCaches = [
139
- gatedMessageCache({
140
+ const newestMessageId = messages[0]?.id
141
+ const fetchNewer = useFetchNewerMessages({ conversation_id, reply_root_id, queryKey })
142
+ const { onSkippedNewMessage } = useHeldBackMessages({
143
+ fetchNewer,
144
+ newestMessageId,
145
+ readingHistory,
146
+ caughtUp,
147
+ })
148
+ useConversationJoltEvents({ conversationId: conversation_id })
149
+ useConversationMessagesJoltEvents({
150
+ conversationId: conversation_id,
151
+ replyRootId: reply_root_id ?? null,
152
+ messageCache: gatedMessageCache({
140
153
  queryKey,
141
154
  acceptNewMessages: caughtUp && !readingHistory,
142
- onSkippedNewMessage: () => {
143
- skippedNewMessages.current = true
144
- },
155
+ onSkippedNewMessage,
145
156
  }),
146
- ]
147
- const newestMessageId = messages[0]?.id
148
- useConversationJoltEvents({ conversationId: conversation_id })
149
- useConversationMessagesJoltEvents({ conversationId: conversation_id, messageCaches })
157
+ })
150
158
  const { markHandledByMessageForm } = useVideoModerationJoltEvents()
151
159
  useEnsureConversationsRouteExists()
152
160
  useMarkLatestMessageRead({ conversation, messages, enabled: !behindLatest })
153
- const fetchNewer = useFetchNewerMessages({ conversation_id, reply_root_id, queryKey })
154
161
  useFetchNewerOnForeground({ fetchNewer, newestMessageId, enabled: anchored && caughtUp })
155
162
  const noMessages = messages.length === 0
156
163
 
@@ -187,9 +194,9 @@ function ConversationScreenContent({
187
194
  }, [handleReturnToBottom, onExitAnchoredMode])
188
195
  const jumpToLatest = useCallback(() => {
189
196
  setShowJumpToBottomButton(false)
190
- if (behindLatest) exitAnchoredMode()
197
+ if (anchored) exitAnchoredMode()
191
198
  else handleReturnToBottom()
192
- }, [behindLatest, exitAnchoredMode, handleReturnToBottom])
199
+ }, [anchored, exitAnchoredMode, handleReturnToBottom])
193
200
 
194
201
  const trackScroll = (event: any) => {
195
202
  const offsetY = event.nativeEvent.contentOffset.y
@@ -203,13 +210,6 @@ function ConversationScreenContent({
203
210
  fetchPreviousPage()
204
211
  }
205
212
 
206
- useEffect(() => {
207
- if (readingHistory || !caughtUp || !newestMessageId || !skippedNewMessages.current) return
208
-
209
- skippedNewMessages.current = false
210
- fetchNewer(newestMessageId)
211
- }, [caughtUp, fetchNewer, newestMessageId, readingHistory])
212
-
213
213
  useEffect(() => {
214
214
  if (reply_root_id) {
215
215
  navigation.setParams({
@@ -9,6 +9,7 @@ import { useReactionStyles } from '../components/conversation/message_reaction'
9
9
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
10
10
  import { useCreateAndroidRippleColor, useFontScale, useTheme } from '../hooks'
11
11
  import { useApiClient } from '../hooks/use_api_client'
12
+ import { useConversationMessageLookup } from '../hooks/use_conversation_message_lookup'
12
13
  import { useConversationMessages } from '../hooks/use_conversation_messages'
13
14
  import { availableFeatures, useFeatures } from '../hooks/use_features'
14
15
  import { useMessageReactionToggle } from '../hooks/use_message_reaction_toggle'
@@ -41,11 +42,8 @@ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
41
42
  isSystemMessage,
42
43
  } = route.params
43
44
 
44
- const { messages, refetch } = useConversationMessages(
45
- { conversation_id },
46
- { refetchOnMount: false }
47
- )
48
- const message = messages.find(m => m.id === message_id)
45
+ const { refetch } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
46
+ const message = useConversationMessageLookup({ conversation_id, message_id })
49
47
 
50
48
  if (!message) return null
51
49
 
@@ -14,7 +14,7 @@ import {
14
14
  } from '../components/display/platform_modal_header_buttons'
15
15
  import BlankState from '../components/primitive/blank_state_primitive'
16
16
  import { useTheme } from '../hooks'
17
- import { useConversationMessages } from '../hooks/use_conversation_messages'
17
+ import { useConversationMessageLookup } from '../hooks/use_conversation_message_lookup'
18
18
  import { useReportMessage } from '../hooks/use_report_message'
19
19
  import { MessageResource } from '../types'
20
20
  import { MessageReportReason } from '../types/resources/message_report'
@@ -51,8 +51,7 @@ export type MessageReportScreenProps = StaticScreenProps<{
51
51
  export function MessageReportScreen({ route }: MessageReportScreenProps) {
52
52
  const { conversation_id, message_id } = route.params
53
53
 
54
- const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
55
- const message = messages.find(m => m.id === message_id)
54
+ const message = useConversationMessageLookup({ conversation_id, message_id })
56
55
 
57
56
  if (!message) return null
58
57
 
@@ -7,7 +7,7 @@ import { Avatar, Text } from '../components'
7
7
  import { Tabs } from '../components/display/tabs'
8
8
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
9
9
  import { useSuspenseGet, useTheme } from '../hooks'
10
- import { useConversationMessages } from '../hooks/use_conversation_messages'
10
+ import { useConversationMessageLookup } from '../hooks/use_conversation_message_lookup'
11
11
  import { useFontScale } from '../hooks/use_font_scale'
12
12
  import { MemberResource } from '../types'
13
13
  import { ReactionCountResource } from '../types/resources/reaction'
@@ -31,9 +31,7 @@ export function ReactionsScreen({ route }: ReactionScreenProps) {
31
31
  const { conversation_id, message_id, reaction_value } = route.params
32
32
  const styles = useStyles()
33
33
 
34
- const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
35
-
36
- const message = messages.find(m => m.id === message_id)
34
+ const message = useConversationMessageLookup({ conversation_id, message_id })
37
35
  const reactionCounts = message?.reactionCounts || []
38
36
  const initialReactionCount =
39
37
  reactionCounts.find(r => r.value === reaction_value) || reactionCounts[0]
@@ -0,0 +1,37 @@
1
+ import { QueryClient } from '@tanstack/react-query'
2
+ import { getMessagesQueryKey } from '../../request/get_messages'
3
+ import { findMessageInCaches } from '../find_message_in_caches'
4
+
5
+ const page = (ids: string[]) => ({
6
+ data: ids.map(id => ({ id, type: 'Message' })),
7
+ links: {},
8
+ meta: { count: ids.length, totalCount: ids.length },
9
+ })
10
+
11
+ const seed = (queryClient: QueryClient, key: unknown[], ids: string[]) =>
12
+ queryClient.setQueryData(key, { pages: [page(ids)], pageParams: [{}] })
13
+
14
+ describe('findMessageInCaches', () => {
15
+ const queryClient = new QueryClient()
16
+
17
+ beforeEach(() => {
18
+ queryClient.clear()
19
+ seed(queryClient, getMessagesQueryKey({ conversation_id: 1 }), ['01C', '01B'])
20
+ seed(queryClient, getMessagesQueryKey({ conversation_id: 1, anchor: '01A' }), ['01A', '00Z'])
21
+ seed(queryClient, getMessagesQueryKey({ conversation_id: 1, reply_root_id: '01B' }), ['01R'])
22
+ seed(queryClient, getMessagesQueryKey({ conversation_id: 2 }), ['02A'])
23
+ })
24
+
25
+ it('finds a message in the live cache', () => {
26
+ expect(findMessageInCaches(queryClient, 1, '01B')?.id).toBe('01B')
27
+ })
28
+
29
+ it('finds a message that only the anchored cache holds', () => {
30
+ expect(findMessageInCaches(queryClient, 1, '00Z')?.id).toBe('00Z')
31
+ })
32
+
33
+ it('ignores reply threads and other conversations', () => {
34
+ expect(findMessageInCaches(queryClient, 1, '01R')).toBeUndefined()
35
+ expect(findMessageInCaches(queryClient, 1, '02A')).toBeUndefined()
36
+ })
37
+ })
@@ -5,31 +5,30 @@ const page = (ids: string[], next?: { idGt: string }) => ({
5
5
  links: {},
6
6
  meta: { count: ids.length, totalCount: ids.length, next },
7
7
  })
8
- const pageParam = { where: { id_gt: '01C' }, order: 'asc' }
9
8
 
10
9
  describe('prependNewerPage', () => {
11
10
  const cached = { pages: [page(['01C', '01B']), page(['01A'])], pageParams: [{}, { offset: 1 }] }
12
11
 
13
- it('prepends only the messages the cache does not already hold', () => {
14
- const result = prependNewerPage(cached, page(['01C', '01D', '01E']), pageParam)
12
+ it('merges the new rows into the first page and leaves the page params alone', () => {
13
+ const result = prependNewerPage(cached, [page(['01C', '01D', '01E'])])
15
14
 
16
- expect(result?.pages[0].data.map(m => m.id)).toEqual(['01D', '01E'])
17
- expect(result?.pages).toHaveLength(3)
18
- expect(result?.pageParams[0]).toEqual(pageParam)
15
+ expect(result?.pages).toHaveLength(2)
16
+ expect(result?.pages[0].data.map(m => m.id)).toEqual(['01D', '01E', '01C', '01B'])
17
+ expect(result?.pageParams).toEqual(cached.pageParams)
19
18
  })
20
19
 
21
- it('leaves the cache alone when nothing new came back', () => {
22
- expect(prependNewerPage(cached, page(['01C']), pageParam)).toBe(cached)
23
- })
20
+ it('merges every fetched batch, newest last', () => {
21
+ const result = prependNewerPage(cached, [page(['01D', '01E']), page(['01F'])])
24
22
 
25
- it('still prepends an empty page when the server reports more newer messages', () => {
26
- const result = prependNewerPage(cached, page(['01C'], { idGt: '01C' }), pageParam)
23
+ expect(result?.pages[0].data.map(m => m.id)).toEqual(['01D', '01E', '01F', '01C', '01B'])
24
+ })
27
25
 
28
- expect(result?.pages[0].data).toEqual([])
29
- expect(result?.pages[0].meta.next).toEqual({ idGt: '01C' })
26
+ it('returns the same data when nothing new came back', () => {
27
+ expect(prependNewerPage(cached, [page(['01C'])])).toBe(cached)
28
+ expect(prependNewerPage(cached, [])).toBe(cached)
30
29
  })
31
30
 
32
31
  it('does nothing without cached data', () => {
33
- expect(prependNewerPage(undefined, page(['01D']), pageParam)).toBeUndefined()
32
+ expect(prependNewerPage(undefined, [page(['01D'])])).toBeUndefined()
34
33
  })
35
34
  })
@@ -0,0 +1,20 @@
1
+ import { InfiniteData, QueryClient } from '@tanstack/react-query'
2
+ import { ApiCollection, MessageResource } from '../../types'
3
+ import { getMessagesRequestArgs } from '../request/get_messages'
4
+
5
+ type QueryData = InfiniteData<ApiCollection<MessageResource>>
6
+
7
+ export const findMessageInCaches = (
8
+ queryClient: QueryClient,
9
+ conversation_id: number,
10
+ message_id: string
11
+ ): MessageResource | undefined => {
12
+ const { url } = getMessagesRequestArgs({ conversation_id })
13
+
14
+ for (const [, data] of queryClient.getQueriesData<QueryData>({ queryKey: [url] })) {
15
+ const found = data?.pages.flatMap(page => page.data).find(message => message.id === message_id)
16
+ if (found) return found
17
+ }
18
+
19
+ return undefined
20
+ }
@@ -9,19 +9,16 @@ export function optimisticallyUpdateMessage({
9
9
  message,
10
10
  text,
11
11
  replyRootId,
12
+ queryKey = getMessagesQueryKey({ conversation_id: conversationId, reply_root_id: replyRootId }),
12
13
  }: {
13
14
  conversationId: number
14
15
  message: MessageResource
15
16
  text: string
16
17
  replyRootId?: string | null
18
+ queryKey?: unknown[]
17
19
  }) {
18
20
  type QueryData = InfiniteData<ApiCollection<MessageResource>>
19
21
 
20
- const queryKey = getMessagesQueryKey({
21
- conversation_id: conversationId,
22
- reply_root_id: replyRootId,
23
- })
24
-
25
22
  let optimisticMessage = message
26
23
 
27
24
  chatQueryClient.setQueryData<QueryData>(queryKey, data =>
@@ -6,17 +6,14 @@ type PagesData<T extends ResourceObject> = InfiniteData<ApiCollection<T>, Partia
6
6
 
7
7
  export function prependNewerPage<T extends ResourceObject>(
8
8
  data: PagesData<T> | undefined,
9
- page: ApiCollection<T>,
10
- pageParam: Partial<RequestData>
9
+ pages: ApiCollection<T>[]
11
10
  ): PagesData<T> | undefined {
12
- if (!data) return data
11
+ if (!data || data.pages.length === 0) return data
13
12
 
14
- const knownIds = new Set(data.pages.flatMap(p => p.data.map(record => record.id)))
15
- const fresh = page.data.filter(record => !knownIds.has(record.id))
16
- if (fresh.length === 0 && !page.meta?.next) return data
13
+ const knownIds = new Set(data.pages.flatMap(page => page.data.map(record => record.id)))
14
+ const fresh = pages.flatMap(page => page.data).filter(record => !knownIds.has(record.id))
15
+ if (fresh.length === 0) return data
17
16
 
18
- return {
19
- pages: [{ ...page, data: fresh }, ...data.pages],
20
- pageParams: [pageParam, ...data.pageParams],
21
- }
17
+ const [first, ...rest] = data.pages
18
+ return { ...data, pages: [{ ...first, data: [...fresh, ...first.data] }, ...rest] }
22
19
  }