@planningcenter/chat-react-native 4.2.0 → 4.2.1-qa-staging.1

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 (123) 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_form.d.ts +2 -1
  6. package/build/components/conversation/message_form.d.ts.map +1 -1
  7. package/build/components/conversation/message_form.js +54 -51
  8. package/build/components/conversation/message_form.js.map +1 -1
  9. package/build/components/conversation/message_list.d.ts +3 -2
  10. package/build/components/conversation/message_list.d.ts.map +1 -1
  11. package/build/components/conversation/message_list.js +152 -66
  12. package/build/components/conversation/message_list.js.map +1 -1
  13. package/build/hooks/index.d.ts +1 -0
  14. package/build/hooks/index.d.ts.map +1 -1
  15. package/build/hooks/index.js +1 -0
  16. package/build/hooks/index.js.map +1 -1
  17. package/build/hooks/paginator_meta.d.ts +3 -1
  18. package/build/hooks/paginator_meta.d.ts.map +1 -1
  19. package/build/hooks/paginator_meta.js +25 -8
  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 +5 -8
  23. package/build/hooks/use_api.js.map +1 -1
  24. package/build/hooks/use_conversation_messages.d.ts +8 -2
  25. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  26. package/build/hooks/use_conversation_messages.js +77 -45
  27. package/build/hooks/use_conversation_messages.js.map +1 -1
  28. package/build/hooks/use_conversation_messages_jolt_events.d.ts +9 -1
  29. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  30. package/build/hooks/use_conversation_messages_jolt_events.js +88 -73
  31. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  32. package/build/hooks/use_direct_message_eligibility.d.ts +14 -0
  33. package/build/hooks/use_direct_message_eligibility.d.ts.map +1 -0
  34. package/build/hooks/use_direct_message_eligibility.js +87 -0
  35. package/build/hooks/use_direct_message_eligibility.js.map +1 -0
  36. package/build/hooks/use_fetch_newer_messages.d.ts +8 -0
  37. package/build/hooks/use_fetch_newer_messages.d.ts.map +1 -0
  38. package/build/hooks/use_fetch_newer_messages.js +56 -0
  39. package/build/hooks/use_fetch_newer_messages.js.map +1 -0
  40. package/build/hooks/use_fetch_newer_on_foreground.d.ts +8 -0
  41. package/build/hooks/use_fetch_newer_on_foreground.d.ts.map +1 -0
  42. package/build/hooks/use_fetch_newer_on_foreground.js +41 -0
  43. package/build/hooks/use_fetch_newer_on_foreground.js.map +1 -0
  44. package/build/hooks/use_mark_latest_message_read.d.ts +2 -1
  45. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  46. package/build/hooks/use_mark_latest_message_read.js +4 -3
  47. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  48. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  49. package/build/hooks/use_suspense_api.js +5 -8
  50. package/build/hooks/use_suspense_api.js.map +1 -1
  51. package/build/screens/conversation_new/components/services_form.js +9 -8
  52. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  53. package/build/screens/conversation_screen.d.ts +1 -0
  54. package/build/screens/conversation_screen.d.ts.map +1 -1
  55. package/build/screens/conversation_screen.js +241 -355
  56. package/build/screens/conversation_screen.js.map +1 -1
  57. package/build/types/api_primitives.d.ts +2 -0
  58. package/build/types/api_primitives.d.ts.map +1 -1
  59. package/build/types/api_primitives.js.map +1 -1
  60. package/build/types/resources/member.d.ts +1 -0
  61. package/build/types/resources/member.d.ts.map +1 -1
  62. package/build/types/resources/member.js.map +1 -1
  63. package/build/utils/cache/prepend_newer_page.d.ts +7 -0
  64. package/build/utils/cache/prepend_newer_page.d.ts.map +1 -0
  65. package/build/utils/cache/prepend_newer_page.js +14 -0
  66. package/build/utils/cache/prepend_newer_page.js.map +1 -0
  67. package/build/utils/client/types.d.ts +1 -0
  68. package/build/utils/client/types.d.ts.map +1 -1
  69. package/build/utils/client/types.js.map +1 -1
  70. package/build/utils/gated_message_cache.d.ts +7 -0
  71. package/build/utils/gated_message_cache.d.ts.map +1 -0
  72. package/build/utils/gated_message_cache.js +13 -0
  73. package/build/utils/gated_message_cache.js.map +1 -0
  74. package/build/utils/generate_placeholder_ulid.d.ts +0 -6
  75. package/build/utils/generate_placeholder_ulid.d.ts.map +1 -1
  76. package/build/utils/generate_placeholder_ulid.js +2 -2
  77. package/build/utils/generate_placeholder_ulid.js.map +1 -1
  78. package/build/utils/group_messages.js +4 -1
  79. package/build/utils/group_messages.js.map +1 -1
  80. package/build/utils/request/get_messages.d.ts +18 -6
  81. package/build/utils/request/get_messages.d.ts.map +1 -1
  82. package/build/utils/request/get_messages.js +10 -12
  83. package/build/utils/request/get_messages.js.map +1 -1
  84. package/build/utils/ulid.d.ts +3 -0
  85. package/build/utils/ulid.d.ts.map +1 -0
  86. package/build/utils/ulid.js +7 -0
  87. package/build/utils/ulid.js.map +1 -0
  88. package/package.json +3 -3
  89. package/src/__tests__/hooks/paginator_meta.test.ts +73 -2
  90. package/src/__tests__/hooks/use_conversation_messages_jolt_events.test.ts +36 -0
  91. package/src/__tests__/hooks/use_direct_message_eligibility.test.tsx +83 -0
  92. package/src/__tests__/screens/conversation_new/components/services_form.test.tsx +91 -0
  93. package/src/__tests__/utils/gated_message_cache.test.ts +26 -0
  94. package/src/__tests__/utils/request/get_messages.test.ts +24 -0
  95. package/src/__tests__/utils/ulid.test.ts +15 -0
  96. package/src/components/conversation/__tests__/anchor_not_found_boundary.test.tsx +51 -0
  97. package/src/components/conversation/__tests__/message_list.test.tsx +42 -0
  98. package/src/components/conversation/anchor_not_found_boundary.tsx +21 -0
  99. package/src/components/conversation/message_form.tsx +4 -0
  100. package/src/components/conversation/message_list.tsx +58 -4
  101. package/src/hooks/index.ts +1 -0
  102. package/src/hooks/paginator_meta.ts +29 -5
  103. package/src/hooks/use_api.ts +4 -5
  104. package/src/hooks/use_conversation_messages.ts +43 -11
  105. package/src/hooks/use_conversation_messages_jolt_events.ts +57 -40
  106. package/src/hooks/use_direct_message_eligibility.ts +40 -0
  107. package/src/hooks/use_fetch_newer_messages.ts +37 -0
  108. package/src/hooks/use_fetch_newer_on_foreground.ts +25 -0
  109. package/src/hooks/use_mark_latest_message_read.ts +4 -3
  110. package/src/hooks/use_suspense_api.ts +4 -5
  111. package/src/screens/conversation_new/components/services_form.tsx +5 -5
  112. package/src/screens/conversation_screen.tsx +120 -17
  113. package/src/types/api_primitives.ts +2 -0
  114. package/src/types/resources/member.ts +1 -0
  115. package/src/utils/__tests__/group_messages.test.ts +29 -0
  116. package/src/utils/cache/__tests__/prepend_newer_page.test.ts +35 -0
  117. package/src/utils/cache/prepend_newer_page.ts +22 -0
  118. package/src/utils/client/types.ts +1 -0
  119. package/src/utils/gated_message_cache.ts +19 -0
  120. package/src/utils/generate_placeholder_ulid.ts +2 -2
  121. package/src/utils/group_messages.ts +4 -1
  122. package/src/utils/request/get_messages.ts +12 -14
  123. package/src/utils/ulid.ts +11 -0
@@ -1,10 +1,11 @@
1
1
  import { c as _c } from "react/compiler-runtime";
2
2
  import { HeaderTitle, PlatformPressable } from '@react-navigation/elements';
3
3
  import { CommonActions, useNavigation, useTheme as useNavigationTheme, useRoute } from '@react-navigation/native';
4
- import React, { useCallback, useEffect, useRef, useState } from 'react';
4
+ import React, { startTransition, useCallback, useEffect, useRef, useState } from 'react';
5
5
  import { Platform, StyleSheet, useWindowDimensions, View } from 'react-native';
6
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
7
7
  import { Badge, Icon } from '../components';
8
+ import { AnchorNotFoundBoundary } from '../components/conversation/anchor_not_found_boundary';
8
9
  import { ConversationStartBanner } from '../components/conversation/conversation_start_banner';
9
10
  import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button';
10
11
  import { MessageForm } from '../components/conversation/message_form';
@@ -20,19 +21,24 @@ import { useConversation } from '../hooks/use_conversation';
20
21
  import { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events';
21
22
  import { useConversationMessages } from '../hooks/use_conversation_messages';
22
23
  import { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events';
24
+ import { useFetchNewerMessages } from '../hooks/use_fetch_newer_messages';
25
+ import { useFetchNewerOnForeground } from '../hooks/use_fetch_newer_on_foreground';
23
26
  import { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read';
24
27
  import { analyticsEvents, normalizeAnalyticsMetadata, usePublishProductAnalyticsEvent } from '../hooks/use_product_analytics';
25
28
  import { useRestAwayFromDismissEdge } from '../hooks/use_rest_away_from_dismiss_edge';
26
29
  import { useVideoModerationJoltEvents } from '../hooks/use_video_moderation_jolt_events';
30
+ import { gatedMessageCache } from '../utils/gated_message_cache';
31
+ import { decodeUlidTime } from '../utils/ulid';
27
32
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
28
33
  export function ConversationScreen(t0) {
29
- const $ = _c(13);
34
+ const $ = _c(19);
30
35
  const {
31
36
  route
32
37
  } = t0;
33
38
  const {
34
39
  conversation_id,
35
- reply_root_id
40
+ reply_root_id,
41
+ initial_message_id
36
42
  } = route.params;
37
43
  let t1;
38
44
  if ($[0] !== conversation_id) {
@@ -48,58 +54,94 @@ export function ConversationScreen(t0) {
48
54
  data: conversation
49
55
  } = useConversation(t1);
50
56
  let t2;
51
- if ($[2] !== conversation) {
52
- t2 = normalizeAnalyticsMetadata(conversation);
53
- $[2] = conversation;
54
- $[3] = t2;
57
+ if ($[2] !== conversation?.lastMessageCreatedAt || $[3] !== initial_message_id) {
58
+ t2 = () => isBeforeLatestMessage(initial_message_id, conversation?.lastMessageCreatedAt) ? initial_message_id : null;
59
+ $[2] = conversation?.lastMessageCreatedAt;
60
+ $[3] = initial_message_id;
61
+ $[4] = t2;
55
62
  } else {
56
- t2 = $[3];
63
+ t2 = $[4];
57
64
  }
65
+ const [anchor, setAnchor] = useState(t2);
58
66
  let t3;
59
- if ($[4] !== reply_root_id || $[5] !== t2) {
60
- t3 = {
61
- reply_root_id,
62
- ...t2
63
- };
64
- $[4] = reply_root_id;
65
- $[5] = t2;
66
- $[6] = t3;
67
+ if ($[5] === Symbol.for("react.memo_cache_sentinel")) {
68
+ t3 = () => startTransition(() => setAnchor(null));
69
+ $[5] = t3;
70
+ } else {
71
+ t3 = $[5];
72
+ }
73
+ const exitAnchoredMode = t3;
74
+ let t4;
75
+ if ($[6] === Symbol.for("react.memo_cache_sentinel")) {
76
+ t4 = () => setAnchor(null);
77
+ $[6] = t4;
67
78
  } else {
68
- t3 = $[6];
79
+ t4 = $[6];
69
80
  }
70
- usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, t3);
71
- const t4 = reply_root_id ?? null;
81
+ const dropAnchor = t4;
72
82
  let t5;
73
- if ($[7] !== route) {
74
- t5 = /*#__PURE__*/_jsx(ConversationScreenContent, {
75
- route: route
76
- });
77
- $[7] = route;
83
+ if ($[7] !== conversation) {
84
+ t5 = normalizeAnalyticsMetadata(conversation);
85
+ $[7] = conversation;
78
86
  $[8] = t5;
79
87
  } else {
80
88
  t5 = $[8];
81
89
  }
82
90
  let t6;
83
- if ($[9] !== conversation_id || $[10] !== t4 || $[11] !== t5) {
84
- t6 = /*#__PURE__*/_jsx(ConversationContextProvider, {
91
+ if ($[9] !== reply_root_id || $[10] !== t5) {
92
+ t6 = {
93
+ reply_root_id,
94
+ ...t5
95
+ };
96
+ $[9] = reply_root_id;
97
+ $[10] = t5;
98
+ $[11] = t6;
99
+ } else {
100
+ t6 = $[11];
101
+ }
102
+ usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, t6);
103
+ const t7 = reply_root_id ?? null;
104
+ let t8;
105
+ if ($[12] !== anchor || $[13] !== route) {
106
+ t8 = anchor ? /*#__PURE__*/_jsx(AnchorNotFoundBoundary, {
107
+ onAnchorNotFound: dropAnchor,
108
+ children: /*#__PURE__*/_jsx(ConversationScreenContent, {
109
+ route: route,
110
+ anchor: anchor,
111
+ onExitAnchoredMode: exitAnchoredMode
112
+ })
113
+ }) : /*#__PURE__*/_jsx(ConversationScreenContent, {
114
+ route: route,
115
+ anchor: null,
116
+ onExitAnchoredMode: exitAnchoredMode
117
+ });
118
+ $[12] = anchor;
119
+ $[13] = route;
120
+ $[14] = t8;
121
+ } else {
122
+ t8 = $[14];
123
+ }
124
+ let t9;
125
+ if ($[15] !== conversation_id || $[16] !== t7 || $[17] !== t8) {
126
+ t9 = /*#__PURE__*/_jsx(ConversationContextProvider, {
85
127
  conversationId: conversation_id,
86
- currentPageReplyRootId: t4,
87
- children: t5
128
+ currentPageReplyRootId: t7,
129
+ children: t8
88
130
  });
89
- $[9] = conversation_id;
90
- $[10] = t4;
91
- $[11] = t5;
92
- $[12] = t6;
131
+ $[15] = conversation_id;
132
+ $[16] = t7;
133
+ $[17] = t8;
134
+ $[18] = t9;
93
135
  } else {
94
- t6 = $[12];
136
+ t9 = $[18];
95
137
  }
96
- return t6;
138
+ return t9;
97
139
  }
98
- function ConversationScreenContent(t0) {
99
- const $ = _c(80);
100
- const {
101
- route
102
- } = t0;
140
+ function ConversationScreenContent({
141
+ route,
142
+ anchor,
143
+ onExitAnchoredMode
144
+ }) {
103
145
  const styles = useStyles();
104
146
  const navigation = useNavigation();
105
147
  const {
@@ -111,62 +153,59 @@ function ConversationScreenContent(t0) {
111
153
  const {
112
154
  data: conversation
113
155
  } = useConversation(route.params);
114
- let t1;
115
- if ($[0] !== conversation_id || $[1] !== reply_root_id) {
116
- t1 = {
117
- conversation_id,
118
- reply_root_id
119
- };
120
- $[0] = conversation_id;
121
- $[1] = reply_root_id;
122
- $[2] = t1;
123
- } else {
124
- t1 = $[2];
125
- }
156
+ const anchored = !!anchor;
126
157
  const {
127
158
  messages,
128
159
  fetchNextPage,
129
- hasNextPage
130
- } = useConversationMessages(t1);
131
- let t2;
132
- if ($[3] !== conversation_id) {
133
- t2 = {
134
- conversationId: conversation_id
135
- };
136
- $[3] = conversation_id;
137
- $[4] = t2;
138
- } else {
139
- t2 = $[4];
140
- }
141
- useConversationJoltEvents(t2);
142
- let t3;
143
- if ($[5] !== conversation_id) {
144
- t3 = {
145
- conversationId: conversation_id
146
- };
147
- $[5] = conversation_id;
148
- $[6] = t3;
149
- } else {
150
- t3 = $[6];
151
- }
152
- useConversationMessagesJoltEvents(t3);
160
+ hasNextPage,
161
+ fetchPreviousPage,
162
+ hasPreviousPage,
163
+ isFetchingPreviousPage,
164
+ queryKey
165
+ } = useConversationMessages({
166
+ conversation_id,
167
+ reply_root_id,
168
+ anchor
169
+ });
170
+ const behindLatest = anchored && hasPreviousPage;
171
+ const caughtUp = !hasPreviousPage;
172
+ const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false);
173
+ const readingHistory = showJumpToBottomButton;
174
+ const skippedNewMessages = useRef(false);
175
+ const messageCaches = [gatedMessageCache({
176
+ queryKey,
177
+ acceptNewMessages: caughtUp && !readingHistory,
178
+ onSkippedNewMessage: () => {
179
+ skippedNewMessages.current = true;
180
+ }
181
+ })];
182
+ const newestMessageId = messages[0]?.id;
183
+ useConversationJoltEvents({
184
+ conversationId: conversation_id
185
+ });
186
+ useConversationMessagesJoltEvents({
187
+ conversationId: conversation_id,
188
+ messageCaches
189
+ });
153
190
  const {
154
191
  markHandledByMessageForm
155
192
  } = useVideoModerationJoltEvents();
156
193
  useEnsureConversationsRouteExists();
157
- let t4;
158
- if ($[7] !== conversation || $[8] !== messages) {
159
- t4 = {
160
- conversation,
161
- messages
162
- };
163
- $[7] = conversation;
164
- $[8] = messages;
165
- $[9] = t4;
166
- } else {
167
- t4 = $[9];
168
- }
169
- useMarkLatestMessageRead(t4);
194
+ useMarkLatestMessageRead({
195
+ conversation,
196
+ messages,
197
+ enabled: !behindLatest
198
+ });
199
+ const fetchNewer = useFetchNewerMessages({
200
+ conversation_id,
201
+ reply_root_id,
202
+ queryKey
203
+ });
204
+ useFetchNewerOnForeground({
205
+ fetchNewer,
206
+ newestMessageId,
207
+ enabled: anchored && caughtUp
208
+ });
170
209
  const noMessages = messages.length === 0;
171
210
  const {
172
211
  repliesDisabled,
@@ -176,294 +215,138 @@ function ConversationScreenContent(t0) {
176
215
  } = conversation;
177
216
  const canReply = memberAbility?.canReply;
178
217
  const showLeaderDisabledReplyBanner = canReply && repliesDisabled;
179
- let t5;
180
- if ($[10] !== editing_message_id || $[11] !== messages) {
181
- let t6;
182
- if ($[13] !== editing_message_id) {
183
- t6 = m => String(m.id) === String(editing_message_id);
184
- $[13] = editing_message_id;
185
- $[14] = t6;
186
- } else {
187
- t6 = $[14];
188
- }
189
- t5 = messages.find(t6);
190
- $[10] = editing_message_id;
191
- $[11] = messages;
192
- $[12] = t5;
193
- } else {
194
- t5 = $[12];
195
- }
196
- const currentlyEditingMessage = t5;
197
- let t6;
198
- if ($[15] !== reply_root_author_name) {
199
- t6 = reply_root_author_name?.split(" ")[0];
200
- $[15] = reply_root_author_name;
201
- $[16] = t6;
202
- } else {
203
- t6 = $[16];
204
- }
205
- const replyRootAuthorFirstName = t6;
206
- const replyHeaderTitle = replyRootAuthorFirstName ? `Reply to ${replyRootAuthorFirstName}` : "Reply";
218
+ const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id));
219
+ const replyRootAuthorFirstName = reply_root_author_name?.split(' ')[0];
220
+ const replyHeaderTitle = replyRootAuthorFirstName ? `Reply to ${replyRootAuthorFirstName}` : 'Reply';
221
+ // Prefer the membership for optimistic updates.
207
222
  const muted = conversation.conversationMembership?.muted ?? conversation.muted;
208
223
  const listRef = useRef(null);
209
- const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false);
210
- let t7;
211
- if ($[17] === Symbol.for("react.memo_cache_sentinel")) {
212
- t7 = event => {
213
- const offsetY = event.nativeEvent.contentOffset.y;
214
- setShowJumpToBottomButton(offsetY > 200);
215
- };
216
- $[17] = t7;
217
- } else {
218
- t7 = $[17];
219
- }
220
- const trackScroll = t7;
221
- let t8;
222
- if ($[18] === Symbol.for("react.memo_cache_sentinel")) {
223
- t8 = {
224
- listRef,
225
- enabled: Platform.OS === "ios"
226
- };
227
- $[18] = t8;
228
- } else {
229
- t8 = $[18];
230
- }
224
+ const [hasDragged, setHasDragged] = useState(false);
225
+ const holdListPosition = behindLatest || readingHistory;
231
226
  const {
232
227
  restOffset,
233
228
  onLayout,
234
229
  onContentSizeChange,
235
230
  onMomentumScrollEnd,
236
231
  onScrollEndDrag
237
- } = useRestAwayFromDismissEdge(t8);
238
- let t9;
239
- if ($[19] !== restOffset) {
240
- t9 = () => {
241
- listRef.current?.scrollToOffset({
242
- offset: restOffset
243
- });
244
- };
245
- $[19] = restOffset;
246
- $[20] = t9;
247
- } else {
248
- t9 = $[20];
249
- }
250
- const handleReturnToBottom = t9;
251
- let t10;
252
- if ($[21] !== badges?.[0] || $[22] !== conversation.deleted || $[23] !== muted || $[24] !== navigation || $[25] !== replyHeaderTitle || $[26] !== reply_root_id || $[27] !== title) {
253
- t10 = () => {
254
- if (reply_root_id) {
255
- navigation.setParams({
256
- title: replyHeaderTitle
257
- });
258
- } else {
259
- navigation.setParams({
260
- title,
261
- badge: badges?.[0],
262
- deleted: conversation?.deleted,
263
- muted
264
- });
265
- }
266
- };
267
- $[21] = badges?.[0];
268
- $[22] = conversation.deleted;
269
- $[23] = muted;
270
- $[24] = navigation;
271
- $[25] = replyHeaderTitle;
272
- $[26] = reply_root_id;
273
- $[27] = title;
274
- $[28] = t10;
275
- } else {
276
- t10 = $[28];
277
- }
278
- const t11 = conversation?.deleted;
279
- let t12;
280
- if ($[29] !== badges || $[30] !== muted || $[31] !== navigation || $[32] !== replyHeaderTitle || $[33] !== reply_root_id || $[34] !== t11 || $[35] !== title) {
281
- t12 = [navigation, title, badges, t11, reply_root_id, replyHeaderTitle, muted];
282
- $[29] = badges;
283
- $[30] = muted;
284
- $[31] = navigation;
285
- $[32] = replyHeaderTitle;
286
- $[33] = reply_root_id;
287
- $[34] = t11;
288
- $[35] = title;
289
- $[36] = t12;
290
- } else {
291
- t12 = $[36];
292
- }
293
- useEffect(t10, t12);
294
- if (!conversation || conversation.deleted) {
295
- let t13;
296
- if ($[37] === Symbol.for("react.memo_cache_sentinel")) {
297
- t13 = /*#__PURE__*/_jsx(BlankState.Imagery, {
298
- name: "general.outlinedTextMessage"
232
+ } = useRestAwayFromDismissEdge({
233
+ listRef,
234
+ enabled: Platform.OS === 'ios'
235
+ });
236
+ const handleReturnToBottom = useCallback(() => {
237
+ listRef.current?.scrollToOffset({
238
+ offset: restOffset
239
+ });
240
+ }, [restOffset]);
241
+ const exitAnchoredMode = useCallback(() => {
242
+ onExitAnchoredMode();
243
+ handleReturnToBottom();
244
+ }, [handleReturnToBottom, onExitAnchoredMode]);
245
+ const jumpToLatest = useCallback(() => {
246
+ setShowJumpToBottomButton(false);
247
+ if (behindLatest) exitAnchoredMode();else handleReturnToBottom();
248
+ }, [behindLatest, exitAnchoredMode, handleReturnToBottom]);
249
+ const trackScroll = event => {
250
+ const offsetY = event.nativeEvent.contentOffset.y;
251
+ setShowJumpToBottomButton(offsetY > 200);
252
+ };
253
+ const loadNewerMessages = () => {
254
+ if (!hasPreviousPage || isFetchingPreviousPage) return;
255
+ setHasDragged(false);
256
+ fetchPreviousPage();
257
+ };
258
+ useEffect(() => {
259
+ if (readingHistory || !caughtUp || !newestMessageId || !skippedNewMessages.current) return;
260
+ skippedNewMessages.current = false;
261
+ fetchNewer(newestMessageId);
262
+ }, [caughtUp, fetchNewer, newestMessageId, readingHistory]);
263
+ useEffect(() => {
264
+ if (reply_root_id) {
265
+ navigation.setParams({
266
+ title: replyHeaderTitle
299
267
  });
300
- $[37] = t13;
301
268
  } else {
302
- t13 = $[37];
303
- }
304
- let t14;
305
- if ($[38] === Symbol.for("react.memo_cache_sentinel")) {
306
- t14 = /*#__PURE__*/_jsx(BlankState.Content, {
307
- children: /*#__PURE__*/_jsx(BlankState.Heading, {
308
- children: "This conversation has been deleted"
309
- })
269
+ navigation.setParams({
270
+ title: title,
271
+ badge: badges?.[0],
272
+ deleted: conversation?.deleted,
273
+ muted
310
274
  });
311
- $[38] = t14;
312
- } else {
313
- t14 = $[38];
314
275
  }
315
- let t15;
316
- if ($[39] !== navigation.goBack) {
317
- t15 = /*#__PURE__*/_jsxs(BlankState.Root, {
318
- children: [t13, t14, /*#__PURE__*/_jsx(BlankState.Button, {
276
+ }, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle, muted]);
277
+ if (!conversation || conversation.deleted) {
278
+ return /*#__PURE__*/_jsx(View, {
279
+ style: styles.container,
280
+ children: /*#__PURE__*/_jsxs(BlankState.Root, {
281
+ children: [/*#__PURE__*/_jsx(BlankState.Imagery, {
282
+ name: "general.outlinedTextMessage"
283
+ }), /*#__PURE__*/_jsx(BlankState.Content, {
284
+ children: /*#__PURE__*/_jsx(BlankState.Heading, {
285
+ children: "This conversation has been deleted"
286
+ })
287
+ }), /*#__PURE__*/_jsx(BlankState.Button, {
319
288
  onPress: navigation.goBack,
320
289
  title: "Back to conversations",
321
290
  accessibilityHint: "Navigates back to the conversations list",
322
291
  accessibilityRole: "link"
323
292
  })]
324
- });
325
- $[39] = navigation.goBack;
326
- $[40] = t15;
327
- } else {
328
- t15 = $[40];
329
- }
330
- let t16;
331
- if ($[41] !== styles.container || $[42] !== t15) {
332
- t16 = /*#__PURE__*/_jsx(View, {
333
- style: styles.container,
334
- children: t15
335
- });
336
- $[41] = styles.container;
337
- $[42] = t15;
338
- $[43] = t16;
339
- } else {
340
- t16 = $[43];
341
- }
342
- return t16;
343
- }
344
- let t13;
345
- if ($[44] !== conversation || $[45] !== conversation_id || $[46] !== fetchNextPage || $[47] !== hasNextPage || $[48] !== messages || $[49] !== noMessages || $[50] !== onContentSizeChange || $[51] !== onLayout || $[52] !== onMomentumScrollEnd || $[53] !== onScrollEndDrag || $[54] !== reply_root_id || $[55] !== styles.emptyState) {
346
- t13 = noMessages ? /*#__PURE__*/_jsx(View, {
347
- style: styles.emptyState,
348
- children: /*#__PURE__*/_jsx(ConversationStartBanner, {
349
- conversation: conversation,
350
- hasMessages: false
351
293
  })
352
- }) : /*#__PURE__*/_jsx(MessageList, {
353
- listRef: listRef,
354
- conversation: conversation,
355
- conversationId: conversation_id,
356
- messages: messages,
357
- replyRootId: reply_root_id,
358
- hasNextPage: hasNextPage,
359
- onEndReached: () => fetchNextPage(),
360
- onScroll: trackScroll,
361
- onLayout: onLayout,
362
- onContentSizeChange: onContentSizeChange,
363
- onScrollEndDrag: onScrollEndDrag,
364
- onMomentumScrollEnd: onMomentumScrollEnd
365
- });
366
- $[44] = conversation;
367
- $[45] = conversation_id;
368
- $[46] = fetchNextPage;
369
- $[47] = hasNextPage;
370
- $[48] = messages;
371
- $[49] = noMessages;
372
- $[50] = onContentSizeChange;
373
- $[51] = onLayout;
374
- $[52] = onMomentumScrollEnd;
375
- $[53] = onScrollEndDrag;
376
- $[54] = reply_root_id;
377
- $[55] = styles.emptyState;
378
- $[56] = t13;
379
- } else {
380
- t13 = $[56];
381
- }
382
- let t14;
383
- if ($[57] !== handleReturnToBottom || $[58] !== showJumpToBottomButton) {
384
- t14 = /*#__PURE__*/_jsx(JumpToBottomButton, {
385
- onPress: handleReturnToBottom,
386
- visible: showJumpToBottomButton
387
294
  });
388
- $[57] = handleReturnToBottom;
389
- $[58] = showJumpToBottomButton;
390
- $[59] = t14;
391
- } else {
392
- t14 = $[59];
393
- }
394
- let t15;
395
- if ($[60] !== noMessages) {
396
- t15 = !noMessages && /*#__PURE__*/_jsx(TypingIndicator, {});
397
- $[60] = noMessages;
398
- $[61] = t15;
399
- } else {
400
- t15 = $[61];
401
- }
402
- let t16;
403
- if ($[62] !== showLeaderDisabledReplyBanner) {
404
- t16 = showLeaderDisabledReplyBanner && /*#__PURE__*/_jsx(LeaderMessagesDisabledBanner, {});
405
- $[62] = showLeaderDisabledReplyBanner;
406
- $[63] = t16;
407
- } else {
408
- t16 = $[63];
409
295
  }
410
- let t17;
411
- if ($[64] !== canReply || $[65] !== conversation || $[66] !== currentlyEditingMessage || $[67] !== markHandledByMessageForm || $[68] !== replyRootAuthorFirstName || $[69] !== reply_root_id) {
412
- t17 = /*#__PURE__*/_jsx(ConversationBottomBar, {
413
- conversation: conversation,
414
- canReply: canReply,
415
- replyRootAuthorFirstName: replyRootAuthorFirstName,
416
- replyRootId: reply_root_id,
417
- currentlyEditingMessage: currentlyEditingMessage,
418
- onFlaggedInMessageForm: markHandledByMessageForm
419
- });
420
- $[64] = canReply;
421
- $[65] = conversation;
422
- $[66] = currentlyEditingMessage;
423
- $[67] = markHandledByMessageForm;
424
- $[68] = replyRootAuthorFirstName;
425
- $[69] = reply_root_id;
426
- $[70] = t17;
427
- } else {
428
- t17 = $[70];
429
- }
430
- let t18;
431
- if ($[71] !== t13 || $[72] !== t14 || $[73] !== t15 || $[74] !== t16 || $[75] !== t17) {
432
- t18 = /*#__PURE__*/_jsxs(KeyboardView, {
433
- children: [t13, t14, t15, t16, t17]
434
- });
435
- $[71] = t13;
436
- $[72] = t14;
437
- $[73] = t15;
438
- $[74] = t16;
439
- $[75] = t17;
440
- $[76] = t18;
441
- } else {
442
- t18 = $[76];
443
- }
444
- let t19;
445
- if ($[77] !== styles.container || $[78] !== t18) {
446
- t19 = /*#__PURE__*/_jsx(View, {
447
- style: styles.container,
448
- children: t18
449
- });
450
- $[77] = styles.container;
451
- $[78] = t18;
452
- $[79] = t19;
453
- } else {
454
- t19 = $[79];
455
- }
456
- return t19;
296
+ return /*#__PURE__*/_jsx(View, {
297
+ style: styles.container,
298
+ children: /*#__PURE__*/_jsxs(KeyboardView, {
299
+ children: [noMessages ? /*#__PURE__*/_jsx(View, {
300
+ style: styles.emptyState,
301
+ children: /*#__PURE__*/_jsx(ConversationStartBanner, {
302
+ conversation: conversation,
303
+ hasMessages: false
304
+ })
305
+ }) : /*#__PURE__*/_jsx(MessageList, {
306
+ listRef: listRef,
307
+ conversation: conversation,
308
+ conversationId: conversation_id,
309
+ messages: messages,
310
+ replyRootId: reply_root_id,
311
+ anchorMessageId: anchor,
312
+ hasNextPage: hasNextPage,
313
+ onEndReached: () => fetchNextPage(),
314
+ onScroll: trackScroll,
315
+ onLayout: onLayout,
316
+ onContentSizeChange: onContentSizeChange,
317
+ onScrollEndDrag: onScrollEndDrag,
318
+ onMomentumScrollEnd: onMomentumScrollEnd,
319
+ onScrollBeginDrag: anchored ? () => setHasDragged(true) : undefined,
320
+ onStartReached: anchored && hasDragged ? loadNewerMessages : undefined,
321
+ onStartReachedThreshold: anchored ? 0.5 : undefined,
322
+ maintainVisibleContentPosition: holdListPosition ? {
323
+ minIndexForVisible: 0
324
+ } : undefined
325
+ }), /*#__PURE__*/_jsx(JumpToBottomButton, {
326
+ onPress: jumpToLatest,
327
+ visible: behindLatest || showJumpToBottomButton
328
+ }), !noMessages && /*#__PURE__*/_jsx(TypingIndicator, {}), showLeaderDisabledReplyBanner && /*#__PURE__*/_jsx(LeaderMessagesDisabledBanner, {}), /*#__PURE__*/_jsx(ConversationBottomBar, {
329
+ conversation: conversation,
330
+ canReply: canReply,
331
+ replyRootAuthorFirstName: replyRootAuthorFirstName,
332
+ replyRootId: reply_root_id,
333
+ currentlyEditingMessage: currentlyEditingMessage,
334
+ onFlaggedInMessageForm: markHandledByMessageForm,
335
+ onBeforeSubmit: jumpToLatest
336
+ })]
337
+ })
338
+ });
457
339
  }
458
340
  function ConversationBottomBar(t0) {
459
- const $ = _c(15);
341
+ const $ = _c(16);
460
342
  const {
461
343
  conversation,
462
344
  canReply,
463
345
  replyRootAuthorFirstName,
464
346
  replyRootId,
465
347
  currentlyEditingMessage,
466
- onFlaggedInMessageForm
348
+ onFlaggedInMessageForm,
349
+ onBeforeSubmit
467
350
  } = t0;
468
351
  const messageLink = useMessageAvailableMembersAction(conversation);
469
352
  if (conversation.disabled) {
@@ -513,27 +396,30 @@ function ConversationBottomBar(t0) {
513
396
  t5 = $[7];
514
397
  }
515
398
  let t6;
516
- if ($[8] !== conversation || $[9] !== currentlyEditingMessage || $[10] !== onFlaggedInMessageForm || $[11] !== replyRootAuthorFirstName || $[12] !== replyRootId || $[13] !== t1) {
399
+ if ($[8] !== conversation || $[9] !== currentlyEditingMessage || $[10] !== onBeforeSubmit || $[11] !== onFlaggedInMessageForm || $[12] !== replyRootAuthorFirstName || $[13] !== replyRootId || $[14] !== t1) {
517
400
  t6 = /*#__PURE__*/_jsxs(MessageForm.Root, {
518
401
  replyRootAuthorFirstName: replyRootAuthorFirstName,
519
402
  conversation: conversation,
520
403
  replyRootId: replyRootId,
521
404
  currentlyEditingMessage: currentlyEditingMessage,
522
405
  onFlaggedInMessageForm: onFlaggedInMessageForm,
406
+ onBeforeSubmit: onBeforeSubmit,
523
407
  children: [t2, t3, t4, t5]
524
408
  }, t1);
525
409
  $[8] = conversation;
526
410
  $[9] = currentlyEditingMessage;
527
- $[10] = onFlaggedInMessageForm;
528
- $[11] = replyRootAuthorFirstName;
529
- $[12] = replyRootId;
530
- $[13] = t1;
531
- $[14] = t6;
411
+ $[10] = onBeforeSubmit;
412
+ $[11] = onFlaggedInMessageForm;
413
+ $[12] = replyRootAuthorFirstName;
414
+ $[13] = replyRootId;
415
+ $[14] = t1;
416
+ $[15] = t6;
532
417
  } else {
533
- t6 = $[14];
418
+ t6 = $[15];
534
419
  }
535
420
  return t6;
536
421
  }
422
+ const isBeforeLatestMessage = (anchor, latestMessageCreatedAt) => !!anchor && !!latestMessageCreatedAt && decodeUlidTime(anchor) < Date.parse(latestMessageCreatedAt);
537
423
  export const ConversationScreenTitle = t0 => {
538
424
  const $ = _c(29);
539
425
  const {