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

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 (169) hide show
  1. package/build/components/conversation/message_form.d.ts +1 -2
  2. package/build/components/conversation/message_form.d.ts.map +1 -1
  3. package/build/components/conversation/message_form.js +51 -54
  4. package/build/components/conversation/message_form.js.map +1 -1
  5. package/build/components/conversation/message_list.d.ts +2 -3
  6. package/build/components/conversation/message_list.d.ts.map +1 -1
  7. package/build/components/conversation/message_list.js +66 -152
  8. package/build/components/conversation/message_list.js.map +1 -1
  9. package/build/contexts/conversation_context.d.ts +1 -3
  10. package/build/contexts/conversation_context.d.ts.map +1 -1
  11. package/build/contexts/conversation_context.js +18 -23
  12. package/build/contexts/conversation_context.js.map +1 -1
  13. package/build/hooks/index.d.ts +0 -1
  14. package/build/hooks/index.d.ts.map +1 -1
  15. package/build/hooks/index.js +0 -1
  16. package/build/hooks/index.js.map +1 -1
  17. package/build/hooks/paginator_meta.d.ts +1 -3
  18. package/build/hooks/paginator_meta.d.ts.map +1 -1
  19. package/build/hooks/paginator_meta.js +8 -25
  20. package/build/hooks/paginator_meta.js.map +1 -1
  21. package/build/hooks/use_api.d.ts.map +1 -1
  22. package/build/hooks/use_api.js +8 -5
  23. package/build/hooks/use_api.js.map +1 -1
  24. package/build/hooks/use_conversation_messages.d.ts +2 -9
  25. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  26. package/build/hooks/use_conversation_messages.js +45 -84
  27. package/build/hooks/use_conversation_messages.js.map +1 -1
  28. package/build/hooks/use_conversation_messages_jolt_events.d.ts +1 -17
  29. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  30. package/build/hooks/use_conversation_messages_jolt_events.js +80 -89
  31. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  32. package/build/hooks/use_mark_latest_message_read.d.ts +1 -2
  33. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  34. package/build/hooks/use_mark_latest_message_read.js +3 -4
  35. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  36. package/build/hooks/use_message_create_or_update.d.ts.map +1 -1
  37. package/build/hooks/use_message_create_or_update.js +80 -91
  38. package/build/hooks/use_message_create_or_update.js.map +1 -1
  39. package/build/hooks/use_message_reaction_toggle.d.ts.map +1 -1
  40. package/build/hooks/use_message_reaction_toggle.js +40 -45
  41. package/build/hooks/use_message_reaction_toggle.js.map +1 -1
  42. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  43. package/build/hooks/use_suspense_api.js +8 -5
  44. package/build/hooks/use_suspense_api.js.map +1 -1
  45. package/build/screens/conversation_new/components/services_form.js +8 -9
  46. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  47. package/build/screens/conversation_screen.d.ts +0 -1
  48. package/build/screens/conversation_screen.d.ts.map +1 -1
  49. package/build/screens/conversation_screen.js +251 -466
  50. package/build/screens/conversation_screen.js.map +1 -1
  51. package/build/screens/message_actions_screen.d.ts.map +1 -1
  52. package/build/screens/message_actions_screen.js +26 -21
  53. package/build/screens/message_actions_screen.js.map +1 -1
  54. package/build/screens/message_report_screen.d.ts.map +1 -1
  55. package/build/screens/message_report_screen.js +44 -17
  56. package/build/screens/message_report_screen.js.map +1 -1
  57. package/build/screens/reactions_screen.d.ts.map +1 -1
  58. package/build/screens/reactions_screen.js +88 -70
  59. package/build/screens/reactions_screen.js.map +1 -1
  60. package/build/types/api_primitives.d.ts +0 -2
  61. package/build/types/api_primitives.d.ts.map +1 -1
  62. package/build/types/api_primitives.js.map +1 -1
  63. package/build/types/resources/member.d.ts +0 -1
  64. package/build/types/resources/member.d.ts.map +1 -1
  65. package/build/types/resources/member.js.map +1 -1
  66. package/build/utils/cache/optimistically_update_message.d.ts +1 -2
  67. package/build/utils/cache/optimistically_update_message.d.ts.map +1 -1
  68. package/build/utils/cache/optimistically_update_message.js +4 -4
  69. package/build/utils/cache/optimistically_update_message.js.map +1 -1
  70. package/build/utils/client/types.d.ts +0 -1
  71. package/build/utils/client/types.d.ts.map +1 -1
  72. package/build/utils/client/types.js.map +1 -1
  73. package/build/utils/generate_placeholder_ulid.d.ts +6 -0
  74. package/build/utils/generate_placeholder_ulid.d.ts.map +1 -1
  75. package/build/utils/generate_placeholder_ulid.js +2 -2
  76. package/build/utils/generate_placeholder_ulid.js.map +1 -1
  77. package/build/utils/request/get_messages.d.ts +6 -18
  78. package/build/utils/request/get_messages.d.ts.map +1 -1
  79. package/build/utils/request/get_messages.js +12 -10
  80. package/build/utils/request/get_messages.js.map +1 -1
  81. package/package.json +3 -3
  82. package/src/__tests__/hooks/paginator_meta.test.ts +2 -73
  83. package/src/components/conversation/__tests__/message_list.test.tsx +0 -42
  84. package/src/components/conversation/message_form.tsx +0 -3
  85. package/src/components/conversation/message_list.tsx +4 -58
  86. package/src/contexts/conversation_context.tsx +1 -6
  87. package/src/hooks/index.ts +0 -1
  88. package/src/hooks/paginator_meta.ts +5 -29
  89. package/src/hooks/use_api.ts +5 -4
  90. package/src/hooks/use_conversation_messages.ts +11 -52
  91. package/src/hooks/use_conversation_messages_jolt_events.ts +43 -62
  92. package/src/hooks/use_mark_latest_message_read.ts +3 -4
  93. package/src/hooks/use_message_create_or_update.ts +8 -8
  94. package/src/hooks/use_message_reaction_toggle.ts +1 -3
  95. package/src/hooks/use_suspense_api.ts +5 -4
  96. package/src/screens/conversation_new/components/services_form.tsx +5 -5
  97. package/src/screens/conversation_screen.tsx +16 -119
  98. package/src/screens/message_actions_screen.tsx +5 -3
  99. package/src/screens/message_report_screen.tsx +3 -2
  100. package/src/screens/reactions_screen.tsx +4 -2
  101. package/src/types/api_primitives.ts +0 -2
  102. package/src/types/resources/member.ts +0 -1
  103. package/src/utils/cache/optimistically_update_message.ts +5 -2
  104. package/src/utils/client/types.ts +0 -1
  105. package/src/utils/generate_placeholder_ulid.ts +2 -2
  106. package/src/utils/request/get_messages.ts +14 -12
  107. package/build/components/conversation/anchor_not_found_boundary.d.ts +0 -18
  108. package/build/components/conversation/anchor_not_found_boundary.d.ts.map +0 -1
  109. package/build/components/conversation/anchor_not_found_boundary.js +0 -20
  110. package/build/components/conversation/anchor_not_found_boundary.js.map +0 -1
  111. package/build/hooks/use_conversation_message_lookup.d.ts +0 -7
  112. package/build/hooks/use_conversation_message_lookup.d.ts.map +0 -1
  113. package/build/hooks/use_conversation_message_lookup.js +0 -52
  114. package/build/hooks/use_conversation_message_lookup.js.map +0 -1
  115. package/build/hooks/use_direct_message_eligibility.d.ts +0 -14
  116. package/build/hooks/use_direct_message_eligibility.d.ts.map +0 -1
  117. package/build/hooks/use_direct_message_eligibility.js +0 -87
  118. package/build/hooks/use_direct_message_eligibility.js.map +0 -1
  119. package/build/hooks/use_fetch_newer_messages.d.ts +0 -8
  120. package/build/hooks/use_fetch_newer_messages.d.ts.map +0 -1
  121. package/build/hooks/use_fetch_newer_messages.js +0 -62
  122. package/build/hooks/use_fetch_newer_messages.js.map +0 -1
  123. package/build/hooks/use_fetch_newer_on_foreground.d.ts +0 -8
  124. package/build/hooks/use_fetch_newer_on_foreground.d.ts.map +0 -1
  125. package/build/hooks/use_fetch_newer_on_foreground.js +0 -42
  126. package/build/hooks/use_fetch_newer_on_foreground.js.map +0 -1
  127. package/build/hooks/use_held_back_messages.d.ts +0 -11
  128. package/build/hooks/use_held_back_messages.d.ts.map +0 -1
  129. package/build/hooks/use_held_back_messages.js +0 -24
  130. package/build/hooks/use_held_back_messages.js.map +0 -1
  131. package/build/utils/cache/find_message_in_caches.d.ts +0 -4
  132. package/build/utils/cache/find_message_in_caches.d.ts.map +0 -1
  133. package/build/utils/cache/find_message_in_caches.js +0 -16
  134. package/build/utils/cache/find_message_in_caches.js.map +0 -1
  135. package/build/utils/cache/prepend_newer_page.d.ts +0 -7
  136. package/build/utils/cache/prepend_newer_page.d.ts.map +0 -1
  137. package/build/utils/cache/prepend_newer_page.js +0 -15
  138. package/build/utils/cache/prepend_newer_page.js.map +0 -1
  139. package/build/utils/gated_message_cache.d.ts +0 -7
  140. package/build/utils/gated_message_cache.d.ts.map +0 -1
  141. package/build/utils/gated_message_cache.js +0 -13
  142. package/build/utils/gated_message_cache.js.map +0 -1
  143. package/build/utils/ulid.d.ts +0 -3
  144. package/build/utils/ulid.d.ts.map +0 -1
  145. package/build/utils/ulid.js +0 -7
  146. package/build/utils/ulid.js.map +0 -1
  147. package/src/__tests__/hooks/use_conversation_messages.test.ts +0 -22
  148. package/src/__tests__/hooks/use_conversation_messages_jolt_events.test.ts +0 -33
  149. package/src/__tests__/hooks/use_direct_message_eligibility.test.tsx +0 -83
  150. package/src/__tests__/screens/conversation_new/components/services_form.test.tsx +0 -91
  151. package/src/__tests__/utils/gated_message_cache.test.ts +0 -26
  152. package/src/__tests__/utils/request/get_messages.test.ts +0 -24
  153. package/src/__tests__/utils/ulid.test.ts +0 -15
  154. package/src/components/conversation/__tests__/anchor_not_found_boundary.test.tsx +0 -51
  155. package/src/components/conversation/anchor_not_found_boundary.tsx +0 -21
  156. package/src/hooks/__tests__/use_fetch_newer_messages.test.tsx +0 -68
  157. package/src/hooks/__tests__/use_held_back_messages.test.tsx +0 -60
  158. package/src/hooks/__tests__/use_message_reaction_toggle.test.tsx +0 -73
  159. package/src/hooks/use_conversation_message_lookup.ts +0 -29
  160. package/src/hooks/use_direct_message_eligibility.ts +0 -40
  161. package/src/hooks/use_fetch_newer_messages.ts +0 -44
  162. package/src/hooks/use_fetch_newer_on_foreground.ts +0 -25
  163. package/src/hooks/use_held_back_messages.ts +0 -33
  164. package/src/utils/cache/__tests__/find_message_in_caches.test.ts +0 -37
  165. package/src/utils/cache/__tests__/prepend_newer_page.test.ts +0 -34
  166. package/src/utils/cache/find_message_in_caches.ts +0 -20
  167. package/src/utils/cache/prepend_newer_page.ts +0 -19
  168. package/src/utils/gated_message_cache.ts +0 -19
  169. package/src/utils/ulid.ts +0 -11
@@ -12,69 +12,28 @@ import {
12
12
  updateCacheWithIndividualMessage,
13
13
  updateCacheWithReaction,
14
14
  updateCacheReplyRoots,
15
+ getThreadedMessagesQueryKey,
15
16
  } from '../utils/cache/messages_cache'
16
17
  import { transformMessageEventDataToMessageResource } from '../utils/jolt/transform_message_event_data_to_message_resource'
17
18
  import { completeMessageCreationTracking } from '../utils/performance_tracking'
18
19
  import { getMessageQueryKey } from '../utils/request/get_message'
19
- import { getMessagesQueryKey } from '../utils/request/get_messages'
20
+ import { getMessagesRequestArgs } from '../utils/request/get_messages'
20
21
  import { useApiClient } from './use_api_client'
21
22
  import { useCurrentPerson } from './use_current_person'
22
23
  import { useJoltChannel, useJoltEvent } from './use_jolt'
24
+ import { getRequestQueryKey } from './use_suspense_api'
23
25
  import { TYPING_TIMEOUT_INTERVAL, useTypingStatusCache } from './use_typing_status_cache'
24
26
 
25
- export type MessagesJoltEvent =
26
- | 'message.created'
27
- | 'message.updated'
28
- | 'message.destroyed'
29
- | 'reaction'
30
-
31
- export interface MessagesCache {
32
- queryKey: unknown[]
33
- canUpdate?: (event: MessagesJoltEvent) => boolean
34
- }
35
-
36
- export interface MessagesView {
37
- replyRootId: string | null
38
- cache: MessagesCache
39
- }
40
-
41
- type MessageEventData = { sort_key: string; reply_root_id?: string | null }
42
-
43
27
  interface Props {
44
28
  conversationId: number
45
- replyRootId?: string | null
46
- messageCache?: MessagesCache
47
29
  }
48
30
 
49
- const belongsToView = (replyRootId: string | null, data: MessageEventData) =>
50
- replyRootId === null || data.reply_root_id === replyRootId || data.sort_key === replyRootId
51
-
52
- export const queryKeysForEvent = (
53
- event: MessagesJoltEvent,
54
- view: MessagesView,
55
- data: MessageEventData
56
- ) => {
57
- const accepted = !view.cache.canUpdate || view.cache.canUpdate(event)
58
- return belongsToView(view.replyRootId, data) && accepted ? [view.cache.queryKey] : []
59
- }
60
-
61
- export function useConversationMessagesJoltEvents({
62
- conversationId,
63
- replyRootId = null,
64
- messageCache,
65
- }: Props) {
31
+ export function useConversationMessagesJoltEvents({ conversationId }: Props) {
66
32
  const queryClient = useQueryClient()
67
33
  const currentPerson = useCurrentPerson()
68
34
  const joltChannel = useJoltChannel(`chat.conversations.${conversationId}`)
69
- const view: MessagesView = {
70
- replyRootId,
71
- cache: messageCache ?? {
72
- queryKey: getMessagesQueryKey({
73
- conversation_id: conversationId,
74
- reply_root_id: replyRootId,
75
- }),
76
- },
77
- }
35
+ const messagesRequestArgs = getMessagesRequestArgs({ conversation_id: conversationId })
36
+ const messagesQueryKey = getRequestQueryKey(messagesRequestArgs)
78
37
  const apiClient = useApiClient()
79
38
 
80
39
  const { addTypingEvent, removeTypingEventById, removeAllTypingEventsByAuthorId } =
@@ -95,12 +54,21 @@ export function useConversationMessagesJoltEvents({
95
54
  }
96
55
  }
97
56
 
98
- const targetQueryKeys = queryKeysForEvent(e.event, view, data)
99
- targetQueryKeys.forEach(queryKey =>
100
- updateCacheWithMessage(queryClient, queryKey, message, e.event)
101
- )
102
- if (isReplyRootUpdate) {
103
- targetQueryKeys.forEach(queryKey => updateCacheReplyRoots(queryClient, queryKey, message))
57
+ // Update the main conversation cache
58
+ updateCacheWithMessage(queryClient, messagesQueryKey, message, e.event)
59
+
60
+ // If message has a reply_root_id, also update the threaded cache
61
+ if (data.reply_root_id) {
62
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(
63
+ conversationId,
64
+ data.reply_root_id
65
+ )
66
+ updateCacheWithMessage(queryClient, threadedMessagesQueryKey, message, e.event)
67
+
68
+ if (isReplyRootUpdate) {
69
+ updateCacheReplyRoots(queryClient, messagesQueryKey, message)
70
+ updateCacheReplyRoots(queryClient, threadedMessagesQueryKey, message)
71
+ }
104
72
  }
105
73
 
106
74
  // Update individual message query cache so reply shadow messages update immediately
@@ -120,21 +88,34 @@ export function useConversationMessagesJoltEvents({
120
88
  currentPersonId: currentPerson.id,
121
89
  })
122
90
 
123
- queryKeysForEvent('message.destroyed', view, data).forEach(queryKey =>
124
- queryClient.setQueryData<QueryData>(queryKey, prev =>
91
+ // Update the main conversation cache
92
+ queryClient.setQueryData<QueryData>(messagesQueryKey, prev =>
93
+ deleteRecordInPagesData({ data: prev, record: message })
94
+ )
95
+
96
+ // If message has a reply_root_id, also update the threaded cache
97
+ if (data.reply_root_id) {
98
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(
99
+ conversationId,
100
+ data.reply_root_id
101
+ )
102
+ queryClient.setQueryData<QueryData>(threadedMessagesQueryKey, prev =>
125
103
  deleteRecordInPagesData({ data: prev, record: message })
126
104
  )
127
- )
105
+ }
128
106
  }
129
107
 
130
108
  const handleReactionJoltEvent = async (e: JoltReactionEvent) => {
131
- const data = {
132
- sort_key: e.data.data.message_sort_key,
133
- reply_root_id: e.data.data.reply_root_id,
109
+ // Update the main conversation cache and capture the reply_root_id if present
110
+ updateCacheWithReaction(queryClient, messagesQueryKey, e, currentPerson.id)
111
+
112
+ const replyRootId = e.data.data.reply_root_id
113
+
114
+ // If the message has a reply_root_id, also update the threaded cache
115
+ if (replyRootId) {
116
+ const threadedMessagesQueryKey = getThreadedMessagesQueryKey(conversationId, replyRootId)
117
+ updateCacheWithReaction(queryClient, threadedMessagesQueryKey, e, currentPerson.id)
134
118
  }
135
- queryKeysForEvent('reaction', view, data).forEach(queryKey =>
136
- updateCacheWithReaction(queryClient, queryKey, e, currentPerson.id)
137
- )
138
119
  }
139
120
 
140
121
  const handleTypingEvent = async (e: JoltTypingEvent) => {
@@ -7,10 +7,9 @@ import { useConversationsMarkRead } from './use_conversations_actions'
7
7
  interface Props {
8
8
  conversation: ConversationResource
9
9
  messages: MessageResource[]
10
- enabled?: boolean
11
10
  }
12
11
 
13
- export function useMarkLatestMessageRead({ conversation, enabled = true }: Props) {
12
+ export function useMarkLatestMessageRead({ conversation }: Props) {
14
13
  const firedOnce = useRef<boolean>(false)
15
14
  const { markRead } = useConversationsMarkRead({ conversation })
16
15
  const debouncedMarkRead = useMemo(
@@ -25,10 +24,10 @@ export function useMarkLatestMessageRead({ conversation, enabled = true }: Props
25
24
  const isActive = appState === 'active'
26
25
 
27
26
  useEffect(() => {
28
- if (!enabled || !isActive || !shouldMarkRead) return
27
+ if (!isActive || !shouldMarkRead) return
29
28
 
30
29
  firedOnce.current = true
31
30
 
32
31
  debouncedMarkRead(true)
33
- }, [debouncedMarkRead, enabled, isActive, shouldMarkRead, unreadReaction])
32
+ }, [debouncedMarkRead, isActive, shouldMarkRead, unreadReaction])
34
33
  }
@@ -1,6 +1,5 @@
1
1
  import { InfiniteData, useMutation } from '@tanstack/react-query'
2
2
  import { chatQueryClient } from '../contexts/api_provider'
3
- import { useConversationContext } from '../contexts/conversation_context'
4
3
  import { ApiCollection, ApiResource, MessageResource } from '../types'
5
4
  import { DenormalizedAttachmentResourceForCreate } from '../types/resources/denormalized_attachment_resource_for_create'
6
5
  import {
@@ -36,12 +35,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
36
35
  const isEditing = !isNewMessage(message)
37
36
  const apiClient = useApiClient()
38
37
  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
45
38
 
46
39
  const mutation = useMutation({
47
40
  mutationFn: ({ text, attachments, idempotentKey }: ResolvedMessageMutationVariables) => {
@@ -86,7 +79,6 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
86
79
  message,
87
80
  text,
88
81
  replyRootId,
89
- queryKey,
90
82
  })
91
83
 
92
84
  return { message: optimisticMessage }
@@ -110,6 +102,10 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
110
102
 
111
103
  // Add error to the optimistic message from the cache on error
112
104
  if (optimisticMessage) {
105
+ const queryKey = getMessagesQueryKey({
106
+ conversation_id: conversationId,
107
+ reply_root_id: replyRootId,
108
+ })
113
109
  chatQueryClient.setQueryData(
114
110
  queryKey,
115
111
  (data: InfiniteData<ApiCollection<MessageResource>> | undefined) =>
@@ -129,6 +125,10 @@ export function useMessageCreateOrUpdate({ conversationId, message, replyRootId
129
125
  const { message: optimisticMessage } = context || {}
130
126
  const updatedMessage = result.data
131
127
  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,7 +1,6 @@
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'
5
4
  import { ApiCollection, ApiResource, MessageResource } from '../types'
6
5
  import { ReactionCountResource } from '../types/resources/reaction'
7
6
  import { updateRecordInPagesData, REACTION_EMOJIS } from '../utils'
@@ -31,8 +30,7 @@ export function useMessageReactionToggle({
31
30
  }: UseMessageReactionToggleProps) {
32
31
  const apiClient = useApiClient()
33
32
  const queryClient = useQueryClient()
34
- const { messagesQueryKey } = useConversationContext()
35
- const queryKey = messagesQueryKey ?? getMessagesQueryKey({ conversation_id })
33
+ const queryKey = getMessagesQueryKey({ conversation_id })
36
34
  const message_id = message.id
37
35
 
38
36
  const toggleReaction = useCallback(
@@ -10,7 +10,7 @@ import { FailedResponse } from '../types/api_primitives'
10
10
  import { Log } from '../utils'
11
11
  import { GetRequest, RequestData } from '../utils/client'
12
12
  import { throwResponseError } from '../utils/response_error'
13
- import { getNextPageParamFromMeta, mergePageWhere } from './paginator_meta'
13
+ import { getNextPageParamFromMeta } from './paginator_meta'
14
14
  import { App, useApiClient } from './use_api_client'
15
15
 
16
16
  interface SuspenseGetOptions extends GetRequest {
@@ -65,11 +65,12 @@ export const useSuspensePaginator = <T extends ResourceObject>(
65
65
  queryFn: ({ pageParam }) => {
66
66
  Log.info('useSuspenseGet', { pageParam })
67
67
 
68
- const where = mergePageWhere(args.data.where, pageParam?.where)
68
+ const pageParmWhere = pageParam?.where || {}
69
+ const argsWhere = args.data.where || {}
70
+ const where = { ...argsWhere, ...pageParmWhere }
69
71
  const app = args.app || 'chat'
70
72
  const offset = pageParam?.offset || args.data.offset
71
- const order = pageParam?.order || args.data.order
72
- const data = { ...args.data, where, offset, order }
73
+ const data = { ...args.data, where, offset }
73
74
 
74
75
  return apiClient[app]
75
76
  .get<ApiCollection<T>>({
@@ -45,7 +45,6 @@ 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<boolean>(!!initialPlanId)
49
48
  const initialState = useMemo(() => uniq(initialTeamIds) || [], [initialTeamIds]) // Uniq here because services can send duplicates in the teams_i_lead response.
50
49
  const [selectedTeamIds, setSelectedTeamIds] = useState<number[]>(initialState)
51
50
 
@@ -53,7 +52,6 @@ export const ServicesForm = ({
53
52
  useEffect(() => {
54
53
  setSelectedTeamIds(initialState)
55
54
  setSelectedPlanId(initialPlanId)
56
- setFilterByPlan(!!initialPlanId)
57
55
  }, [initialState, initialPlanId])
58
56
 
59
57
  const removeSelection = useCallback(
@@ -63,7 +61,9 @@ export const ServicesForm = ({
63
61
  [selectedTeamIds]
64
62
  )
65
63
 
66
- const activePlanId = filterByPlan ? selectedPlanId : undefined
64
+ const [filerByPlan, setFilterByPlan] = useState(false)
65
+
66
+ const activePlanId = filerByPlan ? selectedPlanId : undefined
67
67
 
68
68
  const { payload, isLoading: isLoadingPayload } = useServicesChatConversationPayload({
69
69
  teamIds: selectedTeamIds,
@@ -79,7 +79,7 @@ export const ServicesForm = ({
79
79
 
80
80
  const { members, isError: isMemberError } = useTeamMembersForNewConversation({
81
81
  teamIds: selectedTeamIds,
82
- planId: activePlanId,
82
+ planId: selectedPlanId,
83
83
  })
84
84
  const adultMembers = useMemo(() => members.filter(member => !member.child), [members])
85
85
 
@@ -118,7 +118,7 @@ export const ServicesForm = ({
118
118
  removeSelection={removeSelection}
119
119
  selectedPlanId={selectedPlanId}
120
120
  setSelectedPlanId={setSelectedPlanId}
121
- filterByPlan={filterByPlan}
121
+ filterByPlan={filerByPlan}
122
122
  setFilterByPlan={setFilterByPlan}
123
123
  members={members}
124
124
  isMemberError={isMemberError}
@@ -7,11 +7,10 @@ import {
7
7
  useTheme as useNavigationTheme,
8
8
  useRoute,
9
9
  } from '@react-navigation/native'
10
- import React, { startTransition, useCallback, useEffect, useRef, useState } from 'react'
10
+ import React, { useCallback, useEffect, useRef, useState } from 'react'
11
11
  import { FlatList, Platform, StyleSheet, useWindowDimensions, View } from 'react-native'
12
12
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
13
13
  import { Badge, Icon } from '../components'
14
- import { AnchorNotFoundBoundary } from '../components/conversation/anchor_not_found_boundary'
15
14
  import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
16
15
  import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'
17
16
  import { MessageForm } from '../components/conversation/message_form'
@@ -31,9 +30,6 @@ import { useConversation } from '../hooks/use_conversation'
31
30
  import { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events'
32
31
  import { useConversationMessages } from '../hooks/use_conversation_messages'
33
32
  import { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events'
34
- import { useFetchNewerMessages } from '../hooks/use_fetch_newer_messages'
35
- import { useFetchNewerOnForeground } from '../hooks/use_fetch_newer_on_foreground'
36
- import { useHeldBackMessages } from '../hooks/use_held_back_messages'
37
33
  import { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read'
38
34
  import {
39
35
  analyticsEvents,
@@ -45,9 +41,6 @@ import { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt
45
41
  import { ConversationResource } from '../types/resources/conversation'
46
42
  import { ConversationBadgeResource } from '../types/resources/conversation_badge'
47
43
  import { MessageResource } from '../types/resources/message'
48
- import { gatedMessageCache } from '../utils/gated_message_cache'
49
- import { getMessagesQueryKey } from '../utils/request/get_messages'
50
- import { decodeUlidTime } from '../utils/ulid'
51
44
 
52
45
  export type ConversationRouteProps = {
53
46
  conversation_id: number
@@ -56,7 +49,6 @@ export type ConversationRouteProps = {
56
49
  chat_group_graph_id?: string
57
50
  clear_input?: boolean
58
51
  editing_message_id?: number | null
59
- initial_message_id?: string | null
60
52
  title?: string
61
53
  subtitle?: string
62
54
  badge?: ConversationBadgeResource
@@ -67,16 +59,9 @@ export type ConversationRouteProps = {
67
59
  export type ConversationScreenProps = StaticScreenProps<ConversationRouteProps>
68
60
 
69
61
  export function ConversationScreen({ route }: ConversationScreenProps) {
70
- const { conversation_id, reply_root_id, initial_message_id } = route.params
62
+ const { conversation_id, reply_root_id } = route.params
71
63
 
72
64
  const { data: conversation } = useConversation({ conversation_id })
73
- const [anchor, setAnchor] = useState(() =>
74
- isBeforeLatestMessage(initial_message_id, conversation?.lastMessageCreatedAt)
75
- ? initial_message_id
76
- : null
77
- )
78
- const exitAnchoredMode = useCallback(() => startTransition(() => setAnchor(null)), [])
79
- const dropAnchor = useCallback(() => setAnchor(null), [])
80
65
 
81
66
  usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, {
82
67
  reply_root_id,
@@ -87,78 +72,27 @@ export function ConversationScreen({ route }: ConversationScreenProps) {
87
72
  <ConversationContextProvider
88
73
  conversationId={conversation_id}
89
74
  currentPageReplyRootId={reply_root_id ?? null}
90
- messagesQueryKey={getMessagesQueryKey({ conversation_id, reply_root_id, anchor })}
91
75
  >
92
- {anchor ? (
93
- <AnchorNotFoundBoundary onAnchorNotFound={dropAnchor}>
94
- <ConversationScreenContent
95
- route={route}
96
- anchor={anchor}
97
- onExitAnchoredMode={exitAnchoredMode}
98
- />
99
- </AnchorNotFoundBoundary>
100
- ) : (
101
- <ConversationScreenContent
102
- route={route}
103
- anchor={null}
104
- onExitAnchoredMode={exitAnchoredMode}
105
- />
106
- )}
76
+ <ConversationScreenContent route={route} />
107
77
  </ConversationContextProvider>
108
78
  )
109
79
  }
110
80
 
111
- interface ConversationScreenContentProps extends ConversationScreenProps {
112
- anchor: string | null | undefined
113
- onExitAnchoredMode: () => void
114
- }
115
-
116
- function ConversationScreenContent({
117
- route,
118
- anchor,
119
- onExitAnchoredMode,
120
- }: ConversationScreenContentProps) {
81
+ function ConversationScreenContent({ route }: ConversationScreenProps) {
121
82
  const styles = useStyles()
122
83
  const navigation = useNavigation()
123
84
  const { conversation_id, editing_message_id, reply_root_id, reply_root_author_name } =
124
85
  route.params
125
86
  const { data: conversation } = useConversation(route.params)
126
- const anchored = !!anchor
127
- const {
128
- messages,
129
- fetchNextPage,
130
- hasNextPage,
131
- fetchPreviousPage,
132
- hasPreviousPage,
133
- isFetchingPreviousPage,
134
- queryKey,
135
- } = useConversationMessages({ conversation_id, reply_root_id, anchor })
136
- const behindLatest = anchored && hasPreviousPage
137
- const caughtUp = !hasPreviousPage
138
- const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)
139
- const readingHistory = showJumpToBottomButton
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,
87
+ const { messages, fetchNextPage, hasNextPage } = useConversationMessages({
88
+ conversation_id,
89
+ reply_root_id,
147
90
  })
148
91
  useConversationJoltEvents({ conversationId: conversation_id })
149
- useConversationMessagesJoltEvents({
150
- conversationId: conversation_id,
151
- replyRootId: reply_root_id ?? null,
152
- messageCache: gatedMessageCache({
153
- queryKey,
154
- acceptNewMessages: caughtUp && !readingHistory,
155
- onSkippedNewMessage,
156
- }),
157
- })
92
+ useConversationMessagesJoltEvents({ conversationId: conversation_id })
158
93
  const { markHandledByMessageForm } = useVideoModerationJoltEvents()
159
94
  useEnsureConversationsRouteExists()
160
- useMarkLatestMessageRead({ conversation, messages, enabled: !behindLatest })
161
- useFetchNewerOnForeground({ fetchNewer, newestMessageId, enabled: anchored && caughtUp })
95
+ useMarkLatestMessageRead({ conversation, messages })
162
96
  const noMessages = messages.length === 0
163
97
 
164
98
  const { repliesDisabled, memberAbility, badges, title } = conversation
@@ -173,8 +107,12 @@ function ConversationScreenContent({
173
107
  const muted = conversation.conversationMembership?.muted ?? conversation.muted
174
108
 
175
109
  const listRef = useRef<FlatList>(null)
176
- const [hasDragged, setHasDragged] = useState(false)
177
- const holdListPosition = behindLatest || readingHistory
110
+ const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)
111
+
112
+ const trackScroll = (event: any) => {
113
+ const offsetY = event.nativeEvent.contentOffset.y
114
+ setShowJumpToBottomButton(offsetY > 200)
115
+ }
178
116
 
179
117
  const { restOffset, onLayout, onContentSizeChange, onMomentumScrollEnd, onScrollEndDrag } =
180
118
  useRestAwayFromDismissEdge({
@@ -188,28 +126,6 @@ function ConversationScreenContent({
188
126
  })
189
127
  }, [restOffset])
190
128
 
191
- const exitAnchoredMode = useCallback(() => {
192
- onExitAnchoredMode()
193
- handleReturnToBottom()
194
- }, [handleReturnToBottom, onExitAnchoredMode])
195
- const jumpToLatest = useCallback(() => {
196
- setShowJumpToBottomButton(false)
197
- if (anchored) exitAnchoredMode()
198
- else handleReturnToBottom()
199
- }, [anchored, exitAnchoredMode, handleReturnToBottom])
200
-
201
- const trackScroll = (event: any) => {
202
- const offsetY = event.nativeEvent.contentOffset.y
203
- setShowJumpToBottomButton(offsetY > 200)
204
- }
205
-
206
- const loadNewerMessages = () => {
207
- if (!hasPreviousPage || isFetchingPreviousPage) return
208
-
209
- setHasDragged(false)
210
- fetchPreviousPage()
211
- }
212
-
213
129
  useEffect(() => {
214
130
  if (reply_root_id) {
215
131
  navigation.setParams({
@@ -258,7 +174,6 @@ function ConversationScreenContent({
258
174
  conversationId={conversation_id}
259
175
  messages={messages}
260
176
  replyRootId={reply_root_id}
261
- anchorMessageId={anchor}
262
177
  hasNextPage={hasNextPage}
263
178
  onEndReached={() => fetchNextPage()}
264
179
  onScroll={trackScroll}
@@ -266,18 +181,9 @@ function ConversationScreenContent({
266
181
  onContentSizeChange={onContentSizeChange}
267
182
  onScrollEndDrag={onScrollEndDrag}
268
183
  onMomentumScrollEnd={onMomentumScrollEnd}
269
- onScrollBeginDrag={anchored ? () => setHasDragged(true) : undefined}
270
- onStartReached={anchored && hasDragged ? loadNewerMessages : undefined}
271
- onStartReachedThreshold={anchored ? 0.5 : undefined}
272
- maintainVisibleContentPosition={
273
- holdListPosition ? { minIndexForVisible: 0 } : undefined
274
- }
275
184
  />
276
185
  )}
277
- <JumpToBottomButton
278
- onPress={jumpToLatest}
279
- visible={behindLatest || showJumpToBottomButton}
280
- />
186
+ <JumpToBottomButton onPress={handleReturnToBottom} visible={showJumpToBottomButton} />
281
187
  {!noMessages && <TypingIndicator />}
282
188
  {showLeaderDisabledReplyBanner && <LeaderMessagesDisabledBanner />}
283
189
  <ConversationBottomBar
@@ -287,7 +193,6 @@ function ConversationScreenContent({
287
193
  replyRootId={reply_root_id}
288
194
  currentlyEditingMessage={currentlyEditingMessage}
289
195
  onFlaggedInMessageForm={markHandledByMessageForm}
290
- onBeforeSubmit={jumpToLatest}
291
196
  />
292
197
  </KeyboardView>
293
198
  </View>
@@ -301,7 +206,6 @@ interface ConversationBottomBarProps {
301
206
  replyRootId: string | null | undefined
302
207
  currentlyEditingMessage: MessageResource | undefined
303
208
  onFlaggedInMessageForm?: (id: string) => void
304
- onBeforeSubmit?: () => void
305
209
  }
306
210
 
307
211
  function ConversationBottomBar({
@@ -311,7 +215,6 @@ function ConversationBottomBar({
311
215
  replyRootId,
312
216
  currentlyEditingMessage,
313
217
  onFlaggedInMessageForm,
314
- onBeforeSubmit,
315
218
  }: ConversationBottomBarProps) {
316
219
  const messageLink = useMessageAvailableMembersAction(conversation)
317
220
 
@@ -330,7 +233,6 @@ function ConversationBottomBar({
330
233
  replyRootId={replyRootId}
331
234
  currentlyEditingMessage={currentlyEditingMessage}
332
235
  onFlaggedInMessageForm={onFlaggedInMessageForm}
333
- onBeforeSubmit={onBeforeSubmit}
334
236
  key={
335
237
  currentlyEditingMessage
336
238
  ? `edit-message-form-${currentlyEditingMessage.id}`
@@ -345,11 +247,6 @@ function ConversationBottomBar({
345
247
  )
346
248
  }
347
249
 
348
- const isBeforeLatestMessage = (anchor?: string | null, latestMessageCreatedAt?: string) =>
349
- !!anchor &&
350
- !!latestMessageCreatedAt &&
351
- decodeUlidTime(anchor) < Date.parse(latestMessageCreatedAt)
352
-
353
250
  interface ConversationScreenTitleProps extends HeaderTitleProps {
354
251
  conversation_id: number
355
252
  badge?: ConversationBadgeResource
@@ -9,7 +9,6 @@ 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'
13
12
  import { useConversationMessages } from '../hooks/use_conversation_messages'
14
13
  import { availableFeatures, useFeatures } from '../hooks/use_features'
15
14
  import { useMessageReactionToggle } from '../hooks/use_message_reaction_toggle'
@@ -42,8 +41,11 @@ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
42
41
  isSystemMessage,
43
42
  } = route.params
44
43
 
45
- const { refetch } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
46
- const message = useConversationMessageLookup({ conversation_id, message_id })
44
+ const { messages, refetch } = useConversationMessages(
45
+ { conversation_id },
46
+ { refetchOnMount: false }
47
+ )
48
+ const message = messages.find(m => m.id === message_id)
47
49
 
48
50
  if (!message) return null
49
51
 
@@ -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 { useConversationMessageLookup } from '../hooks/use_conversation_message_lookup'
17
+ import { useConversationMessages } from '../hooks/use_conversation_messages'
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,7 +51,8 @@ export type MessageReportScreenProps = StaticScreenProps<{
51
51
  export function MessageReportScreen({ route }: MessageReportScreenProps) {
52
52
  const { conversation_id, message_id } = route.params
53
53
 
54
- const message = useConversationMessageLookup({ conversation_id, message_id })
54
+ const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
55
+ const message = messages.find(m => m.id === message_id)
55
56
 
56
57
  if (!message) return null
57
58
 
@@ -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 { useConversationMessageLookup } from '../hooks/use_conversation_message_lookup'
10
+ import { useConversationMessages } from '../hooks/use_conversation_messages'
11
11
  import { useFontScale } from '../hooks/use_font_scale'
12
12
  import { MemberResource } from '../types'
13
13
  import { ReactionCountResource } from '../types/resources/reaction'
@@ -31,7 +31,9 @@ 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 message = useConversationMessageLookup({ conversation_id, message_id })
34
+ const { messages } = useConversationMessages({ conversation_id }, { refetchOnMount: false })
35
+
36
+ const message = messages.find(m => m.id === message_id)
35
37
  const reactionCounts = message?.reactionCounts || []
36
38
  const initialReactionCount =
37
39
  reactionCounts.find(r => r.value === reaction_value) || reactionCounts[0]
@@ -33,14 +33,12 @@ export interface NextPageCursor {
33
33
  idLte?: string
34
34
  idGt?: string
35
35
  idGte?: string
36
- order?: 'asc' | 'desc'
37
36
  }
38
37
 
39
38
  export interface CollectionMeta {
40
39
  count: number
41
40
  totalCount: number
42
41
  next?: NextPageCursor
43
- prev?: NextPageCursor
44
42
  parent?: ResourceObject
45
43
  [attributeName: string]: unknown
46
44
  }
@@ -6,7 +6,6 @@ export interface MemberResource {
6
6
  badges: MemberBadge[]
7
7
  child: boolean
8
8
  directMessagesDisabled?: boolean
9
- canDirectMessage?: boolean
10
9
  gender: string | null
11
10
  role?: string
12
11
  }