@planningcenter/chat-react-native 3.38.0-rc.8 → 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 (154) 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/groups/use_group_chat_conversation_payload.d.ts.map +1 -1
  13. package/build/hooks/groups/use_group_chat_conversation_payload.js +1 -0
  14. package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -1
  15. package/build/hooks/use_conversation_messages.d.ts +6 -15
  16. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  17. package/build/hooks/use_conversation_messages.js +9 -62
  18. package/build/hooks/use_conversation_messages.js.map +1 -1
  19. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  20. package/build/hooks/use_conversation_messages_jolt_events.js +4 -4
  21. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  22. package/build/hooks/use_conversations_actions.d.ts +0 -5
  23. package/build/hooks/use_conversations_actions.d.ts.map +1 -1
  24. package/build/hooks/use_conversations_actions.js +0 -12
  25. package/build/hooks/use_conversations_actions.js.map +1 -1
  26. package/build/hooks/use_features.d.ts +0 -1
  27. package/build/hooks/use_features.d.ts.map +1 -1
  28. package/build/hooks/use_features.js +0 -1
  29. package/build/hooks/use_features.js.map +1 -1
  30. package/build/hooks/use_mark_latest_message_read.d.ts +1 -1
  31. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  32. package/build/hooks/use_mark_latest_message_read.js +1 -17
  33. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  34. package/build/hooks/use_suspense_api.d.ts +0 -1
  35. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  36. package/build/hooks/use_suspense_api.js +1 -1
  37. package/build/hooks/use_suspense_api.js.map +1 -1
  38. package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -1
  39. package/build/screens/conversation_filter_recipients/components/header_row.js +3 -2
  40. package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -1
  41. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -1
  42. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +47 -18
  43. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -1
  44. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +2 -1
  45. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
  46. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +23 -26
  47. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
  48. package/build/screens/conversation_filter_recipients/types.d.ts +1 -1
  49. package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -1
  50. package/build/screens/conversation_filter_recipients/types.js.map +1 -1
  51. package/build/screens/conversation_screen.d.ts +0 -1
  52. package/build/screens/conversation_screen.d.ts.map +1 -1
  53. package/build/screens/conversation_screen.js +48 -95
  54. package/build/screens/conversation_screen.js.map +1 -1
  55. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +1 -1
  56. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -1
  57. package/build/screens/conversation_select_recipients/components/recipient_link_row.js +3 -3
  58. package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -1
  59. package/build/screens/conversation_select_recipients/components/team_recipient_row.d.ts.map +1 -1
  60. package/build/screens/conversation_select_recipients/components/team_recipient_row.js +1 -1
  61. package/build/screens/conversation_select_recipients/components/team_recipient_row.js.map +1 -1
  62. package/build/utils/cache/messages_cache.d.ts +0 -1
  63. package/build/utils/cache/messages_cache.d.ts.map +1 -1
  64. package/build/utils/cache/messages_cache.js +0 -4
  65. package/build/utils/cache/messages_cache.js.map +1 -1
  66. package/build/utils/group_messages.d.ts +2 -9
  67. package/build/utils/group_messages.d.ts.map +1 -1
  68. package/build/utils/group_messages.js +1 -20
  69. package/build/utils/group_messages.js.map +1 -1
  70. package/package.json +3 -3
  71. package/src/__tests__/hooks/use_group_chat_conversation_payload.test.tsx +50 -0
  72. package/src/components/conversation/jump_to_bottom_button.tsx +8 -57
  73. package/src/components/conversation/reply_shadow_message.tsx +1 -1
  74. package/src/contexts/conversation_context.tsx +2 -30
  75. package/src/hooks/groups/use_group_chat_conversation_payload.ts +1 -0
  76. package/src/hooks/use_conversation_messages.ts +20 -120
  77. package/src/hooks/use_conversation_messages_jolt_events.ts +3 -4
  78. package/src/hooks/use_conversations_actions.ts +0 -15
  79. package/src/hooks/use_features.ts +0 -1
  80. package/src/hooks/use_mark_latest_message_read.ts +2 -16
  81. package/src/hooks/use_suspense_api.ts +1 -1
  82. package/src/screens/conversation_filter_recipients/components/header_row.tsx +3 -2
  83. package/src/screens/conversation_filter_recipients/hooks/__tests__/use_service_types_with_teams.test.ts +108 -0
  84. package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +46 -19
  85. package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +31 -29
  86. package/src/screens/conversation_filter_recipients/types.tsx +1 -1
  87. package/src/screens/conversation_screen.tsx +76 -184
  88. package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +6 -4
  89. package/src/screens/conversation_select_recipients/components/team_recipient_row.tsx +2 -1
  90. package/src/utils/__tests__/group_messages.test.ts +0 -71
  91. package/src/utils/cache/messages_cache.ts +0 -5
  92. package/src/utils/group_messages.ts +2 -42
  93. package/build/components/conversation/unread_divider.d.ts +0 -6
  94. package/build/components/conversation/unread_divider.d.ts.map +0 -1
  95. package/build/components/conversation/unread_divider.js +0 -59
  96. package/build/components/conversation/unread_divider.js.map +0 -1
  97. package/build/hooks/use_flat_list_viewability.d.ts +0 -20
  98. package/build/hooks/use_flat_list_viewability.d.ts.map +0 -1
  99. package/build/hooks/use_flat_list_viewability.js +0 -30
  100. package/build/hooks/use_flat_list_viewability.js.map +0 -1
  101. package/build/hooks/use_jump_to_bottom_action.d.ts +0 -9
  102. package/build/hooks/use_jump_to_bottom_action.d.ts.map +0 -1
  103. package/build/hooks/use_jump_to_bottom_action.js +0 -62
  104. package/build/hooks/use_jump_to_bottom_action.js.map +0 -1
  105. package/build/hooks/use_jump_to_unread_anchor.d.ts +0 -20
  106. package/build/hooks/use_jump_to_unread_anchor.d.ts.map +0 -1
  107. package/build/hooks/use_jump_to_unread_anchor.js +0 -53
  108. package/build/hooks/use_jump_to_unread_anchor.js.map +0 -1
  109. package/build/hooks/use_jump_to_unread_gates.d.ts +0 -5
  110. package/build/hooks/use_jump_to_unread_gates.d.ts.map +0 -1
  111. package/build/hooks/use_jump_to_unread_gates.js +0 -10
  112. package/build/hooks/use_jump_to_unread_gates.js.map +0 -1
  113. package/build/hooks/use_scroll_tracking.d.ts +0 -13
  114. package/build/hooks/use_scroll_tracking.d.ts.map +0 -1
  115. package/build/hooks/use_scroll_tracking.js +0 -45
  116. package/build/hooks/use_scroll_tracking.js.map +0 -1
  117. package/build/hooks/use_track_highest_seen_message.d.ts +0 -4
  118. package/build/hooks/use_track_highest_seen_message.d.ts.map +0 -1
  119. package/build/hooks/use_track_highest_seen_message.js +0 -35
  120. package/build/hooks/use_track_highest_seen_message.js.map +0 -1
  121. package/build/utils/conversation_messages.d.ts +0 -10
  122. package/build/utils/conversation_messages.d.ts.map +0 -1
  123. package/build/utils/conversation_messages.js +0 -22
  124. package/build/utils/conversation_messages.js.map +0 -1
  125. package/build/utils/highest_seen_tracker.d.ts +0 -12
  126. package/build/utils/highest_seen_tracker.d.ts.map +0 -1
  127. package/build/utils/highest_seen_tracker.js +0 -37
  128. package/build/utils/highest_seen_tracker.js.map +0 -1
  129. package/build/utils/message_viewability.d.ts +0 -24
  130. package/build/utils/message_viewability.d.ts.map +0 -1
  131. package/build/utils/message_viewability.js +0 -29
  132. package/build/utils/message_viewability.js.map +0 -1
  133. package/build/utils/unread_divider_helpers.d.ts +0 -18
  134. package/build/utils/unread_divider_helpers.d.ts.map +0 -1
  135. package/build/utils/unread_divider_helpers.js +0 -13
  136. package/build/utils/unread_divider_helpers.js.map +0 -1
  137. package/src/__tests__/hooks/use_conversation_messages.test.tsx +0 -109
  138. package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +0 -154
  139. package/src/__tests__/utils/cache/messages_cache.test.ts +0 -54
  140. package/src/components/conversation/unread_divider.tsx +0 -90
  141. package/src/hooks/use_flat_list_viewability.ts +0 -50
  142. package/src/hooks/use_jump_to_bottom_action.ts +0 -75
  143. package/src/hooks/use_jump_to_unread_anchor.ts +0 -68
  144. package/src/hooks/use_jump_to_unread_gates.ts +0 -10
  145. package/src/hooks/use_scroll_tracking.ts +0 -64
  146. package/src/hooks/use_track_highest_seen_message.ts +0 -43
  147. package/src/utils/__tests__/conversation_messages.test.ts +0 -105
  148. package/src/utils/__tests__/highest_seen_tracker.test.ts +0 -82
  149. package/src/utils/__tests__/message_viewability.test.ts +0 -168
  150. package/src/utils/__tests__/unread_divider_helpers.test.ts +0 -85
  151. package/src/utils/conversation_messages.ts +0 -37
  152. package/src/utils/highest_seen_tracker.ts +0 -42
  153. package/src/utils/message_viewability.ts +0 -49
  154. 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":"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","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"}