@planningcenter/chat-react-native 4.4.1-qa-staging.39 → 4.4.1-qa-1036.2
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.
- package/build/components/conversation/message_list.d.ts.map +1 -1
- package/build/components/conversation/message_list.js +123 -155
- package/build/components/conversation/message_list.js.map +1 -1
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +0 -1
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/display/keyboard_scroll_view.d.ts.map +1 -1
- package/build/components/display/keyboard_scroll_view.js +0 -1
- package/build/components/display/keyboard_scroll_view.js.map +1 -1
- package/build/components/page/page_error_boundary.d.ts +1 -9
- package/build/components/page/page_error_boundary.d.ts.map +1 -1
- package/build/components/page/page_error_boundary.js +31 -56
- package/build/components/page/page_error_boundary.js.map +1 -1
- package/build/navigation/index.d.ts +2 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +6 -11
- package/build/navigation/index.js.map +1 -1
- package/build/navigation/screenLayout.d.ts.map +1 -1
- package/build/navigation/screenLayout.js +44 -13
- package/build/navigation/screenLayout.js.map +1 -1
- package/build/screens/age_check/age_check_required_screen.d.ts.map +1 -1
- package/build/screens/age_check/age_check_required_screen.js +0 -1
- package/build/screens/age_check/age_check_required_screen.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +0 -1
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js +0 -1
- package/build/screens/conversation_select_recipients/conversation_new_entry_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +291 -332
- package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js +0 -1
- package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js +0 -1
- package/build/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.js.map +1 -1
- package/build/screens/get_help_screen.js +62 -56
- package/build/screens/get_help_screen.js.map +1 -1
- package/build/screens/group_notification_settings_screen.js +2 -3
- package/build/screens/group_notification_settings_screen.js.map +1 -1
- package/build/screens/notification_settings_screen.d.ts.map +1 -1
- package/build/screens/notification_settings_screen.js +0 -1
- package/build/screens/notification_settings_screen.js.map +1 -1
- package/build/screens/preferred_app_selection_screen.js +39 -45
- package/build/screens/preferred_app_selection_screen.js.map +1 -1
- package/build/screens/search/components/search_results_list.d.ts +1 -4
- package/build/screens/search/components/search_results_list.d.ts.map +1 -1
- package/build/screens/search/components/search_results_list.js +110 -136
- package/build/screens/search/components/search_results_list.js.map +1 -1
- package/build/screens/search/search_screen.d.ts.map +1 -1
- package/build/screens/search/search_screen.js +28 -21
- package/build/screens/search/search_screen.js.map +1 -1
- package/build/screens/settings_screen.d.ts.map +1 -1
- package/build/screens/settings_screen.js +6 -7
- package/build/screens/settings_screen.js.map +1 -1
- package/package.json +3 -3
- package/src/components/conversation/__tests__/message_list.test.tsx +0 -4
- package/src/components/conversation/message_list.tsx +0 -6
- package/src/components/conversations/conversations.tsx +0 -1
- package/src/components/display/keyboard_scroll_view.tsx +0 -1
- package/src/components/page/__tests__/page_error_boundary.test.tsx +0 -33
- package/src/components/page/page_error_boundary.tsx +12 -43
- package/src/navigation/index.tsx +3 -11
- package/src/navigation/screenLayout.tsx +19 -4
- package/src/screens/age_check/age_check_required_screen.tsx +1 -5
- package/src/screens/conversation_details_screen.tsx +0 -1
- package/src/screens/conversation_select_recipients/conversation_new_entry_screen.tsx +1 -4
- package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +68 -78
- package/src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx +0 -1
- package/src/screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen.tsx +0 -1
- package/src/screens/get_help_screen.tsx +4 -4
- package/src/screens/group_notification_settings_screen.tsx +3 -3
- package/src/screens/notification_settings_screen.tsx +0 -1
- package/src/screens/preferred_app_selection_screen.tsx +4 -4
- package/src/screens/search/__tests__/search_screen.test.tsx +7 -5
- package/src/screens/search/components/__tests__/search_results_list.test.tsx +2 -6
- package/src/screens/search/components/search_results_list.tsx +13 -34
- package/src/screens/search/search_screen.tsx +18 -8
- package/src/screens/settings_screen.tsx +25 -25
- package/build/navigation/page_error_fallbacks.d.ts +0 -7
- package/build/navigation/page_error_fallbacks.d.ts.map +0 -1
- package/build/navigation/page_error_fallbacks.js +0 -7
- package/build/navigation/page_error_fallbacks.js.map +0 -1
- package/src/navigation/page_error_fallbacks.ts +0 -14
- package/src/screens/conversation_select_recipients/__tests__/conversation_select_direct_message_recipients_screen.test.tsx +0 -100
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { PlatformPressable } from '@react-navigation/elements'
|
|
2
2
|
import { StackActions, useNavigation } from '@react-navigation/native'
|
|
3
|
-
import {
|
|
3
|
+
import { RefObject, useRef, useState } from 'react'
|
|
4
4
|
import { FlatList, Pressable, StyleSheet, TextInput, View } from 'react-native'
|
|
5
5
|
import { Avatar, Badge, Banner, Icon, KeyboardView, Spinner, Text } from '../../components'
|
|
6
6
|
import { ActionButton } from '../../components/display/action_button'
|
|
7
7
|
import { AutoFocusAwareTextInput } from '../../components/display/text_input'
|
|
8
|
+
import { ComponentErrorBoundary } from '../../components/page/component_error_boundary'
|
|
8
9
|
import { useTheme } from '../../hooks'
|
|
9
10
|
import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations'
|
|
10
11
|
import { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates'
|
|
@@ -91,31 +92,38 @@ export function ConversationSelectDirectMessageRecipientsScreen({
|
|
|
91
92
|
|
|
92
93
|
return (
|
|
93
94
|
<KeyboardView>
|
|
95
|
+
{isError && (
|
|
96
|
+
<Banner
|
|
97
|
+
appearance="error"
|
|
98
|
+
description="There was an issue starting the conversation. Please try again."
|
|
99
|
+
style={styles.errorBanner}
|
|
100
|
+
/>
|
|
101
|
+
)}
|
|
102
|
+
<ToField
|
|
103
|
+
selectedPeople={selectedPeople}
|
|
104
|
+
searchTerm={searchTerm}
|
|
105
|
+
onSearchChange={setSearchTerm}
|
|
106
|
+
onRemove={removePerson}
|
|
107
|
+
onClear={() => setSelectedPeople(new Map())}
|
|
108
|
+
searchInputRef={searchInputRef}
|
|
109
|
+
/>
|
|
94
110
|
<View style={styles.candidateResultsContainer}>
|
|
95
|
-
<
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
{
|
|
102
|
-
|
|
103
|
-
appearance="error"
|
|
104
|
-
description="There was an issue starting the conversation. Please try again."
|
|
105
|
-
style={styles.errorBanner}
|
|
106
|
-
/>
|
|
107
|
-
)}
|
|
108
|
-
<ToField
|
|
109
|
-
selectedPeople={selectedPeople}
|
|
110
|
-
searchTerm={searchTerm}
|
|
111
|
-
onSearchChange={setSearchTerm}
|
|
112
|
-
onRemove={removePerson}
|
|
113
|
-
onClear={() => setSelectedPeople(new Map())}
|
|
114
|
-
searchInputRef={searchInputRef}
|
|
115
|
-
/>
|
|
116
|
-
</>
|
|
111
|
+
<ComponentErrorBoundary
|
|
112
|
+
key={debouncedTerm}
|
|
113
|
+
fallback={
|
|
114
|
+
<Banner
|
|
115
|
+
appearance="error"
|
|
116
|
+
description="Couldn't load people right now. Try again."
|
|
117
|
+
style={styles.errorBanner}
|
|
118
|
+
/>
|
|
117
119
|
}
|
|
118
|
-
|
|
120
|
+
>
|
|
121
|
+
<CandidateResults
|
|
122
|
+
term={debouncedTerm}
|
|
123
|
+
selectedPeople={selectedPeople}
|
|
124
|
+
onSelect={selectPerson}
|
|
125
|
+
/>
|
|
126
|
+
</ComponentErrorBoundary>
|
|
119
127
|
</View>
|
|
120
128
|
<ActionButton
|
|
121
129
|
title={buttonText}
|
|
@@ -206,57 +214,53 @@ function CandidateResults({
|
|
|
206
214
|
term,
|
|
207
215
|
selectedPeople,
|
|
208
216
|
onSelect,
|
|
209
|
-
header,
|
|
210
217
|
}: {
|
|
211
218
|
term: string
|
|
212
219
|
selectedPeople: Map<string, DirectMessageCandidateResource>
|
|
213
220
|
onSelect: (candidate: DirectMessageCandidateResource) => void
|
|
214
|
-
header: ReactElement
|
|
215
221
|
}) {
|
|
216
222
|
const styles = useStyles()
|
|
217
223
|
const { data, isFetching } = useDirectMessageCandidates(term)
|
|
218
224
|
const { groups, teams, resultsDescription } = useDirectMessageAffiliations()
|
|
219
225
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS
|
|
223
|
-
const showsResults = term.length >= 1 && !isAtLimit && unselectedCandidates.length > 0
|
|
226
|
+
if (term.length < 1) {
|
|
227
|
+
if (selectedPeople.size > 0) return null
|
|
224
228
|
|
|
225
|
-
|
|
226
|
-
|
|
229
|
+
return (
|
|
230
|
+
<View style={styles.emptyState}>
|
|
231
|
+
<Icon name="churchCenter.people" size={40} style={styles.emptyStateIcon} />
|
|
232
|
+
<Text style={styles.emptyStateTitle}>Search for people to direct message</Text>
|
|
233
|
+
<Text variant="secondary" style={styles.emptyStateSubtitle}>
|
|
234
|
+
Start a conversation with people in your groups and teams.
|
|
235
|
+
</Text>
|
|
236
|
+
</View>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
227
239
|
|
|
228
|
-
|
|
229
|
-
if (selectedPeople.size > 0) return null
|
|
240
|
+
const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS
|
|
230
241
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
}
|
|
242
|
+
if (isAtLimit) {
|
|
243
|
+
return (
|
|
244
|
+
<View style={styles.emptyState}>
|
|
245
|
+
<Text variant="secondary" style={styles.emptyStateSubtitle}>
|
|
246
|
+
You can add up to {MAX_RECIPIENTS} people to a direct message.
|
|
247
|
+
</Text>
|
|
248
|
+
</View>
|
|
249
|
+
)
|
|
250
|
+
}
|
|
241
251
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
<View style={styles.emptyState}>
|
|
245
|
-
<Text variant="secondary" style={styles.emptyStateSubtitle}>
|
|
246
|
-
You can add up to {MAX_RECIPIENTS} people to a direct message.
|
|
247
|
-
</Text>
|
|
248
|
-
</View>
|
|
249
|
-
)
|
|
250
|
-
}
|
|
252
|
+
const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id))
|
|
253
|
+
const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)
|
|
251
254
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
255
|
+
if (isFetching && unselectedCandidates.length === 0) {
|
|
256
|
+
return (
|
|
257
|
+
<View style={styles.emptyState}>
|
|
258
|
+
<Spinner />
|
|
259
|
+
</View>
|
|
260
|
+
)
|
|
261
|
+
}
|
|
259
262
|
|
|
263
|
+
if (!isFetching && unselectedCandidates.length === 0) {
|
|
260
264
|
return (
|
|
261
265
|
<View style={styles.emptyState}>
|
|
262
266
|
<Icon name="general.search" size={32} style={styles.emptyStateIcon} />
|
|
@@ -266,15 +270,13 @@ function CandidateResults({
|
|
|
266
270
|
</Text>
|
|
267
271
|
</View>
|
|
268
272
|
)
|
|
269
|
-
}
|
|
273
|
+
}
|
|
270
274
|
|
|
271
275
|
return (
|
|
272
276
|
<CandidateList
|
|
273
|
-
|
|
274
|
-
candidates={showsResults ? unselectedCandidates : []}
|
|
277
|
+
candidates={unselectedCandidates}
|
|
275
278
|
hasTruncated={hasTruncated}
|
|
276
279
|
description={resultsDescription}
|
|
277
|
-
emptyState={emptyState}
|
|
278
280
|
groups={groups}
|
|
279
281
|
teams={teams}
|
|
280
282
|
onSelect={onSelect}
|
|
@@ -307,33 +309,27 @@ function candidateAffiliationNames(
|
|
|
307
309
|
}
|
|
308
310
|
|
|
309
311
|
function CandidateList({
|
|
310
|
-
header,
|
|
311
312
|
candidates,
|
|
312
313
|
hasTruncated,
|
|
313
314
|
description,
|
|
314
|
-
emptyState,
|
|
315
315
|
groups,
|
|
316
316
|
teams,
|
|
317
317
|
onSelect,
|
|
318
318
|
}: {
|
|
319
|
-
header: ReactElement
|
|
320
319
|
candidates: DirectMessageCandidateResource[]
|
|
321
320
|
hasTruncated: boolean
|
|
322
321
|
description: string | null
|
|
323
|
-
emptyState: ReactElement | null
|
|
324
322
|
groups: Map<number, string>
|
|
325
323
|
teams: Map<number, string>
|
|
326
324
|
onSelect: (candidate: DirectMessageCandidateResource) => void
|
|
327
325
|
}) {
|
|
328
326
|
const styles = useStyles()
|
|
329
|
-
const hasCandidates = candidates.length > 0
|
|
330
327
|
const available = candidates.filter(c => !c.directMessagesDisabled)
|
|
331
328
|
const dmDisabled = candidates.filter(c => c.directMessagesDisabled)
|
|
332
329
|
|
|
333
330
|
return (
|
|
334
331
|
<FlatList<DirectMessageCandidateResource>
|
|
335
332
|
data={available}
|
|
336
|
-
contentInsetAdjustmentBehavior="automatic"
|
|
337
333
|
keyboardShouldPersistTaps="handled"
|
|
338
334
|
keyExtractor={item => item.id}
|
|
339
335
|
renderItem={({ item }) => (
|
|
@@ -344,13 +340,7 @@ function CandidateList({
|
|
|
344
340
|
onSelect={() => onSelect(item)}
|
|
345
341
|
/>
|
|
346
342
|
)}
|
|
347
|
-
ListHeaderComponent={
|
|
348
|
-
<>
|
|
349
|
-
{header}
|
|
350
|
-
{hasCandidates && <ResultsHeading description={description} />}
|
|
351
|
-
</>
|
|
352
|
-
}
|
|
353
|
-
ListEmptyComponent={emptyState}
|
|
343
|
+
ListHeaderComponent={<ResultsHeading description={description} />}
|
|
354
344
|
ListFooterComponent={
|
|
355
345
|
<>
|
|
356
346
|
{dmDisabled.length > 0 && (
|
|
@@ -371,7 +361,7 @@ function CandidateList({
|
|
|
371
361
|
))}
|
|
372
362
|
</>
|
|
373
363
|
)}
|
|
374
|
-
{
|
|
364
|
+
{hasTruncated && (
|
|
375
365
|
<View style={styles.truncatedFooter}>
|
|
376
366
|
<Text variant="secondary" style={styles.truncatedText}>
|
|
377
367
|
Keep typing to narrow your results.
|
package/src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx
CHANGED
|
@@ -60,7 +60,6 @@ export const ConversationSelectGroupRecipientsScreen = ({
|
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
62
|
<SectionList<GroupsGroupResource, GroupsSection>
|
|
63
|
-
contentInsetAdjustmentBehavior="automatic"
|
|
64
63
|
sections={sections}
|
|
65
64
|
keyExtractor={item => item.id.toString()}
|
|
66
65
|
stickySectionHeadersEnabled={false}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
2
2
|
import { useCallback, useMemo } from 'react'
|
|
3
|
-
import { Alert, Linking,
|
|
3
|
+
import { Alert, Linking, StyleSheet, View } from 'react-native'
|
|
4
4
|
import { Heading, PressableRow, Text, TextInlineButton } from '../components'
|
|
5
5
|
import { useApiGet, useTheme } from '../hooks'
|
|
6
6
|
import { useAppName } from '../hooks/use_app_name'
|
|
@@ -56,7 +56,7 @@ export const GetHelpScreen = ({ route }: GetHelpScreenProps) => {
|
|
|
56
56
|
}, [navigation])
|
|
57
57
|
|
|
58
58
|
return (
|
|
59
|
-
<
|
|
59
|
+
<View style={[styles.container]}>
|
|
60
60
|
{appSpecificHelpUrls.length > 0 && (
|
|
61
61
|
<Heading variant="h2" style={[styles.heading, styles.headingBottomBorder]}>
|
|
62
62
|
How-to articles
|
|
@@ -90,7 +90,7 @@ export const GetHelpScreen = ({ route }: GetHelpScreenProps) => {
|
|
|
90
90
|
to the development team.
|
|
91
91
|
</Text>
|
|
92
92
|
</View>
|
|
93
|
-
</
|
|
93
|
+
</View>
|
|
94
94
|
)
|
|
95
95
|
}
|
|
96
96
|
|
|
@@ -145,7 +145,7 @@ const useStyles = () => {
|
|
|
145
145
|
|
|
146
146
|
return StyleSheet.create({
|
|
147
147
|
container: {
|
|
148
|
-
|
|
148
|
+
flex: 1,
|
|
149
149
|
},
|
|
150
150
|
text: {
|
|
151
151
|
paddingVertical: 4,
|
|
@@ -2,7 +2,7 @@ import { PlatformPressable } from '@react-navigation/elements'
|
|
|
2
2
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
3
3
|
import type { NativeStackNavigationProp } from '@react-navigation/native-stack'
|
|
4
4
|
import React, { useEffect } from 'react'
|
|
5
|
-
import { Platform,
|
|
5
|
+
import { Platform, StyleSheet, View } from 'react-native'
|
|
6
6
|
import { Heading, Icon, Text } from '../components'
|
|
7
7
|
import { useTheme } from '../hooks'
|
|
8
8
|
import { platformFontWeightBold } from '../utils/styles'
|
|
@@ -38,7 +38,7 @@ export function GroupNotificationSettingsScreen({ route }: GroupNotificationSett
|
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
return (
|
|
41
|
-
<
|
|
41
|
+
<View style={styles.container}>
|
|
42
42
|
<View style={styles.sectionOuter}>
|
|
43
43
|
<View style={styles.sectionInner}>
|
|
44
44
|
<Heading variant="h2" style={styles.sectionHeading}>
|
|
@@ -76,7 +76,7 @@ export function GroupNotificationSettingsScreen({ route }: GroupNotificationSett
|
|
|
76
76
|
)}
|
|
77
77
|
</View>
|
|
78
78
|
</PlatformPressable>
|
|
79
|
-
</
|
|
79
|
+
</View>
|
|
80
80
|
)
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -123,7 +123,6 @@ export function NotificationSettingsScreen({}: NotificationSettingsScreenProps)
|
|
|
123
123
|
return (
|
|
124
124
|
<View style={styles.listContainer}>
|
|
125
125
|
<FlatList
|
|
126
|
-
contentInsetAdjustmentBehavior="automatic"
|
|
127
126
|
data={listData as SectionListData}
|
|
128
127
|
contentContainerStyle={styles.contentContainer}
|
|
129
128
|
renderItem={({ item, index }) => {
|
|
@@ -2,7 +2,7 @@ import { PlatformPressable } from '@react-navigation/elements'
|
|
|
2
2
|
import { StaticScreenProps } from '@react-navigation/native'
|
|
3
3
|
import { useMutation } from '@tanstack/react-query'
|
|
4
4
|
import React, { type PropsWithChildren } from 'react'
|
|
5
|
-
import { Image,
|
|
5
|
+
import { Image, StyleSheet, View, type ViewStyle } from 'react-native'
|
|
6
6
|
import { Heading, Icon, Text } from '../components'
|
|
7
7
|
import { useApiClient, useTheme } from '../hooks'
|
|
8
8
|
import { useAppName } from '../hooks/use_app_name'
|
|
@@ -45,7 +45,7 @@ export function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScre
|
|
|
45
45
|
const sectionTitle = chatType ? chatTypeLabel(chatType.title) : undefined
|
|
46
46
|
|
|
47
47
|
return (
|
|
48
|
-
<
|
|
48
|
+
<View style={styles.container}>
|
|
49
49
|
<View style={styles.section}>
|
|
50
50
|
<Heading variant="h2" style={styles.sectionHeading}>
|
|
51
51
|
{sectionTitle}
|
|
@@ -64,7 +64,7 @@ export function PreferredAppSelectionScreen({ route }: PreferredAppSelectionScre
|
|
|
64
64
|
</PressableRow>
|
|
65
65
|
))}
|
|
66
66
|
</View>
|
|
67
|
-
</
|
|
67
|
+
</View>
|
|
68
68
|
)
|
|
69
69
|
}
|
|
70
70
|
|
|
@@ -118,7 +118,7 @@ const PressableRow = ({
|
|
|
118
118
|
|
|
119
119
|
const styles = StyleSheet.create({
|
|
120
120
|
container: {
|
|
121
|
-
|
|
121
|
+
flex: 1,
|
|
122
122
|
},
|
|
123
123
|
section: {
|
|
124
124
|
paddingTop: 24,
|
|
@@ -106,13 +106,12 @@ describe('SearchScreen', () => {
|
|
|
106
106
|
fireEvent.changeText(input, ' budget ')
|
|
107
107
|
|
|
108
108
|
expect(view.getByText('Search chat')).toBeTruthy()
|
|
109
|
-
|
|
110
|
-
new Set(mockUseSearchResults.mock.calls.map(([term]) => term).filter(term => term.trim()))
|
|
111
|
-
expect([...searchedTerms()]).toEqual([])
|
|
109
|
+
expect(mockUseSearchResults).not.toHaveBeenCalled()
|
|
112
110
|
|
|
113
111
|
act(() => jest.advanceTimersByTime(200))
|
|
114
112
|
|
|
115
|
-
|
|
113
|
+
const searchedTerms = new Set(mockUseSearchResults.mock.calls.map(([term]) => term))
|
|
114
|
+
expect([...searchedTerms]).toEqual(['budget'])
|
|
116
115
|
expect(view.queryByText('Search chat')).toBeNull()
|
|
117
116
|
expect(view.getByLabelText('Loading results')).toBeTruthy()
|
|
118
117
|
})
|
|
@@ -122,7 +121,10 @@ describe('SearchScreen', () => {
|
|
|
122
121
|
|
|
123
122
|
const scrollView = view.UNSAFE_getByType(ScrollView)
|
|
124
123
|
expect(scrollView.props.keyboardShouldPersistTaps).toBe('handled')
|
|
125
|
-
expect(scrollView.props.contentContainerStyle).toMatchObject({
|
|
124
|
+
expect(scrollView.props.contentContainerStyle).toMatchObject({
|
|
125
|
+
flexGrow: 1,
|
|
126
|
+
justifyContent: 'center',
|
|
127
|
+
})
|
|
126
128
|
expect(view.getByText('Search chat')).toBeTruthy()
|
|
127
129
|
})
|
|
128
130
|
|
|
@@ -49,13 +49,9 @@ const messageResult = (id: string): MessageSearchResultResource => ({
|
|
|
49
49
|
},
|
|
50
50
|
})
|
|
51
51
|
|
|
52
|
-
const slots = { header: <></>, prompt: <></> }
|
|
53
|
-
|
|
54
52
|
const renderList = (state: Partial<SearchState>, onSettled = jest.fn()) => {
|
|
55
53
|
mockUseSearchResults.mockReturnValue(searchState(state))
|
|
56
|
-
const list = () => (
|
|
57
|
-
<SearchResultsList term="potluck" onSelect={jest.fn()} onSettled={onSettled} {...slots} />
|
|
58
|
-
)
|
|
54
|
+
const list = () => <SearchResultsList term="potluck" onSelect={jest.fn()} onSettled={onSettled} />
|
|
59
55
|
const view = render(list())
|
|
60
56
|
const rerenderWith = (next: Partial<SearchState>) => {
|
|
61
57
|
mockUseSearchResults.mockReturnValue(searchState(next))
|
|
@@ -134,7 +130,7 @@ describe('SearchResultsList', () => {
|
|
|
134
130
|
const results = [conversationResult('1'), messageResult('1'), messageResult('2')]
|
|
135
131
|
mockUseSearchResults.mockReturnValue(searchState({ results }))
|
|
136
132
|
const view = render(
|
|
137
|
-
<SearchResultsList term="potluck" onSelect={onSelect} onSettled={jest.fn()}
|
|
133
|
+
<SearchResultsList term="potluck" onSelect={onSelect} onSettled={jest.fn()} />
|
|
138
134
|
)
|
|
139
135
|
|
|
140
136
|
fireEvent.press(view.getByLabelText(/^Message 2/))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, {
|
|
1
|
+
import React, { useEffect, useRef } from 'react'
|
|
2
2
|
import { FlatList, StyleSheet, View } from 'react-native'
|
|
3
3
|
import { Banner, Spinner, Text, TextButton } from '../../../components'
|
|
4
4
|
import { useSearchResults } from '../../../hooks/use_search_results'
|
|
@@ -23,17 +23,9 @@ interface SearchResultsListProps {
|
|
|
23
23
|
term: string
|
|
24
24
|
onSelect: (result: SearchResultResource, position: number) => void
|
|
25
25
|
onSettled: (term: string, counts: SearchResultCounts) => void
|
|
26
|
-
header: ReactElement
|
|
27
|
-
prompt: ReactElement
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
export function SearchResultsList({
|
|
31
|
-
term,
|
|
32
|
-
onSelect,
|
|
33
|
-
onSettled,
|
|
34
|
-
header,
|
|
35
|
-
prompt,
|
|
36
|
-
}: SearchResultsListProps) {
|
|
28
|
+
export function SearchResultsList({ term, onSelect, onSettled }: SearchResultsListProps) {
|
|
37
29
|
const {
|
|
38
30
|
results,
|
|
39
31
|
failedTypes,
|
|
@@ -44,10 +36,9 @@ export function SearchResultsList({
|
|
|
44
36
|
hasNextPage,
|
|
45
37
|
isFetchingNextPage,
|
|
46
38
|
} = useSearchResults(term)
|
|
47
|
-
const
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
const settled = searching && !isPending && !isError
|
|
39
|
+
const conversationResults = results.filter(isConversationResult)
|
|
40
|
+
const messageResults = results.filter(isMessageResult)
|
|
41
|
+
const settled = !isPending && !isError
|
|
51
42
|
|
|
52
43
|
const settledTermRef = useRef<string | undefined>(undefined)
|
|
53
44
|
|
|
@@ -65,7 +56,6 @@ export function SearchResultsList({
|
|
|
65
56
|
<FlatList
|
|
66
57
|
data={messageResults}
|
|
67
58
|
keyExtractor={item => item.id}
|
|
68
|
-
contentInsetAdjustmentBehavior="automatic"
|
|
69
59
|
keyboardShouldPersistTaps="handled"
|
|
70
60
|
keyboardDismissMode="on-drag"
|
|
71
61
|
contentContainerStyle={styles.content}
|
|
@@ -74,27 +64,20 @@ export function SearchResultsList({
|
|
|
74
64
|
)}
|
|
75
65
|
ListHeaderComponent={
|
|
76
66
|
<>
|
|
77
|
-
{header}
|
|
78
67
|
{conversationResults.length > 0 && (
|
|
79
68
|
<ConversationResults results={conversationResults} onSelect={onSelect} />
|
|
80
69
|
)}
|
|
81
|
-
{
|
|
82
|
-
<SectionFailure type="conversation" />
|
|
83
|
-
)}
|
|
70
|
+
{failedTypes.includes('conversation') && <SectionFailure type="conversation" />}
|
|
84
71
|
{messageResults.length > 0 && <ResultsSection title="Messages" />}
|
|
85
72
|
</>
|
|
86
73
|
}
|
|
87
74
|
ListEmptyComponent={
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
/>
|
|
95
|
-
) : (
|
|
96
|
-
<View style={styles.prompt}>{prompt}</View>
|
|
97
|
-
)
|
|
75
|
+
<ListEmpty
|
|
76
|
+
term={term}
|
|
77
|
+
isError={isError}
|
|
78
|
+
isPending={isPending}
|
|
79
|
+
noResults={results.length === 0 && failedTypes.length === 0}
|
|
80
|
+
/>
|
|
98
81
|
}
|
|
99
82
|
ListFooterComponent={
|
|
100
83
|
<>
|
|
@@ -108,7 +91,7 @@ export function SearchResultsList({
|
|
|
108
91
|
Try again
|
|
109
92
|
</TextButton>
|
|
110
93
|
)}
|
|
111
|
-
{
|
|
94
|
+
{failedTypes.includes('message') && <SectionFailure type="message" />}
|
|
112
95
|
</>
|
|
113
96
|
}
|
|
114
97
|
onEndReached={() => {
|
|
@@ -166,10 +149,6 @@ const styles = StyleSheet.create({
|
|
|
166
149
|
content: {
|
|
167
150
|
flexGrow: 1,
|
|
168
151
|
},
|
|
169
|
-
prompt: {
|
|
170
|
-
flexGrow: 1,
|
|
171
|
-
justifyContent: 'center',
|
|
172
|
-
},
|
|
173
152
|
banner: {
|
|
174
153
|
margin: 16,
|
|
175
154
|
},
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NativeStackScreenProps,
|
|
5
5
|
} from '@react-navigation/native-stack'
|
|
6
6
|
import React, { useRef, useState } from 'react'
|
|
7
|
-
import { Keyboard, StyleSheet, View } from 'react-native'
|
|
7
|
+
import { Keyboard, ScrollView, StyleSheet, View } from 'react-native'
|
|
8
8
|
import { KeyboardView } from '../../components'
|
|
9
9
|
import {
|
|
10
10
|
composeOptions,
|
|
@@ -64,13 +64,19 @@ export function SearchScreen() {
|
|
|
64
64
|
return (
|
|
65
65
|
<KeyboardView>
|
|
66
66
|
<View style={styles.container} testID="search-screen">
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
67
|
+
<SearchField term={term} onChange={setTerm} />
|
|
68
|
+
{debouncedTerm.length > 0 ? (
|
|
69
|
+
<SearchResultsList
|
|
70
|
+
key={debouncedTerm}
|
|
71
|
+
term={debouncedTerm}
|
|
72
|
+
onSelect={openResult}
|
|
73
|
+
onSettled={publishSearch}
|
|
74
|
+
/>
|
|
75
|
+
) : (
|
|
76
|
+
<ScrollView contentContainerStyle={styles.prompt} keyboardShouldPersistTaps="handled">
|
|
77
|
+
<SearchPromptBlankState />
|
|
78
|
+
</ScrollView>
|
|
79
|
+
)}
|
|
74
80
|
</View>
|
|
75
81
|
</KeyboardView>
|
|
76
82
|
)
|
|
@@ -80,4 +86,8 @@ const styles = StyleSheet.create({
|
|
|
80
86
|
container: {
|
|
81
87
|
flex: 1,
|
|
82
88
|
},
|
|
89
|
+
prompt: {
|
|
90
|
+
flexGrow: 1,
|
|
91
|
+
justifyContent: 'center',
|
|
92
|
+
},
|
|
83
93
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PlatformPressable } from '@react-navigation/elements'
|
|
2
2
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
3
3
|
import React, { useCallback } from 'react'
|
|
4
|
-
import { Platform,
|
|
4
|
+
import { Platform, StyleSheet, View } from 'react-native'
|
|
5
5
|
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
6
6
|
import { Heading, Icon, Text, VersionFooter } from '../components'
|
|
7
7
|
import { Switch } from '../components/display/switch'
|
|
@@ -28,31 +28,29 @@ export function SettingsScreen({}: SettingsScreenProps) {
|
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
30
|
<View style={styles.container}>
|
|
31
|
-
<
|
|
32
|
-
<View style={styles.
|
|
33
|
-
<
|
|
34
|
-
<Heading variant="h2">Messages</Heading>
|
|
35
|
-
</View>
|
|
36
|
-
{directMessagesEligible && (
|
|
37
|
-
<View style={styles.settingRow}>
|
|
38
|
-
<View style={styles.settingRowText}>
|
|
39
|
-
<Text>Allow direct messages</Text>
|
|
40
|
-
<Text variant="tertiary">
|
|
41
|
-
When off, you can't be added to new direct messages, and any you're already in
|
|
42
|
-
will be turned off.
|
|
43
|
-
</Text>
|
|
44
|
-
</View>
|
|
45
|
-
<Switch
|
|
46
|
-
value={!directMessagesDisabled}
|
|
47
|
-
onValueChange={enabled => setDirectMessagesDisabled(!enabled)}
|
|
48
|
-
disabled={isMutating}
|
|
49
|
-
/>
|
|
50
|
-
</View>
|
|
51
|
-
)}
|
|
52
|
-
<NavRow label="Notification settings" onPress={handleNotificationSettings} />
|
|
53
|
-
{appName !== 'services' && <NavRow label="Get help" onPress={handleGetHelp} />}
|
|
31
|
+
<View style={styles.sectionOuter}>
|
|
32
|
+
<View style={styles.sectionHeader}>
|
|
33
|
+
<Heading variant="h2">Messages</Heading>
|
|
54
34
|
</View>
|
|
55
|
-
|
|
35
|
+
{directMessagesEligible && (
|
|
36
|
+
<View style={styles.settingRow}>
|
|
37
|
+
<View style={styles.settingRowText}>
|
|
38
|
+
<Text>Allow direct messages</Text>
|
|
39
|
+
<Text variant="tertiary">
|
|
40
|
+
When off, you can't be added to new direct messages, and any you're already in will
|
|
41
|
+
be turned off.
|
|
42
|
+
</Text>
|
|
43
|
+
</View>
|
|
44
|
+
<Switch
|
|
45
|
+
value={!directMessagesDisabled}
|
|
46
|
+
onValueChange={enabled => setDirectMessagesDisabled(!enabled)}
|
|
47
|
+
disabled={isMutating}
|
|
48
|
+
/>
|
|
49
|
+
</View>
|
|
50
|
+
)}
|
|
51
|
+
<NavRow label="Notification settings" onPress={handleNotificationSettings} />
|
|
52
|
+
{appName !== 'services' && <NavRow label="Get help" onPress={handleGetHelp} />}
|
|
53
|
+
</View>
|
|
56
54
|
<View style={styles.footer}>
|
|
57
55
|
<VersionFooter />
|
|
58
56
|
</View>
|
|
@@ -92,6 +90,8 @@ const useStyles = () => {
|
|
|
92
90
|
flex: 1,
|
|
93
91
|
},
|
|
94
92
|
footer: {
|
|
93
|
+
flex: 1,
|
|
94
|
+
justifyContent: 'flex-end',
|
|
95
95
|
paddingBottom: Math.max(insets.bottom, 8),
|
|
96
96
|
},
|
|
97
97
|
sectionOuter: {
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { StaticParamList } from '@react-navigation/native';
|
|
2
|
-
import type { PageErrorFallback } from '../components/page/page_error_boundary';
|
|
3
|
-
import type { NewConversationStack } from './index';
|
|
4
|
-
type RouteName = keyof ReactNavigation.RootParamList | keyof StaticParamList<typeof NewConversationStack>;
|
|
5
|
-
export declare const PAGE_ERROR_FALLBACKS: Partial<Record<RouteName, PageErrorFallback>>;
|
|
6
|
-
export {};
|
|
7
|
-
//# sourceMappingURL=page_error_fallbacks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page_error_fallbacks.d.ts","sourceRoot":"","sources":["../../src/navigation/page_error_fallbacks.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAC/D,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wCAAwC,CAAA;AAC/E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAA;AAEnD,KAAK,SAAS,GACV,MAAM,eAAe,CAAC,aAAa,GACnC,MAAM,eAAe,CAAC,OAAO,oBAAoB,CAAC,CAAA;AAEtD,eAAO,MAAM,oBAAoB,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAK9E,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"page_error_fallbacks.js","names":["PAGE_ERROR_FALLBACKS","ConversationSelectDirectMessageRecipients","heading","body"],"sources":["../../src/navigation/page_error_fallbacks.ts"],"sourcesContent":["import type { StaticParamList } from '@react-navigation/native'\nimport type { PageErrorFallback } from '../components/page/page_error_boundary'\nimport type { NewConversationStack } from './index'\n\ntype RouteName =\n | keyof ReactNavigation.RootParamList\n | keyof StaticParamList<typeof NewConversationStack>\n\nexport const PAGE_ERROR_FALLBACKS: Partial<Record<RouteName, PageErrorFallback>> = {\n ConversationSelectDirectMessageRecipients: {\n heading: \"Couldn't load people right now\",\n body: 'Try again.',\n },\n}\n"],"mappings":"AAQA,OAAO,MAAMA,oBAAmE,GAAG;EACjFC,yCAAyC,EAAE;IACzCC,OAAO,EAAE,gCAAgC;IACzCC,IAAI,EAAE;EACR;AACF,CAAC","ignoreList":[]}
|