@planningcenter/chat-react-native 3.38.0-rc.9 → 3.38.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 (149) hide show
  1. package/build/components/conversation/jump_to_bottom_button.d.ts +1 -2
  2. package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
  3. package/build/components/conversation/jump_to_bottom_button.js +7 -39
  4. package/build/components/conversation/jump_to_bottom_button.js.map +1 -1
  5. package/build/components/conversation/reply_shadow_message.d.ts +2 -1
  6. package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
  7. package/build/components/conversation/reply_shadow_message.js.map +1 -1
  8. package/build/contexts/conversation_context.d.ts +1 -8
  9. package/build/contexts/conversation_context.d.ts.map +1 -1
  10. package/build/contexts/conversation_context.js +3 -21
  11. package/build/contexts/conversation_context.js.map +1 -1
  12. package/build/hooks/use_conversation_messages.d.ts +6 -15
  13. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  14. package/build/hooks/use_conversation_messages.js +9 -62
  15. package/build/hooks/use_conversation_messages.js.map +1 -1
  16. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  17. package/build/hooks/use_conversation_messages_jolt_events.js +4 -4
  18. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  19. package/build/hooks/use_conversations_actions.d.ts +0 -5
  20. package/build/hooks/use_conversations_actions.d.ts.map +1 -1
  21. package/build/hooks/use_conversations_actions.js +0 -12
  22. package/build/hooks/use_conversations_actions.js.map +1 -1
  23. package/build/hooks/use_features.d.ts +0 -1
  24. package/build/hooks/use_features.d.ts.map +1 -1
  25. package/build/hooks/use_features.js +0 -1
  26. package/build/hooks/use_features.js.map +1 -1
  27. package/build/hooks/use_mark_latest_message_read.d.ts +1 -1
  28. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  29. package/build/hooks/use_mark_latest_message_read.js +1 -17
  30. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  31. package/build/hooks/use_suspense_api.d.ts +0 -1
  32. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  33. package/build/hooks/use_suspense_api.js +1 -1
  34. package/build/hooks/use_suspense_api.js.map +1 -1
  35. package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -1
  36. package/build/screens/conversation_filter_recipients/components/header_row.js +3 -2
  37. package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -1
  38. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -1
  39. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +47 -18
  40. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -1
  41. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +2 -1
  42. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
  43. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +23 -26
  44. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
  45. package/build/screens/conversation_filter_recipients/types.d.ts +1 -1
  46. package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -1
  47. package/build/screens/conversation_filter_recipients/types.js.map +1 -1
  48. package/build/screens/conversation_screen.d.ts +0 -1
  49. package/build/screens/conversation_screen.d.ts.map +1 -1
  50. package/build/screens/conversation_screen.js +48 -95
  51. package/build/screens/conversation_screen.js.map +1 -1
  52. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +1 -1
  53. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -1
  54. package/build/screens/conversation_select_recipients/components/recipient_link_row.js +3 -3
  55. package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -1
  56. package/build/screens/conversation_select_recipients/components/team_recipient_row.d.ts.map +1 -1
  57. package/build/screens/conversation_select_recipients/components/team_recipient_row.js +1 -1
  58. package/build/screens/conversation_select_recipients/components/team_recipient_row.js.map +1 -1
  59. package/build/utils/cache/messages_cache.d.ts +0 -1
  60. package/build/utils/cache/messages_cache.d.ts.map +1 -1
  61. package/build/utils/cache/messages_cache.js +0 -4
  62. package/build/utils/cache/messages_cache.js.map +1 -1
  63. package/build/utils/group_messages.d.ts +2 -9
  64. package/build/utils/group_messages.d.ts.map +1 -1
  65. package/build/utils/group_messages.js +1 -20
  66. package/build/utils/group_messages.js.map +1 -1
  67. package/package.json +3 -3
  68. package/src/components/conversation/jump_to_bottom_button.tsx +8 -57
  69. package/src/components/conversation/reply_shadow_message.tsx +1 -1
  70. package/src/contexts/conversation_context.tsx +2 -30
  71. package/src/hooks/use_conversation_messages.ts +20 -120
  72. package/src/hooks/use_conversation_messages_jolt_events.ts +3 -4
  73. package/src/hooks/use_conversations_actions.ts +0 -15
  74. package/src/hooks/use_features.ts +0 -1
  75. package/src/hooks/use_mark_latest_message_read.ts +2 -16
  76. package/src/hooks/use_suspense_api.ts +1 -1
  77. package/src/screens/conversation_filter_recipients/components/header_row.tsx +3 -2
  78. package/src/screens/conversation_filter_recipients/hooks/__tests__/use_service_types_with_teams.test.ts +108 -0
  79. package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +46 -19
  80. package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +31 -29
  81. package/src/screens/conversation_filter_recipients/types.tsx +1 -1
  82. package/src/screens/conversation_screen.tsx +76 -184
  83. package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +6 -4
  84. package/src/screens/conversation_select_recipients/components/team_recipient_row.tsx +2 -1
  85. package/src/utils/__tests__/group_messages.test.ts +0 -71
  86. package/src/utils/cache/messages_cache.ts +0 -5
  87. package/src/utils/group_messages.ts +2 -42
  88. package/build/components/conversation/unread_divider.d.ts +0 -6
  89. package/build/components/conversation/unread_divider.d.ts.map +0 -1
  90. package/build/components/conversation/unread_divider.js +0 -59
  91. package/build/components/conversation/unread_divider.js.map +0 -1
  92. package/build/hooks/use_flat_list_viewability.d.ts +0 -20
  93. package/build/hooks/use_flat_list_viewability.d.ts.map +0 -1
  94. package/build/hooks/use_flat_list_viewability.js +0 -30
  95. package/build/hooks/use_flat_list_viewability.js.map +0 -1
  96. package/build/hooks/use_jump_to_bottom_action.d.ts +0 -9
  97. package/build/hooks/use_jump_to_bottom_action.d.ts.map +0 -1
  98. package/build/hooks/use_jump_to_bottom_action.js +0 -62
  99. package/build/hooks/use_jump_to_bottom_action.js.map +0 -1
  100. package/build/hooks/use_jump_to_unread_anchor.d.ts +0 -20
  101. package/build/hooks/use_jump_to_unread_anchor.d.ts.map +0 -1
  102. package/build/hooks/use_jump_to_unread_anchor.js +0 -53
  103. package/build/hooks/use_jump_to_unread_anchor.js.map +0 -1
  104. package/build/hooks/use_jump_to_unread_gates.d.ts +0 -5
  105. package/build/hooks/use_jump_to_unread_gates.d.ts.map +0 -1
  106. package/build/hooks/use_jump_to_unread_gates.js +0 -10
  107. package/build/hooks/use_jump_to_unread_gates.js.map +0 -1
  108. package/build/hooks/use_scroll_tracking.d.ts +0 -13
  109. package/build/hooks/use_scroll_tracking.d.ts.map +0 -1
  110. package/build/hooks/use_scroll_tracking.js +0 -45
  111. package/build/hooks/use_scroll_tracking.js.map +0 -1
  112. package/build/hooks/use_track_highest_seen_message.d.ts +0 -4
  113. package/build/hooks/use_track_highest_seen_message.d.ts.map +0 -1
  114. package/build/hooks/use_track_highest_seen_message.js +0 -35
  115. package/build/hooks/use_track_highest_seen_message.js.map +0 -1
  116. package/build/utils/conversation_messages.d.ts +0 -10
  117. package/build/utils/conversation_messages.d.ts.map +0 -1
  118. package/build/utils/conversation_messages.js +0 -22
  119. package/build/utils/conversation_messages.js.map +0 -1
  120. package/build/utils/highest_seen_tracker.d.ts +0 -12
  121. package/build/utils/highest_seen_tracker.d.ts.map +0 -1
  122. package/build/utils/highest_seen_tracker.js +0 -37
  123. package/build/utils/highest_seen_tracker.js.map +0 -1
  124. package/build/utils/message_viewability.d.ts +0 -24
  125. package/build/utils/message_viewability.d.ts.map +0 -1
  126. package/build/utils/message_viewability.js +0 -29
  127. package/build/utils/message_viewability.js.map +0 -1
  128. package/build/utils/unread_divider_helpers.d.ts +0 -18
  129. package/build/utils/unread_divider_helpers.d.ts.map +0 -1
  130. package/build/utils/unread_divider_helpers.js +0 -13
  131. package/build/utils/unread_divider_helpers.js.map +0 -1
  132. package/src/__tests__/hooks/use_conversation_messages.test.tsx +0 -109
  133. package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +0 -154
  134. package/src/__tests__/utils/cache/messages_cache.test.ts +0 -54
  135. package/src/components/conversation/unread_divider.tsx +0 -90
  136. package/src/hooks/use_flat_list_viewability.ts +0 -50
  137. package/src/hooks/use_jump_to_bottom_action.ts +0 -75
  138. package/src/hooks/use_jump_to_unread_anchor.ts +0 -68
  139. package/src/hooks/use_jump_to_unread_gates.ts +0 -10
  140. package/src/hooks/use_scroll_tracking.ts +0 -64
  141. package/src/hooks/use_track_highest_seen_message.ts +0 -43
  142. package/src/utils/__tests__/conversation_messages.test.ts +0 -105
  143. package/src/utils/__tests__/highest_seen_tracker.test.ts +0 -82
  144. package/src/utils/__tests__/message_viewability.test.ts +0 -168
  145. package/src/utils/__tests__/unread_divider_helpers.test.ts +0 -85
  146. package/src/utils/conversation_messages.ts +0 -37
  147. package/src/utils/highest_seen_tracker.ts +0 -42
  148. package/src/utils/message_viewability.ts +0 -49
  149. package/src/utils/unread_divider_helpers.ts +0 -25
@@ -9,7 +9,8 @@ interface TeamRecipientRowProps {
9
9
 
10
10
  export const TeamRecipientRow = ({ serviceType, onPress }: TeamRecipientRowProps) => {
11
11
  const serviceTypeAccessibilityLabel = `Select ${pluralize(serviceType.teams.length, 'team')} for ${serviceType.name}`
12
- const teamNames = serviceType.teams.map(team => team.name).join(', ')
12
+ const teamNames =
13
+ serviceType.id > 0 ? serviceType.teams.map(team => team.name).join(', ') : undefined
13
14
 
14
15
  return (
15
16
  <RecipientLinkRow
@@ -124,77 +124,6 @@ describe('groupMessages — nextRendersAuthor mirrors the newer enriched neighbo
124
124
  })
125
125
  })
126
126
 
127
- describe('groupMessages — unread divider', () => {
128
- it('inserts the divider between the read and unread boundary when jumpToUnreadActive', () => {
129
- const messages = [
130
- message('04', { createdAt: '2026-01-01T00:04:00Z' }),
131
- message('03', { createdAt: '2026-01-01T00:03:00Z' }),
132
- message('02', { createdAt: '2026-01-01T00:02:00Z' }),
133
- message('01', { createdAt: '2026-01-01T00:01:00Z' }),
134
- ]
135
-
136
- const enriched = groupMessages({
137
- ms: messages,
138
- jumpToUnreadActive: true,
139
- initialMessageId: '02',
140
- })
141
-
142
- const dividerIdx = enriched.findIndex(item => 'type' in item && item.type === 'UnreadDivider')
143
- const msg03Idx = enriched.findIndex(
144
- item => 'id' in item && item.id === '03' && !('type' in item && item.type !== 'Message')
145
- )
146
- const msg02Idx = enriched.findIndex(
147
- item => 'id' in item && item.id === '02' && !('type' in item && item.type !== 'Message')
148
- )
149
-
150
- expect(dividerIdx).toBeGreaterThan(msg03Idx)
151
- expect(dividerIdx).toBeLessThan(msg02Idx)
152
- })
153
-
154
- it('does not insert the divider when jumpToUnreadActive is false', () => {
155
- const enriched = groupMessages({
156
- ms: [message('02'), message('01')],
157
- jumpToUnreadActive: false,
158
- initialMessageId: '01',
159
- })
160
-
161
- expect(enriched.some(item => 'type' in item && item.type === 'UnreadDivider')).toBe(false)
162
- })
163
-
164
- it('does not insert the divider when no message crosses the boundary', () => {
165
- const enriched = groupMessages({
166
- ms: [message('05'), message('04'), message('03')],
167
- jumpToUnreadActive: true,
168
- initialMessageId: '02',
169
- })
170
-
171
- expect(enriched.some(item => 'type' in item && item.type === 'UnreadDivider')).toBe(false)
172
- })
173
-
174
- it('orders ULID-style ids consistently with backend sort_key comparisons', () => {
175
- const enriched = groupMessages({
176
- ms: [
177
- message('01KQSTAY189PHCJBT8T13R9VMP'),
178
- message('01KQST9HZAB10K3CXR7TYN2QWE'),
179
- message('01KQST73KZRPXNRDA7TYN19KXQ'),
180
- message('01KQST5JKZRPXNRDA7TYN19ABC'),
181
- ],
182
- jumpToUnreadActive: true,
183
- initialMessageId: '01KQST73KZRPXNRDA7TYN19KXQ',
184
- })
185
-
186
- const dividerIdx = enriched.findIndex(item => 'type' in item && item.type === 'UnreadDivider')
187
- const newerIdx = enriched.findIndex(
188
- item =>
189
- 'id' in item &&
190
- item.id === '01KQST9HZAB10K3CXR7TYN2QWE' &&
191
- !('type' in item && item.type !== 'Message')
192
- )
193
-
194
- expect(dividerIdx).toBeGreaterThan(newerIdx)
195
- })
196
- })
197
-
198
127
  describe('groupMessages — system messages', () => {
199
128
  it('flags lastInGroup true and renderAuthor false on system messages', () => {
200
129
  const messages = [
@@ -131,11 +131,6 @@ export function getThreadedMessagesQueryKey(conversationId: number, replyRootId:
131
131
  return getRequestQueryKey(requestArgs)
132
132
  }
133
133
 
134
- export function hasUnloadedNewerPages(queryClient: QueryClient, queryKey: unknown[]): boolean {
135
- const data = queryClient.getQueryData<MessagesQueryData>(queryKey)
136
- return !!data?.pages?.[0]?.meta?.next?.idGt
137
- }
138
-
139
134
  export function mergeMessageUpdate(
140
135
  record: MessageResource,
141
136
  current?: MessageResource
@@ -4,12 +4,8 @@ import { isSystemMessage } from './system_messages'
4
4
 
5
5
  const FIVE_MINUTES_MS = 5 * 60 * 1000
6
6
 
7
- export const UNREAD_DIVIDER_KEY = 'unread-divider'
8
-
9
7
  export type DateSeparator = { type: 'DateSeparator'; id: string; date: string }
10
8
 
11
- export type UnreadDividerItem = { type: 'UnreadDivider'; id: typeof UNREAD_DIVIDER_KEY }
12
-
13
9
  export type ReplyShadowMessage = {
14
10
  type: 'ReplyShadowMessage'
15
11
  id: string
@@ -18,25 +14,14 @@ export type ReplyShadowMessage = {
18
14
  nextRendersAuthor: boolean
19
15
  }
20
16
 
21
- export type EnrichedMessage =
22
- | MessageResource
23
- | DateSeparator
24
- | UnreadDividerItem
25
- | ReplyShadowMessage
17
+ export type EnrichedMessage = MessageResource | DateSeparator | ReplyShadowMessage
26
18
 
27
19
  interface GroupMessagesProps {
28
20
  ms: MessageResource[]
29
21
  inReplyScreen?: boolean
30
- jumpToUnreadActive?: boolean
31
- initialMessageId?: string | null
32
22
  }
33
23
 
34
- export function groupMessages({
35
- ms,
36
- inReplyScreen,
37
- jumpToUnreadActive,
38
- initialMessageId,
39
- }: GroupMessagesProps): EnrichedMessage[] {
24
+ export function groupMessages({ ms, inReplyScreen }: GroupMessagesProps): EnrichedMessage[] {
40
25
  const items: EnrichedMessage[] = []
41
26
  let myLatestSeen = false
42
27
  let nextNeighborEnriched: MessageResource | undefined
@@ -48,9 +33,6 @@ export function groupMessages({
48
33
  if (isSystemMessage(message)) {
49
34
  const enriched = enrichSystemMessage(message, next)
50
35
  items.push(enriched)
51
- if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
52
- items.push(unreadDivider())
53
- }
54
36
  if (datesDifferBetween(message, prev)) items.push(dateSeparator(message))
55
37
  nextNeighborEnriched = enriched
56
38
  return
@@ -62,10 +44,6 @@ export function groupMessages({
62
44
  const enriched = enrichRegularMessage(message, prev, next, isMyLatest, !!inReplyScreen)
63
45
  items.push(enriched)
64
46
 
65
- if (crossesUnreadBoundary(message, prev, jumpToUnreadActive, initialMessageId)) {
66
- items.push(unreadDivider())
67
- }
68
-
69
47
  const shadow = replyShadowFor(enriched, prev)
70
48
  if (shadow) items.push(shadow)
71
49
 
@@ -79,24 +57,6 @@ export function groupMessages({
79
57
  return items
80
58
  }
81
59
 
82
- function crossesUnreadBoundary(
83
- message: MessageResource,
84
- prev: MessageResource | undefined,
85
- jumpToUnreadActive: boolean | undefined,
86
- initialMessageId: string | null | undefined
87
- ): boolean {
88
- if (!jumpToUnreadActive) return false
89
- if (!initialMessageId) return false
90
- if (!prev) return false
91
- return (
92
- prev.id.localeCompare(initialMessageId) <= 0 && message.id.localeCompare(initialMessageId) > 0
93
- )
94
- }
95
-
96
- function unreadDivider(): UnreadDividerItem {
97
- return { type: 'UnreadDivider', id: UNREAD_DIVIDER_KEY }
98
- }
99
-
100
60
  function neighborsOf<T>(arr: T[], i: number): { prev: T | undefined; next: T | undefined } {
101
61
  return { prev: arr[i + 1], next: arr[i - 1] }
102
62
  }
@@ -1,6 +0,0 @@
1
- interface UnreadDividerProps {
2
- scrolledPast?: boolean;
3
- }
4
- export declare function UnreadDivider({ scrolledPast }: UnreadDividerProps): import("react").JSX.Element | null;
5
- export {};
6
- //# sourceMappingURL=unread_divider.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unread_divider.d.ts","sourceRoot":"","sources":["../../../src/components/conversation/unread_divider.tsx"],"names":[],"mappings":"AAQA,UAAU,kBAAkB;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAMD,wBAAgB,aAAa,CAAC,EAAE,YAAoB,EAAE,EAAE,kBAAkB,sCAqBzE"}
@@ -1,59 +0,0 @@
1
- import { StyleSheet, View } from 'react-native';
2
- import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
3
- import Svg, { Defs, Path, Pattern, Rect } from 'react-native-svg';
4
- import { useConversationContext } from '../../contexts/conversation_context';
5
- import { useTheme } from '../../hooks';
6
- import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../../utils/styles';
7
- import { Text } from '../display';
8
- const WAVE_WIDTH = 16;
9
- const WAVE_HEIGHT = 8;
10
- const FADE_DURATION = 750;
11
- export function UnreadDivider({ scrolledPast = false }) {
12
- const styles = useStyles();
13
- const { atEndOfMessageHistory } = useConversationContext();
14
- if (scrolledPast || atEndOfMessageHistory)
15
- return null;
16
- return (<Animated.View entering={FadeIn.duration(FADE_DURATION)} exiting={FadeOut.duration(FADE_DURATION)} style={styles.container} accessibilityRole="header" accessibilityLabel="Unread messages start here">
17
- <SquigglyLine />
18
- <Text variant="footnote" style={styles.label}>
19
- New
20
- </Text>
21
- <SquigglyLine />
22
- </Animated.View>);
23
- }
24
- function SquigglyLine() {
25
- const { colors } = useTheme();
26
- return (<View style={squigglyStyle.container}>
27
- <Svg width="100%" height={WAVE_HEIGHT}>
28
- <Defs>
29
- <Pattern id="wave" x="0" y="0" width={WAVE_WIDTH} height={WAVE_HEIGHT} patternUnits="userSpaceOnUse">
30
- <Path d="M 0 4 Q 4 0 8 4 T 16 4" stroke={colors.interaction} strokeWidth={1.5} fill="none"/>
31
- </Pattern>
32
- </Defs>
33
- <Rect x="0" y="0" width="100%" height={WAVE_HEIGHT} fill="url(#wave)"/>
34
- </Svg>
35
- </View>);
36
- }
37
- const squigglyStyle = StyleSheet.create({
38
- container: {
39
- flex: 1,
40
- height: WAVE_HEIGHT,
41
- },
42
- });
43
- const useStyles = () => {
44
- const { colors } = useTheme();
45
- return StyleSheet.create({
46
- container: {
47
- alignItems: 'center',
48
- flexDirection: 'row',
49
- paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,
50
- paddingVertical: 8,
51
- gap: 8,
52
- },
53
- label: {
54
- color: colors.interaction,
55
- fontWeight: '600',
56
- },
57
- });
58
- };
59
- //# sourceMappingURL=unread_divider.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"unread_divider.js","sourceRoot":"","sources":["../../../src/components/conversation/unread_divider.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StyleSheet, View } from 'react-native'\nimport Animated, { FadeIn, FadeOut } from 'react-native-reanimated'\nimport Svg, { Defs, Path, Pattern, Rect } from 'react-native-svg'\nimport { useConversationContext } from '../../contexts/conversation_context'\nimport { useTheme } from '../../hooks'\nimport { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../../utils/styles'\nimport { Text } from '../display'\n\ninterface UnreadDividerProps {\n scrolledPast?: boolean\n}\n\nconst WAVE_WIDTH = 16\nconst WAVE_HEIGHT = 8\nconst FADE_DURATION = 750\n\nexport function UnreadDivider({ scrolledPast = false }: UnreadDividerProps) {\n const styles = useStyles()\n const { atEndOfMessageHistory } = useConversationContext()\n\n if (scrolledPast || atEndOfMessageHistory) return null\n\n return (\n <Animated.View\n entering={FadeIn.duration(FADE_DURATION)}\n exiting={FadeOut.duration(FADE_DURATION)}\n style={styles.container}\n accessibilityRole=\"header\"\n accessibilityLabel=\"Unread messages start here\"\n >\n <SquigglyLine />\n <Text variant=\"footnote\" style={styles.label}>\n New\n </Text>\n <SquigglyLine />\n </Animated.View>\n )\n}\n\nfunction SquigglyLine() {\n const { colors } = useTheme()\n return (\n <View style={squigglyStyle.container}>\n <Svg width=\"100%\" height={WAVE_HEIGHT}>\n <Defs>\n <Pattern\n id=\"wave\"\n x=\"0\"\n y=\"0\"\n width={WAVE_WIDTH}\n height={WAVE_HEIGHT}\n patternUnits=\"userSpaceOnUse\"\n >\n <Path\n d=\"M 0 4 Q 4 0 8 4 T 16 4\"\n stroke={colors.interaction}\n strokeWidth={1.5}\n fill=\"none\"\n />\n </Pattern>\n </Defs>\n <Rect x=\"0\" y=\"0\" width=\"100%\" height={WAVE_HEIGHT} fill=\"url(#wave)\" />\n </Svg>\n </View>\n )\n}\n\nconst squigglyStyle = StyleSheet.create({\n container: {\n flex: 1,\n height: WAVE_HEIGHT,\n },\n})\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n container: {\n alignItems: 'center',\n flexDirection: 'row',\n paddingHorizontal: CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL,\n paddingVertical: 8,\n gap: 8,\n },\n label: {\n color: colors.interaction,\n fontWeight: '600',\n },\n })\n}\n"]}
@@ -1,20 +0,0 @@
1
- import type { ViewToken } from 'react-native';
2
- import type { ViewabilityObserver } from '../utils/message_viewability';
3
- interface UseFlatListViewabilityArgs<Item> {
4
- observers: ViewabilityObserver<Item>[];
5
- itemVisiblePercentThreshold?: number;
6
- }
7
- export declare function useFlatListViewability<Item>({ observers, itemVisiblePercentThreshold, }: UseFlatListViewabilityArgs<Item>): {
8
- viewabilityConfigCallbackPairs: {
9
- viewabilityConfig: {
10
- itemVisiblePercentThreshold: number;
11
- };
12
- onViewableItemsChanged: ({ viewableItems, changed, }: {
13
- viewableItems: ViewToken[];
14
- changed: ViewToken[];
15
- }) => void;
16
- }[];
17
- onScrollBeginDrag: () => void;
18
- };
19
- export {};
20
- //# sourceMappingURL=use_flat_list_viewability.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_flat_list_viewability.d.ts","sourceRoot":"","sources":["../../src/hooks/use_flat_list_viewability.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AAEvE,UAAU,0BAA0B,CAAC,IAAI;IACvC,SAAS,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAA;IACtC,2BAA2B,CAAC,EAAE,MAAM,CAAA;CACrC;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,EAC3C,SAAS,EACT,2BAAgC,GACjC,EAAE,0BAA0B,CAAC,IAAI,CAAC;;;;;8DAkB1B;YACD,aAAa,EAAE,SAAS,EAAE,CAAA;YAC1B,OAAO,EAAE,SAAS,EAAE,CAAA;SACrB;;;EAYN"}
@@ -1,30 +0,0 @@
1
- import { useCallback, useEffect, useRef } from 'react';
2
- export function useFlatListViewability({ observers, itemVisiblePercentThreshold = 50, }) {
3
- const userHasScrolledRef = useRef(false);
4
- const observersRef = useRef(observers);
5
- useEffect(() => {
6
- observersRef.current = observers;
7
- });
8
- const onScrollBeginDrag = useCallback(() => {
9
- userHasScrolledRef.current = true;
10
- }, []);
11
- const viewabilityConfigCallbackPairs = useRef([
12
- {
13
- viewabilityConfig: { itemVisiblePercentThreshold },
14
- onViewableItemsChanged: ({ viewableItems, changed, }) => {
15
- const event = {
16
- viewableItems: viewableItems.map((toEntry)),
17
- changed: changed.map((toEntry)),
18
- userHasScrolled: userHasScrolledRef.current,
19
- };
20
- for (const observer of observersRef.current)
21
- observer(event);
22
- },
23
- },
24
- ]).current;
25
- return { viewabilityConfigCallbackPairs, onScrollBeginDrag };
26
- }
27
- function toEntry(token) {
28
- return { key: token.key, isViewable: !!token.isViewable, item: token.item };
29
- }
30
- //# sourceMappingURL=use_flat_list_viewability.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_flat_list_viewability.js","sourceRoot":"","sources":["../../src/hooks/use_flat_list_viewability.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAStD,MAAM,UAAU,sBAAsB,CAAO,EAC3C,SAAS,EACT,2BAA2B,GAAG,EAAE,GACC;IACjC,MAAM,kBAAkB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACxC,MAAM,YAAY,GAAG,MAAM,CAAC,SAAS,CAAC,CAAA;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,YAAY,CAAC,OAAO,GAAG,SAAS,CAAA;IAClC,CAAC,CAAC,CAAA;IAEF,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,kBAAkB,CAAC,OAAO,GAAG,IAAI,CAAA;IACnC,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,8BAA8B,GAAG,MAAM,CAAC;QAC5C;YACE,iBAAiB,EAAE,EAAE,2BAA2B,EAAE;YAClD,sBAAsB,EAAE,CAAC,EACvB,aAAa,EACb,OAAO,GAIR,EAAE,EAAE;gBACH,MAAM,KAAK,GAAG;oBACZ,aAAa,EAAE,aAAa,CAAC,GAAG,CAAC,CAAA,OAAa,CAAA,CAAC;oBAC/C,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA,OAAa,CAAA,CAAC;oBACnC,eAAe,EAAE,kBAAkB,CAAC,OAAO;iBAC5C,CAAA;gBACD,KAAK,MAAM,QAAQ,IAAI,YAAY,CAAC,OAAO;oBAAE,QAAQ,CAAC,KAAK,CAAC,CAAA;YAC9D,CAAC;SACF;KACF,CAAC,CAAC,OAAO,CAAA;IAEV,OAAO,EAAE,8BAA8B,EAAE,iBAAiB,EAAE,CAAA;AAC9D,CAAC;AAED,SAAS,OAAO,CAAO,KAAgB;IACrC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE,KAAK,CAAC,IAAY,EAAE,CAAA;AACrF,CAAC","sourcesContent":["import { useCallback, useEffect, useRef } from 'react'\nimport type { ViewToken } from 'react-native'\nimport type { ViewabilityObserver } from '../utils/message_viewability'\n\ninterface UseFlatListViewabilityArgs<Item> {\n observers: ViewabilityObserver<Item>[]\n itemVisiblePercentThreshold?: number\n}\n\nexport function useFlatListViewability<Item>({\n observers,\n itemVisiblePercentThreshold = 50,\n}: UseFlatListViewabilityArgs<Item>) {\n const userHasScrolledRef = useRef(false)\n const observersRef = useRef(observers)\n\n useEffect(() => {\n observersRef.current = observers\n })\n\n const onScrollBeginDrag = useCallback(() => {\n userHasScrolledRef.current = true\n }, [])\n\n const viewabilityConfigCallbackPairs = useRef([\n {\n viewabilityConfig: { itemVisiblePercentThreshold },\n onViewableItemsChanged: ({\n viewableItems,\n changed,\n }: {\n viewableItems: ViewToken[]\n changed: ViewToken[]\n }) => {\n const event = {\n viewableItems: viewableItems.map(toEntry<Item>),\n changed: changed.map(toEntry<Item>),\n userHasScrolled: userHasScrolledRef.current,\n }\n for (const observer of observersRef.current) observer(event)\n },\n },\n ]).current\n\n return { viewabilityConfigCallbackPairs, onScrollBeginDrag }\n}\n\nfunction toEntry<Item>(token: ViewToken) {\n return { key: token.key, isViewable: !!token.isViewable, item: token.item as Item }\n}\n"]}
@@ -1,9 +0,0 @@
1
- import { RefObject } from 'react';
2
- import type { FlatList } from 'react-native';
3
- export declare function useJumpToBottomAction({ listRef }: {
4
- listRef: RefObject<FlatList | null>;
5
- }): {
6
- handleJumpToBottom: () => void;
7
- isJumpingToBottom: boolean;
8
- };
9
- //# sourceMappingURL=use_jump_to_bottom_action.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_bottom_action.d.ts","sourceRoot":"","sources":["../../src/hooks/use_jump_to_bottom_action.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAA4C,MAAM,OAAO,CAAA;AAC3E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAU5C,wBAAgB,qBAAqB,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAA;CAAE;;;EA8DzF"}
@@ -1,62 +0,0 @@
1
- import { useQueryClient } from '@tanstack/react-query';
2
- import { useCallback, useEffect, useRef, useState } from 'react';
3
- import { useConversationContext } from '../contexts/conversation_context';
4
- import { Haptic } from '../utils/native_adapters';
5
- import { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages';
6
- import { useApiClient } from './use_api_client';
7
- import { useJumpToUnreadGates } from './use_jump_to_unread_gates';
8
- const LATEST_PAGE_SIZE = 25;
9
- export function useJumpToBottomAction({ listRef }) {
10
- const { jumpToUnreadEnabled } = useJumpToUnreadGates();
11
- const { conversationId, currentPageReplyRootId, initialMessageId, setInitialMessageId } = useConversationContext();
12
- const queryClient = useQueryClient();
13
- const apiClient = useApiClient();
14
- const [isJumpingToBottom, setIsJumpingToBottom] = useState(false);
15
- const mountedRef = useRef(true);
16
- useEffect(() => () => {
17
- mountedRef.current = false;
18
- }, []);
19
- const handleJumpToBottom = useCallback(() => {
20
- Haptic.impactLight();
21
- listRef.current?.scrollToOffset({ offset: 0, animated: true });
22
- if (!jumpToUnreadEnabled || !initialMessageId)
23
- return;
24
- const queryKey = getMessagesQueryKey({
25
- conversation_id: conversationId,
26
- reply_root_id: currentPageReplyRootId,
27
- });
28
- const args = getMessagesRequestArgs({
29
- conversation_id: conversationId,
30
- reply_root_id: currentPageReplyRootId,
31
- });
32
- setIsJumpingToBottom(true);
33
- queryClient
34
- .cancelQueries({ queryKey })
35
- .then(() => apiClient.chat.get({
36
- url: args.url,
37
- data: { ...args.data, perPage: LATEST_PAGE_SIZE },
38
- }))
39
- .then(latest => {
40
- if (!mountedRef.current)
41
- return;
42
- queryClient.setQueryData(queryKey, { pages: [latest], pageParams: [{}] });
43
- setInitialMessageId(null);
44
- listRef.current?.scrollToOffset({ offset: 0, animated: false });
45
- })
46
- .finally(() => {
47
- if (mountedRef.current)
48
- setIsJumpingToBottom(false);
49
- });
50
- }, [
51
- jumpToUnreadEnabled,
52
- initialMessageId,
53
- setInitialMessageId,
54
- queryClient,
55
- apiClient,
56
- conversationId,
57
- currentPageReplyRootId,
58
- listRef,
59
- ]);
60
- return { handleJumpToBottom, isJumpingToBottom };
61
- }
62
- //# sourceMappingURL=use_jump_to_bottom_action.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_bottom_action.js","sourceRoot":"","sources":["../../src/hooks/use_jump_to_bottom_action.ts"],"names":[],"mappings":"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","sourcesContent":["import { useQueryClient } from '@tanstack/react-query'\nimport { RefObject, useCallback, useEffect, useRef, useState } from 'react'\nimport type { FlatList } from 'react-native'\nimport { useConversationContext } from '../contexts/conversation_context'\nimport { ApiCollection, MessageResource } from '../types'\nimport { Haptic } from '../utils/native_adapters'\nimport { getMessagesQueryKey, getMessagesRequestArgs } from '../utils/request/get_messages'\nimport { useApiClient } from './use_api_client'\nimport { useJumpToUnreadGates } from './use_jump_to_unread_gates'\n\nconst LATEST_PAGE_SIZE = 25\n\nexport function useJumpToBottomAction({ listRef }: { listRef: RefObject<FlatList | null> }) {\n const { jumpToUnreadEnabled } = useJumpToUnreadGates()\n const { conversationId, currentPageReplyRootId, initialMessageId, setInitialMessageId } =\n useConversationContext()\n const queryClient = useQueryClient()\n const apiClient = useApiClient()\n const [isJumpingToBottom, setIsJumpingToBottom] = useState(false)\n\n const mountedRef = useRef(true)\n useEffect(\n () => () => {\n mountedRef.current = false\n },\n []\n )\n\n const handleJumpToBottom = useCallback(() => {\n Haptic.impactLight()\n listRef.current?.scrollToOffset({ offset: 0, animated: true })\n\n if (!jumpToUnreadEnabled || !initialMessageId) return\n\n const queryKey = getMessagesQueryKey({\n conversation_id: conversationId,\n reply_root_id: currentPageReplyRootId,\n })\n const args = getMessagesRequestArgs({\n conversation_id: conversationId,\n reply_root_id: currentPageReplyRootId,\n })\n\n setIsJumpingToBottom(true)\n\n queryClient\n .cancelQueries({ queryKey })\n .then(() =>\n apiClient.chat.get<ApiCollection<MessageResource>>({\n url: args.url,\n data: { ...args.data, perPage: LATEST_PAGE_SIZE },\n })\n )\n .then(latest => {\n if (!mountedRef.current) return\n queryClient.setQueryData(queryKey, { pages: [latest], pageParams: [{}] })\n setInitialMessageId(null)\n listRef.current?.scrollToOffset({ offset: 0, animated: false })\n })\n .finally(() => {\n if (mountedRef.current) setIsJumpingToBottom(false)\n })\n }, [\n jumpToUnreadEnabled,\n initialMessageId,\n setInitialMessageId,\n queryClient,\n apiClient,\n conversationId,\n currentPageReplyRootId,\n listRef,\n ])\n\n return { handleJumpToBottom, isJumpingToBottom }\n}\n"]}
@@ -1,20 +0,0 @@
1
- import { RefObject } from 'react';
2
- import type { FlatList } from 'react-native';
3
- interface UseJumpToUnreadAnchorArgs<T> {
4
- listRef: RefObject<FlatList<T> | null>;
5
- items: T[];
6
- }
7
- interface ScrollToIndexFailInfo {
8
- index: number;
9
- highestMeasuredFrameIndex: number;
10
- averageItemLength: number;
11
- }
12
- export declare function useJumpToUnreadAnchor<T extends {
13
- id?: string | number;
14
- }>({ listRef, items, }: UseJumpToUnreadAnchorArgs<T>): {
15
- onScrollBeginDrag: () => void;
16
- onContentSizeChange: () => void;
17
- onScrollToIndexFailed: (info: ScrollToIndexFailInfo) => void;
18
- };
19
- export {};
20
- //# sourceMappingURL=use_jump_to_unread_anchor.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_unread_anchor.d.ts","sourceRoot":"","sources":["../../src/hooks/use_jump_to_unread_anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkC,MAAM,OAAO,CAAA;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAI5C,UAAU,yBAAyB,CAAC,CAAC;IACnC,OAAO,EAAE,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAA;IACtC,KAAK,EAAE,CAAC,EAAE,CAAA;CACX;AAED,UAAU,qBAAqB;IAC7B,KAAK,EAAE,MAAM,CAAA;IACb,yBAAyB,EAAE,MAAM,CAAA;IACjC,iBAAiB,EAAE,MAAM,CAAA;CAC1B;AAED,wBAAgB,qBAAqB,CAAC,CAAC,SAAS;IAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,EAAE,EACxE,OAAO,EACP,KAAK,GACN,EAAE,yBAAyB,CAAC,CAAC,CAAC;;;kCAiCpB,qBAAqB;EAe/B"}
@@ -1,53 +0,0 @@
1
- import { useCallback, useEffect, useRef } from 'react';
2
- import { useConversationContext } from '../contexts/conversation_context';
3
- import { useJumpToUnreadGates } from './use_jump_to_unread_gates';
4
- export function useJumpToUnreadAnchor({ listRef, items, }) {
5
- const { jumpToUnreadActive } = useJumpToUnreadGates();
6
- const { initialMessageId } = useConversationContext();
7
- const hasAnchoredRef = useRef(false);
8
- const userTouchedRef = useRef(false);
9
- const retryTimerRef = useRef(null);
10
- useEffect(() => {
11
- return () => {
12
- if (retryTimerRef.current)
13
- clearTimeout(retryTimerRef.current);
14
- retryTimerRef.current = null;
15
- };
16
- }, []);
17
- const onScrollBeginDrag = useCallback(() => {
18
- userTouchedRef.current = true;
19
- if (retryTimerRef.current) {
20
- clearTimeout(retryTimerRef.current);
21
- retryTimerRef.current = null;
22
- }
23
- }, []);
24
- const onContentSizeChange = useCallback(() => {
25
- if (hasAnchoredRef.current)
26
- return;
27
- if (!jumpToUnreadActive || !initialMessageId)
28
- return;
29
- if (userTouchedRef.current)
30
- return;
31
- const index = items.findIndex(item => String(item.id ?? '') === initialMessageId);
32
- if (index < 0)
33
- return;
34
- hasAnchoredRef.current = true;
35
- listRef.current?.scrollToIndex({ index, viewPosition: 0.25, animated: false });
36
- }, [jumpToUnreadActive, initialMessageId, items, listRef]);
37
- const onScrollToIndexFailed = useCallback((info) => {
38
- if (userTouchedRef.current)
39
- return;
40
- const offset = info.averageItemLength * info.index;
41
- listRef.current?.scrollToOffset({ offset, animated: false });
42
- if (retryTimerRef.current)
43
- clearTimeout(retryTimerRef.current);
44
- retryTimerRef.current = setTimeout(() => {
45
- retryTimerRef.current = null;
46
- if (userTouchedRef.current)
47
- return;
48
- listRef.current?.scrollToIndex({ index: info.index, viewPosition: 0.25, animated: false });
49
- }, 50);
50
- }, [listRef]);
51
- return { onScrollBeginDrag, onContentSizeChange, onScrollToIndexFailed };
52
- }
53
- //# sourceMappingURL=use_jump_to_unread_anchor.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_unread_anchor.js","sourceRoot":"","sources":["../../src/hooks/use_jump_to_unread_anchor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAEjE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AACzE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAajE,MAAM,UAAU,qBAAqB,CAAqC,EACxE,OAAO,EACP,KAAK,GACwB;IAC7B,MAAM,EAAE,kBAAkB,EAAE,GAAG,oBAAoB,EAAE,CAAA;IACrD,MAAM,EAAE,gBAAgB,EAAE,GAAG,sBAAsB,EAAE,CAAA;IACrD,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACpC,MAAM,cAAc,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IACpC,MAAM,aAAa,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAA;IAExE,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE;YACV,IAAI,aAAa,CAAC,OAAO;gBAAE,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;YAC9D,aAAa,CAAC,OAAO,GAAG,IAAI,CAAA;QAC9B,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,iBAAiB,GAAG,WAAW,CAAC,GAAG,EAAE;QACzC,cAAc,CAAC,OAAO,GAAG,IAAI,CAAA;QAC7B,IAAI,aAAa,CAAC,OAAO,EAAE,CAAC;YAC1B,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;YACnC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAA;QAC9B,CAAC;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,mBAAmB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC3C,IAAI,cAAc,CAAC,OAAO;YAAE,OAAM;QAClC,IAAI,CAAC,kBAAkB,IAAI,CAAC,gBAAgB;YAAE,OAAM;QACpD,IAAI,cAAc,CAAC,OAAO;YAAE,OAAM;QAClC,MAAM,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAA;QACjF,IAAI,KAAK,GAAG,CAAC;YAAE,OAAM;QACrB,cAAc,CAAC,OAAO,GAAG,IAAI,CAAA;QAC7B,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;IAChF,CAAC,EAAE,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAA;IAE1D,MAAM,qBAAqB,GAAG,WAAW,CACvC,CAAC,IAA2B,EAAE,EAAE;QAC9B,IAAI,cAAc,CAAC,OAAO;YAAE,OAAM;QAClC,MAAM,MAAM,GAAG,IAAI,CAAC,iBAAiB,GAAG,IAAI,CAAC,KAAK,CAAA;QAClD,OAAO,CAAC,OAAO,EAAE,cAAc,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5D,IAAI,aAAa,CAAC,OAAO;YAAE,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;QAC9D,aAAa,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YACtC,aAAa,CAAC,OAAO,GAAG,IAAI,CAAA;YAC5B,IAAI,cAAc,CAAC,OAAO;gBAAE,OAAM;YAClC,OAAO,CAAC,OAAO,EAAE,aAAa,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC5F,CAAC,EAAE,EAAE,CAAC,CAAA;IACR,CAAC,EACD,CAAC,OAAO,CAAC,CACV,CAAA;IAED,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAA;AAC1E,CAAC","sourcesContent":["import { RefObject, useCallback, useEffect, useRef } from 'react'\nimport type { FlatList } from 'react-native'\nimport { useConversationContext } from '../contexts/conversation_context'\nimport { useJumpToUnreadGates } from './use_jump_to_unread_gates'\n\ninterface UseJumpToUnreadAnchorArgs<T> {\n listRef: RefObject<FlatList<T> | null>\n items: T[]\n}\n\ninterface ScrollToIndexFailInfo {\n index: number\n highestMeasuredFrameIndex: number\n averageItemLength: number\n}\n\nexport function useJumpToUnreadAnchor<T extends { id?: string | number }>({\n listRef,\n items,\n}: UseJumpToUnreadAnchorArgs<T>) {\n const { jumpToUnreadActive } = useJumpToUnreadGates()\n const { initialMessageId } = useConversationContext()\n const hasAnchoredRef = useRef(false)\n const userTouchedRef = useRef(false)\n const retryTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n useEffect(() => {\n return () => {\n if (retryTimerRef.current) clearTimeout(retryTimerRef.current)\n retryTimerRef.current = null\n }\n }, [])\n\n const onScrollBeginDrag = useCallback(() => {\n userTouchedRef.current = true\n if (retryTimerRef.current) {\n clearTimeout(retryTimerRef.current)\n retryTimerRef.current = null\n }\n }, [])\n\n const onContentSizeChange = useCallback(() => {\n if (hasAnchoredRef.current) return\n if (!jumpToUnreadActive || !initialMessageId) return\n if (userTouchedRef.current) return\n const index = items.findIndex(item => String(item.id ?? '') === initialMessageId)\n if (index < 0) return\n hasAnchoredRef.current = true\n listRef.current?.scrollToIndex({ index, viewPosition: 0.25, animated: false })\n }, [jumpToUnreadActive, initialMessageId, items, listRef])\n\n const onScrollToIndexFailed = useCallback(\n (info: ScrollToIndexFailInfo) => {\n if (userTouchedRef.current) return\n const offset = info.averageItemLength * info.index\n listRef.current?.scrollToOffset({ offset, animated: false })\n if (retryTimerRef.current) clearTimeout(retryTimerRef.current)\n retryTimerRef.current = setTimeout(() => {\n retryTimerRef.current = null\n if (userTouchedRef.current) return\n listRef.current?.scrollToIndex({ index: info.index, viewPosition: 0.25, animated: false })\n }, 50)\n },\n [listRef]\n )\n\n return { onScrollBeginDrag, onContentSizeChange, onScrollToIndexFailed }\n}\n"]}
@@ -1,5 +0,0 @@
1
- export declare function useJumpToUnreadGates(): {
2
- jumpToUnreadEnabled: boolean;
3
- jumpToUnreadActive: boolean;
4
- };
5
- //# sourceMappingURL=use_jump_to_unread_gates.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_unread_gates.d.ts","sourceRoot":"","sources":["../../src/hooks/use_jump_to_unread_gates.ts"],"names":[],"mappings":"AAGA,wBAAgB,oBAAoB;;;EAMnC"}
@@ -1,10 +0,0 @@
1
- import { useConversationContext } from '../contexts/conversation_context';
2
- import { availableFeatures, useFeatures } from './use_features';
3
- export function useJumpToUnreadGates() {
4
- const { featureEnabled } = useFeatures();
5
- const { initialMessageIdIsAnchor } = useConversationContext();
6
- const jumpToUnreadEnabled = featureEnabled(availableFeatures.jump_to_unread);
7
- const jumpToUnreadActive = jumpToUnreadEnabled && initialMessageIdIsAnchor;
8
- return { jumpToUnreadEnabled, jumpToUnreadActive };
9
- }
10
- //# sourceMappingURL=use_jump_to_unread_gates.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_jump_to_unread_gates.js","sourceRoot":"","sources":["../../src/hooks/use_jump_to_unread_gates.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AACzE,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAA;AAE/D,MAAM,UAAU,oBAAoB;IAClC,MAAM,EAAE,cAAc,EAAE,GAAG,WAAW,EAAE,CAAA;IACxC,MAAM,EAAE,wBAAwB,EAAE,GAAG,sBAAsB,EAAE,CAAA;IAC7D,MAAM,mBAAmB,GAAG,cAAc,CAAC,iBAAiB,CAAC,cAAc,CAAC,CAAA;IAC5E,MAAM,kBAAkB,GAAG,mBAAmB,IAAI,wBAAwB,CAAA;IAC1E,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,CAAA;AACpD,CAAC","sourcesContent":["import { useConversationContext } from '../contexts/conversation_context'\nimport { availableFeatures, useFeatures } from './use_features'\n\nexport function useJumpToUnreadGates() {\n const { featureEnabled } = useFeatures()\n const { initialMessageIdIsAnchor } = useConversationContext()\n const jumpToUnreadEnabled = featureEnabled(availableFeatures.jump_to_unread)\n const jumpToUnreadActive = jumpToUnreadEnabled && initialMessageIdIsAnchor\n return { jumpToUnreadEnabled, jumpToUnreadActive }\n}\n"]}
@@ -1,13 +0,0 @@
1
- import type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native';
2
- interface UseScrollTrackingArgs {
3
- hasMoreNewerMessages: boolean;
4
- isFetchingNewerMessages: boolean;
5
- fetchNewerMessages: () => void;
6
- cancelFetchNewerMessages: () => void;
7
- }
8
- export declare function useScrollTracking({ hasMoreNewerMessages, isFetchingNewerMessages, fetchNewerMessages, cancelFetchNewerMessages, }: UseScrollTrackingArgs): {
9
- onScroll: (event: NativeSyntheticEvent<NativeScrollEvent>) => void;
10
- showJumpToBottomButton: boolean;
11
- };
12
- export {};
13
- //# sourceMappingURL=use_scroll_tracking.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_scroll_tracking.d.ts","sourceRoot":"","sources":["../../src/hooks/use_scroll_tracking.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AAO3E,UAAU,qBAAqB;IAC7B,oBAAoB,EAAE,OAAO,CAAA;IAC7B,uBAAuB,EAAE,OAAO,CAAA;IAChC,kBAAkB,EAAE,MAAM,IAAI,CAAA;IAC9B,wBAAwB,EAAE,MAAM,IAAI,CAAA;CACrC;AAED,wBAAgB,iBAAiB,CAAC,EAChC,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,GACzB,EAAE,qBAAqB;sBAgBZ,oBAAoB,CAAC,iBAAiB,CAAC;;EA2BlD"}
@@ -1,45 +0,0 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
- import { useConversationContext } from '../contexts/conversation_context';
3
- const JUMP_TO_BOTTOM_OFFSET_THRESHOLD = 200;
4
- const AT_BOTTOM_OFFSET_TOLERANCE = 5;
5
- const FETCH_NEWER_OFFSET_THRESHOLD = 600;
6
- export function useScrollTracking({ hasMoreNewerMessages, isFetchingNewerMessages, fetchNewerMessages, cancelFetchNewerMessages, }) {
7
- const { atEndOfMessageHistory, setAtEndOfMessageHistory } = useConversationContext();
8
- const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false);
9
- const withinBoundaryRef = useRef(false);
10
- useEffect(() => {
11
- return () => {
12
- cancelFetchNewerMessages();
13
- };
14
- }, [cancelFetchNewerMessages]);
15
- useEffect(() => {
16
- if (!isFetchingNewerMessages)
17
- withinBoundaryRef.current = false;
18
- }, [isFetchingNewerMessages]);
19
- const onScroll = useCallback((event) => {
20
- const offsetY = event.nativeEvent.contentOffset.y;
21
- setShowJumpToBottomButton(offsetY > JUMP_TO_BOTTOM_OFFSET_THRESHOLD);
22
- const atBottom = offsetY < AT_BOTTOM_OFFSET_TOLERANCE;
23
- const atEnd = atBottom && !hasMoreNewerMessages;
24
- if (atEnd !== atEndOfMessageHistory)
25
- setAtEndOfMessageHistory(atEnd);
26
- if (offsetY >= FETCH_NEWER_OFFSET_THRESHOLD) {
27
- withinBoundaryRef.current = false;
28
- return;
29
- }
30
- if (withinBoundaryRef.current)
31
- return;
32
- if (!hasMoreNewerMessages || isFetchingNewerMessages)
33
- return;
34
- withinBoundaryRef.current = true;
35
- fetchNewerMessages();
36
- }, [
37
- hasMoreNewerMessages,
38
- isFetchingNewerMessages,
39
- fetchNewerMessages,
40
- atEndOfMessageHistory,
41
- setAtEndOfMessageHistory,
42
- ]);
43
- return { onScroll, showJumpToBottomButton };
44
- }
45
- //# sourceMappingURL=use_scroll_tracking.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_scroll_tracking.js","sourceRoot":"","sources":["../../src/hooks/use_scroll_tracking.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAEhE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AAEzE,MAAM,+BAA+B,GAAG,GAAG,CAAA;AAC3C,MAAM,0BAA0B,GAAG,CAAC,CAAA;AACpC,MAAM,4BAA4B,GAAG,GAAG,CAAA;AASxC,MAAM,UAAU,iBAAiB,CAAC,EAChC,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,wBAAwB,GACF;IACtB,MAAM,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,GAAG,sBAAsB,EAAE,CAAA;IACpF,MAAM,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC3E,MAAM,iBAAiB,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAEvC,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE;YACV,wBAAwB,EAAE,CAAA;QAC5B,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,wBAAwB,CAAC,CAAC,CAAA;IAE9B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,uBAAuB;YAAE,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAA;IACjE,CAAC,EAAE,CAAC,uBAAuB,CAAC,CAAC,CAAA;IAE7B,MAAM,QAAQ,GAAG,WAAW,CAC1B,CAAC,KAA8C,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,KAAK,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,CAAA;QACjD,yBAAyB,CAAC,OAAO,GAAG,+BAA+B,CAAC,CAAA;QAEpE,MAAM,QAAQ,GAAG,OAAO,GAAG,0BAA0B,CAAA;QACrD,MAAM,KAAK,GAAG,QAAQ,IAAI,CAAC,oBAAoB,CAAA;QAC/C,IAAI,KAAK,KAAK,qBAAqB;YAAE,wBAAwB,CAAC,KAAK,CAAC,CAAA;QAEpE,IAAI,OAAO,IAAI,4BAA4B,EAAE,CAAC;YAC5C,iBAAiB,CAAC,OAAO,GAAG,KAAK,CAAA;YACjC,OAAM;QACR,CAAC;QACD,IAAI,iBAAiB,CAAC,OAAO;YAAE,OAAM;QACrC,IAAI,CAAC,oBAAoB,IAAI,uBAAuB;YAAE,OAAM;QAC5D,iBAAiB,CAAC,OAAO,GAAG,IAAI,CAAA;QAChC,kBAAkB,EAAE,CAAA;IACtB,CAAC,EACD;QACE,oBAAoB;QACpB,uBAAuB;QACvB,kBAAkB;QAClB,qBAAqB;QACrB,wBAAwB;KACzB,CACF,CAAA;IAED,OAAO,EAAE,QAAQ,EAAE,sBAAsB,EAAE,CAAA;AAC7C,CAAC","sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react'\nimport type { NativeScrollEvent, NativeSyntheticEvent } from 'react-native'\nimport { useConversationContext } from '../contexts/conversation_context'\n\nconst JUMP_TO_BOTTOM_OFFSET_THRESHOLD = 200\nconst AT_BOTTOM_OFFSET_TOLERANCE = 5\nconst FETCH_NEWER_OFFSET_THRESHOLD = 600\n\ninterface UseScrollTrackingArgs {\n hasMoreNewerMessages: boolean\n isFetchingNewerMessages: boolean\n fetchNewerMessages: () => void\n cancelFetchNewerMessages: () => void\n}\n\nexport function useScrollTracking({\n hasMoreNewerMessages,\n isFetchingNewerMessages,\n fetchNewerMessages,\n cancelFetchNewerMessages,\n}: UseScrollTrackingArgs) {\n const { atEndOfMessageHistory, setAtEndOfMessageHistory } = useConversationContext()\n const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false)\n const withinBoundaryRef = useRef(false)\n\n useEffect(() => {\n return () => {\n cancelFetchNewerMessages()\n }\n }, [cancelFetchNewerMessages])\n\n useEffect(() => {\n if (!isFetchingNewerMessages) withinBoundaryRef.current = false\n }, [isFetchingNewerMessages])\n\n const onScroll = useCallback(\n (event: NativeSyntheticEvent<NativeScrollEvent>) => {\n const offsetY = event.nativeEvent.contentOffset.y\n setShowJumpToBottomButton(offsetY > JUMP_TO_BOTTOM_OFFSET_THRESHOLD)\n\n const atBottom = offsetY < AT_BOTTOM_OFFSET_TOLERANCE\n const atEnd = atBottom && !hasMoreNewerMessages\n if (atEnd !== atEndOfMessageHistory) setAtEndOfMessageHistory(atEnd)\n\n if (offsetY >= FETCH_NEWER_OFFSET_THRESHOLD) {\n withinBoundaryRef.current = false\n return\n }\n if (withinBoundaryRef.current) return\n if (!hasMoreNewerMessages || isFetchingNewerMessages) return\n withinBoundaryRef.current = true\n fetchNewerMessages()\n },\n [\n hasMoreNewerMessages,\n isFetchingNewerMessages,\n fetchNewerMessages,\n atEndOfMessageHistory,\n setAtEndOfMessageHistory,\n ]\n )\n\n return { onScroll, showJumpToBottomButton }\n}\n"]}
@@ -1,4 +0,0 @@
1
- export declare function useTrackHighestSeenMessage(): {
2
- onMessageSeen: (sortKey: string) => void;
3
- };
4
- //# sourceMappingURL=use_track_highest_seen_message.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_track_highest_seen_message.d.ts","sourceRoot":"","sources":["../../src/hooks/use_track_highest_seen_message.ts"],"names":[],"mappings":"AAOA,wBAAgB,0BAA0B;6BAY5B,MAAM;EAuBnB"}