@planningcenter/chat-react-native 4.4.1-qa-staging.31 → 4.4.1-qa-staging.32

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 (34) hide show
  1. package/build/components/page/page_error_boundary.d.ts +9 -1
  2. package/build/components/page/page_error_boundary.d.ts.map +1 -1
  3. package/build/components/page/page_error_boundary.js +56 -31
  4. package/build/components/page/page_error_boundary.js.map +1 -1
  5. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts +1 -3
  6. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts.map +1 -1
  7. package/build/hooks/direct_messages/use_direct_message_candidates.js +29 -42
  8. package/build/hooks/direct_messages/use_direct_message_candidates.js.map +1 -1
  9. package/build/navigation/page_error_fallbacks.d.ts +7 -0
  10. package/build/navigation/page_error_fallbacks.d.ts.map +1 -0
  11. package/build/navigation/page_error_fallbacks.js +7 -0
  12. package/build/navigation/page_error_fallbacks.js.map +1 -0
  13. package/build/navigation/screenLayout.d.ts.map +1 -1
  14. package/build/navigation/screenLayout.js +10 -6
  15. package/build/navigation/screenLayout.js.map +1 -1
  16. package/build/screens/age_check/age_check_required_screen.d.ts.map +1 -1
  17. package/build/screens/age_check/age_check_required_screen.js +1 -0
  18. package/build/screens/age_check/age_check_required_screen.js.map +1 -1
  19. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -1
  20. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +168 -228
  21. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
  22. package/build/screens/search/components/search_results_list.d.ts.map +1 -1
  23. package/build/screens/search/components/search_results_list.js +82 -94
  24. package/build/screens/search/components/search_results_list.js.map +1 -1
  25. package/package.json +3 -3
  26. package/src/components/page/__tests__/page_error_boundary.test.tsx +33 -0
  27. package/src/components/page/page_error_boundary.tsx +43 -12
  28. package/src/hooks/direct_messages/use_direct_message_candidates.ts +2 -2
  29. package/src/navigation/page_error_fallbacks.ts +14 -0
  30. package/src/navigation/screenLayout.tsx +3 -1
  31. package/src/screens/age_check/age_check_required_screen.tsx +5 -1
  32. package/src/screens/conversation_select_recipients/__tests__/conversation_select_direct_message_recipients_screen.test.tsx +25 -8
  33. package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +7 -32
  34. package/src/screens/search/components/search_results_list.tsx +11 -11
@@ -1 +1 @@
1
- {"version":3,"file":"search_results_list.js","names":["React","useEffect","useRef","FlatList","StyleSheet","View","Banner","Spinner","Text","TextButton","useSearchResults","ConversationResults","MessageResultRow","ResultsSection","NoResultsBlankState","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","SEARCH_ERROR_MESSAGE","SearchResultsList","t0","$","_c","term","onSelect","onSettled","header","prompt","results","failedTypes","isPending","isError","isFetchNextPageError","loadMore","hasNextPage","isFetchingNextPage","t1","trim","searching","length","t2","filter","isConversationResult","conversationResults","t3","isMessageResult","messageResults","settled","settledTermRef","undefined","t4","t5","current","conversationResultCount","messageResultCount","t6","t7","item","item_0","index","onPress","t8","includes","SectionFailure","type","t9","title","t10","children","t11","t12","ListEmpty","noResults","t13","accessibilityLabel","style","styles","loading","t14","retry","t15","t16","t17","t18","keyExtractor","_temp","contentInsetAdjustmentBehavior","keyboardShouldPersistTaps","keyboardDismissMode","contentContainerStyle","content","renderItem","ListHeaderComponent","ListEmptyComponent","ListFooterComponent","onEndReached","onEndReachedThreshold","id","Symbol","for","appearance","banner","accessibilityRole","variant","sectionFailure","result","create","flexGrow","justifyContent","margin","alignItems","paddingVertical","alignSelf","fontSize","paddingHorizontal"],"sources":["../../../../src/screens/search/components/search_results_list.tsx"],"sourcesContent":["import React, { ReactElement, useEffect, useRef } from 'react'\nimport { FlatList, StyleSheet, View } from 'react-native'\nimport { Banner, Spinner, Text, TextButton } from '../../../components'\nimport { useSearchResults } from '../../../hooks/use_search_results'\nimport type {\n ConversationSearchResultResource,\n MessageSearchResultResource,\n SearchResultResource,\n} from '../../../types/resources/search_result'\nimport { ConversationResults } from './conversation_results'\nimport { MessageResultRow } from './message_result_row'\nimport { ResultsSection } from './results_section'\nimport { NoResultsBlankState } from './search_blank_states'\n\nconst SEARCH_ERROR_MESSAGE = \"Couldn't search right now. Try again.\"\n\nexport interface SearchResultCounts {\n conversationResultCount: number\n messageResultCount: number\n}\n\ninterface SearchResultsListProps {\n term: string\n onSelect: (result: SearchResultResource, position: number) => void\n onSettled: (term: string, counts: SearchResultCounts) => void\n header: ReactElement\n prompt: ReactElement\n}\n\nexport function SearchResultsList({\n term,\n onSelect,\n onSettled,\n header,\n prompt,\n}: SearchResultsListProps) {\n const {\n results,\n failedTypes,\n isPending,\n isError,\n isFetchNextPageError,\n loadMore,\n hasNextPage,\n isFetchingNextPage,\n } = useSearchResults(term)\n const searching = term.trim().length > 0\n const conversationResults = searching ? results.filter(isConversationResult) : []\n const messageResults = searching ? results.filter(isMessageResult) : []\n const settled = searching && !isPending && !isError\n\n const settledTermRef = useRef<string | undefined>(undefined)\n\n useEffect(() => {\n if (!settled || settledTermRef.current === term) return\n\n settledTermRef.current = term\n onSettled(term, {\n conversationResultCount: conversationResults.length,\n messageResultCount: messageResults.length,\n })\n }, [settled, term, conversationResults.length, messageResults.length, onSettled])\n\n return (\n <FlatList\n data={messageResults}\n keyExtractor={item => item.id}\n contentInsetAdjustmentBehavior=\"automatic\"\n keyboardShouldPersistTaps=\"handled\"\n keyboardDismissMode=\"on-drag\"\n contentContainerStyle={styles.content}\n renderItem={({ item, index }) => (\n <MessageResultRow result={item} onPress={() => onSelect(item, index)} />\n )}\n ListHeaderComponent={\n <>\n {header}\n {conversationResults.length > 0 && (\n <ConversationResults results={conversationResults} onSelect={onSelect} />\n )}\n {searching && failedTypes.includes('conversation') && (\n <SectionFailure type=\"conversation\" />\n )}\n {messageResults.length > 0 && <ResultsSection title=\"Messages\" />}\n </>\n }\n ListEmptyComponent={\n <ListEmpty\n term={term}\n prompt={prompt}\n isError={isError}\n isPending={isPending}\n noResults={results.length === 0 && failedTypes.length === 0}\n />\n }\n ListFooterComponent={\n <>\n {isFetchingNextPage && (\n <View accessibilityLabel=\"Loading more results\" style={styles.loading}>\n <Spinner />\n </View>\n )}\n {isFetchNextPageError && !isFetchingNextPage && (\n <TextButton onPress={loadMore} style={styles.retry}>\n Try again\n </TextButton>\n )}\n {searching && failedTypes.includes('message') && <SectionFailure type=\"message\" />}\n </>\n }\n onEndReached={() => {\n if (hasNextPage && !isFetchingNextPage && !isFetchNextPageError) loadMore()\n }}\n onEndReachedThreshold={0.5}\n />\n )\n}\n\ninterface ListEmptyProps {\n term: string\n prompt: ReactElement\n isError: boolean\n isPending: boolean\n noResults: boolean\n}\n\nfunction ListEmpty({ term, prompt, isError, isPending, noResults }: ListEmptyProps) {\n if (term.trim().length === 0) return <View style={styles.prompt}>{prompt}</View>\n\n if (isError) {\n return <Banner appearance=\"error\" description={SEARCH_ERROR_MESSAGE} style={styles.banner} />\n }\n\n if (isPending) {\n return (\n <View accessibilityLabel=\"Loading results\" style={styles.loading}>\n <Spinner />\n </View>\n )\n }\n\n if (noResults) return <NoResultsBlankState term={term} />\n\n return null\n}\n\nfunction SectionFailure({ type }: { type: SearchResultResource['type'] }) {\n return (\n <Text accessibilityRole=\"alert\" variant=\"secondary\" style={styles.sectionFailure}>\n Couldn&rsquo;t load {type}s.\n </Text>\n )\n}\n\nfunction isConversationResult(\n result: SearchResultResource\n): result is ConversationSearchResultResource {\n return result.type === 'conversation'\n}\n\nfunction isMessageResult(result: SearchResultResource): result is MessageSearchResultResource {\n return result.type === 'message'\n}\n\nconst styles = StyleSheet.create({\n content: {\n flexGrow: 1,\n },\n prompt: {\n flexGrow: 1,\n justifyContent: 'center',\n },\n banner: {\n margin: 16,\n },\n loading: {\n alignItems: 'center',\n paddingVertical: 16,\n },\n retry: {\n alignSelf: 'center',\n paddingVertical: 16,\n },\n sectionFailure: {\n fontSize: 14,\n paddingHorizontal: 16,\n paddingVertical: 8,\n },\n})\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"search_results_list.js","names":["React","useEffect","useRef","FlatList","StyleSheet","View","Banner","Spinner","Text","TextButton","useSearchResults","ConversationResults","MessageResultRow","ResultsSection","NoResultsBlankState","jsx","_jsx","Fragment","_Fragment","jsxs","_jsxs","SEARCH_ERROR_MESSAGE","SearchResultsList","t0","$","_c","term","onSelect","onSettled","header","prompt","results","failedTypes","isPending","isError","isFetchNextPageError","loadMore","hasNextPage","isFetchingNextPage","t1","trim","searching","length","t2","filter","isConversationResult","conversationResults","t3","isMessageResult","messageResults","settled","settledTermRef","undefined","t4","t5","current","conversationResultCount","messageResultCount","t6","t7","item","item_0","index","onPress","t8","includes","SectionFailure","type","t9","title","t10","children","t11","ListEmpty","noResults","style","styles","t12","accessibilityLabel","loading","t13","retry","t14","t15","t16","t17","keyExtractor","_temp","contentInsetAdjustmentBehavior","keyboardShouldPersistTaps","keyboardDismissMode","contentContainerStyle","content","renderItem","ListHeaderComponent","ListEmptyComponent","ListFooterComponent","onEndReached","onEndReachedThreshold","id","Symbol","for","appearance","banner","accessibilityRole","variant","sectionFailure","result","create","flexGrow","justifyContent","margin","alignItems","paddingVertical","alignSelf","fontSize","paddingHorizontal"],"sources":["../../../../src/screens/search/components/search_results_list.tsx"],"sourcesContent":["import React, { ReactElement, useEffect, useRef } from 'react'\nimport { FlatList, StyleSheet, View } from 'react-native'\nimport { Banner, Spinner, Text, TextButton } from '../../../components'\nimport { useSearchResults } from '../../../hooks/use_search_results'\nimport type {\n ConversationSearchResultResource,\n MessageSearchResultResource,\n SearchResultResource,\n} from '../../../types/resources/search_result'\nimport { ConversationResults } from './conversation_results'\nimport { MessageResultRow } from './message_result_row'\nimport { ResultsSection } from './results_section'\nimport { NoResultsBlankState } from './search_blank_states'\n\nconst SEARCH_ERROR_MESSAGE = \"Couldn't search right now. Try again.\"\n\nexport interface SearchResultCounts {\n conversationResultCount: number\n messageResultCount: number\n}\n\ninterface SearchResultsListProps {\n term: string\n onSelect: (result: SearchResultResource, position: number) => void\n onSettled: (term: string, counts: SearchResultCounts) => void\n header: ReactElement\n prompt: ReactElement\n}\n\nexport function SearchResultsList({\n term,\n onSelect,\n onSettled,\n header,\n prompt,\n}: SearchResultsListProps) {\n const {\n results,\n failedTypes,\n isPending,\n isError,\n isFetchNextPageError,\n loadMore,\n hasNextPage,\n isFetchingNextPage,\n } = useSearchResults(term)\n const searching = term.trim().length > 0\n const conversationResults = searching ? results.filter(isConversationResult) : []\n const messageResults = searching ? results.filter(isMessageResult) : []\n const settled = searching && !isPending && !isError\n\n const settledTermRef = useRef<string | undefined>(undefined)\n\n useEffect(() => {\n if (!settled || settledTermRef.current === term) return\n\n settledTermRef.current = term\n onSettled(term, {\n conversationResultCount: conversationResults.length,\n messageResultCount: messageResults.length,\n })\n }, [settled, term, conversationResults.length, messageResults.length, onSettled])\n\n return (\n <FlatList\n data={messageResults}\n keyExtractor={item => item.id}\n contentInsetAdjustmentBehavior=\"automatic\"\n keyboardShouldPersistTaps=\"handled\"\n keyboardDismissMode=\"on-drag\"\n contentContainerStyle={styles.content}\n renderItem={({ item, index }) => (\n <MessageResultRow result={item} onPress={() => onSelect(item, index)} />\n )}\n ListHeaderComponent={\n <>\n {header}\n {conversationResults.length > 0 && (\n <ConversationResults results={conversationResults} onSelect={onSelect} />\n )}\n {searching && failedTypes.includes('conversation') && (\n <SectionFailure type=\"conversation\" />\n )}\n {messageResults.length > 0 && <ResultsSection title=\"Messages\" />}\n </>\n }\n ListEmptyComponent={\n searching ? (\n <ListEmpty\n term={term}\n isError={isError}\n isPending={isPending}\n noResults={results.length === 0 && failedTypes.length === 0}\n />\n ) : (\n <View style={styles.prompt}>{prompt}</View>\n )\n }\n ListFooterComponent={\n <>\n {isFetchingNextPage && (\n <View accessibilityLabel=\"Loading more results\" style={styles.loading}>\n <Spinner />\n </View>\n )}\n {isFetchNextPageError && !isFetchingNextPage && (\n <TextButton onPress={loadMore} style={styles.retry}>\n Try again\n </TextButton>\n )}\n {searching && failedTypes.includes('message') && <SectionFailure type=\"message\" />}\n </>\n }\n onEndReached={() => {\n if (hasNextPage && !isFetchingNextPage && !isFetchNextPageError) loadMore()\n }}\n onEndReachedThreshold={0.5}\n />\n )\n}\n\ninterface ListEmptyProps {\n term: string\n isError: boolean\n isPending: boolean\n noResults: boolean\n}\n\nfunction ListEmpty({ term, isError, isPending, noResults }: ListEmptyProps) {\n if (isError) {\n return <Banner appearance=\"error\" description={SEARCH_ERROR_MESSAGE} style={styles.banner} />\n }\n\n if (isPending) {\n return (\n <View accessibilityLabel=\"Loading results\" style={styles.loading}>\n <Spinner />\n </View>\n )\n }\n\n if (noResults) return <NoResultsBlankState term={term} />\n\n return null\n}\n\nfunction SectionFailure({ type }: { type: SearchResultResource['type'] }) {\n return (\n <Text accessibilityRole=\"alert\" variant=\"secondary\" style={styles.sectionFailure}>\n Couldn&rsquo;t load {type}s.\n </Text>\n )\n}\n\nfunction isConversationResult(\n result: SearchResultResource\n): result is ConversationSearchResultResource {\n return result.type === 'conversation'\n}\n\nfunction isMessageResult(result: SearchResultResource): result is MessageSearchResultResource {\n return result.type === 'message'\n}\n\nconst styles = StyleSheet.create({\n content: {\n flexGrow: 1,\n },\n prompt: {\n flexGrow: 1,\n justifyContent: 'center',\n },\n banner: {\n margin: 16,\n },\n loading: {\n alignItems: 'center',\n paddingVertical: 16,\n },\n retry: {\n alignSelf: 'center',\n paddingVertical: 16,\n },\n sectionFailure: {\n fontSize: 14,\n paddingHorizontal: 16,\n paddingVertical: 8,\n },\n})\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "4.4.1-qa-staging.31",
3
+ "version": "4.4.1-qa-staging.32",
4
4
  "description": "",
5
5
  "repository": {
6
6
  "type": "git",
@@ -33,7 +33,7 @@
33
33
  "dependencies": {
34
34
  "@fortawesome/fontawesome-svg-core": "^7.2.0",
35
35
  "@fortawesome/react-native-fontawesome": "^0.3.2",
36
- "@planningcenter/emoji-keyboard": "4.4.1-qa-staging.31",
36
+ "@planningcenter/emoji-keyboard": "4.4.1-qa-staging.32",
37
37
  "lodash-inflection": "^1.5.0"
38
38
  },
39
39
  "peerDependencies": {
@@ -84,5 +84,5 @@
84
84
  "sf-symbols-typescript": "^2.2.0",
85
85
  "typescript": "~6.0.3"
86
86
  },
87
- "gitHead": "49bcabb80be23af0b7cc02eb64ebed1e53ab15ca"
87
+ "gitHead": "1f71f59f1f9f115d21df50180c264c62c79f2908"
88
88
  }
@@ -4,6 +4,7 @@ import { render } from '@testing-library/react-native'
4
4
  import React from 'react'
5
5
  import { buildTestQueryClient } from '../../../__utils__/query_client'
6
6
  import { Log } from '../../../utils/native_adapters/configuration'
7
+ import { ResponseError } from '../../../utils/response_error'
7
8
  import { PageErrorBoundary } from '../page_error_boundary'
8
9
 
9
10
  jest.mock('../../primitive/blank_state_primitive', () => {
@@ -74,4 +75,36 @@ describe('PageErrorBoundary', () => {
74
75
  expect(getByText('Oops!')).toBeTruthy()
75
76
  expect(getByText('Something unexpected happened.')).toBeTruthy()
76
77
  })
78
+
79
+ describe('with a generic fallback override', () => {
80
+ const genericFallback = { heading: 'Nothing here', body: 'Come back later.' }
81
+ const responseError = (status: number) =>
82
+ new ResponseError({ status, statusText: 'x', errors: [] } as never)
83
+
84
+ it.each([
85
+ ['a plain error', new Error('boom')],
86
+ ['an unhandled status', responseError(500)],
87
+ ])('replaces the Oops copy for %s', (_label, thrown) => {
88
+ const { getByText, queryByText } = renderWithProviders(
89
+ <PageErrorBoundary genericFallback={genericFallback}>
90
+ <Boom thrown={thrown} />
91
+ </PageErrorBoundary>
92
+ )
93
+
94
+ expect(getByText('Nothing here')).toBeTruthy()
95
+ expect(getByText('Come back later.')).toBeTruthy()
96
+ expect(queryByText('Oops!')).toBeNull()
97
+ })
98
+
99
+ it('leaves a known status alone', () => {
100
+ const { getByText, queryByText } = renderWithProviders(
101
+ <PageErrorBoundary genericFallback={genericFallback}>
102
+ <Boom thrown={responseError(403)} />
103
+ </PageErrorBoundary>
104
+ )
105
+
106
+ expect(getByText('Permission required')).toBeTruthy()
107
+ expect(queryByText('Nothing here')).toBeNull()
108
+ })
109
+ })
77
110
  })
@@ -6,11 +6,26 @@ import { ResponseError } from '../../utils/response_error'
6
6
  import BlankState from '../primitive/blank_state_primitive'
7
7
  import { ErrorBoundary, ErrorBoundaryFallback, ErrorBoundaryProps } from './error_boundary'
8
8
 
9
- const renderPageFallback: ErrorBoundaryFallback = (error, reset) => (
10
- <ErrorView error={error} reset={reset} />
11
- )
9
+ export type PageErrorFallback = { heading: string; body: string }
10
+
11
+ const GENERIC_FALLBACK: PageErrorFallback = {
12
+ heading: 'Oops!',
13
+ body: 'Something unexpected happened.',
14
+ }
15
+
16
+ type PageErrorBoundaryProps = PropsWithChildren<
17
+ ErrorBoundaryProps & { genericFallback?: PageErrorFallback }
18
+ >
19
+
20
+ export function PageErrorBoundary({
21
+ children,
22
+ genericFallback = GENERIC_FALLBACK,
23
+ ...props
24
+ }: PageErrorBoundaryProps) {
25
+ const renderPageFallback: ErrorBoundaryFallback = (error, reset) => (
26
+ <ErrorView error={error} reset={reset} generic={genericFallback} />
27
+ )
12
28
 
13
- export function PageErrorBoundary({ children, ...props }: PropsWithChildren<ErrorBoundaryProps>) {
14
29
  return (
15
30
  <ErrorBoundary scope="screen" fallback={renderPageFallback} {...props}>
16
31
  {children}
@@ -18,7 +33,15 @@ export function PageErrorBoundary({ children, ...props }: PropsWithChildren<Erro
18
33
  )
19
34
  }
20
35
 
21
- function ErrorView({ error, reset }: { error: Error; reset: () => void }) {
36
+ function ErrorView({
37
+ error,
38
+ reset,
39
+ generic,
40
+ }: {
41
+ error: Error
42
+ reset: () => void
43
+ generic: PageErrorFallback
44
+ }) {
22
45
  const { reset: resetQueries } = useQueryErrorResetBoundary()
23
46
 
24
47
  const handleReset = useCallback(() => {
@@ -29,7 +52,7 @@ function ErrorView({ error, reset }: { error: Error; reset: () => void }) {
29
52
  useEffect(() => handleReset, [handleReset])
30
53
 
31
54
  if (error instanceof ResponseError) {
32
- return <ResponseErrorView response={error.response} onReset={handleReset} />
55
+ return <ResponseErrorView response={error.response} onReset={handleReset} generic={generic} />
33
56
  }
34
57
 
35
58
  if (isNetworkError(error)) {
@@ -41,7 +64,7 @@ function ErrorView({ error, reset }: { error: Error; reset: () => void }) {
41
64
  )
42
65
  }
43
66
 
44
- return <ErrorContent heading={'Oops!'} body={'Something unexpected happened.'} />
67
+ return <ErrorContent heading={generic.heading} body={generic.body} />
45
68
  }
46
69
 
47
70
  function isNetworkError(error: Error) {
@@ -54,7 +77,15 @@ function isNetworkError(error: Error) {
54
77
  return new RegExp(networkFailedMessages.join('|'), 'i').test(error.message)
55
78
  }
56
79
 
57
- function ResponseErrorView({ response, onReset }: { response: Response; onReset: () => void }) {
80
+ function ResponseErrorView({
81
+ response,
82
+ onReset,
83
+ generic,
84
+ }: {
85
+ response: Response
86
+ onReset: () => void
87
+ generic: PageErrorFallback
88
+ }) {
58
89
  const { status } = response
59
90
 
60
91
  const heading = useMemo(() => {
@@ -64,9 +95,9 @@ function ResponseErrorView({ response, onReset }: { response: Response; onReset:
64
95
  case 404:
65
96
  return 'Content not found'
66
97
  default:
67
- return 'Oops!'
98
+ return generic.heading
68
99
  }
69
- }, [status])
100
+ }, [status, generic.heading])
70
101
 
71
102
  const body = useMemo(() => {
72
103
  switch (status) {
@@ -75,9 +106,9 @@ function ResponseErrorView({ response, onReset }: { response: Response; onReset:
75
106
  case 404:
76
107
  return 'If you believe something should be here, please reach out to your administrator.'
77
108
  default:
78
- return 'Something unexpected happened.'
109
+ return generic.body
79
110
  }
80
- }, [status])
111
+ }, [status, generic.body])
81
112
 
82
113
  useEffect(() => {
83
114
  if (status !== 401) return
@@ -3,7 +3,7 @@ import { ApiCollection } from '../../types'
3
3
  import { DirectMessageCandidateResource } from '../../types/resources/direct_message_candidate'
4
4
  import { useApiClient } from '../use_api_client'
5
5
 
6
- export function useDirectMessageCandidates(term: string, { throwOnError = true } = {}) {
6
+ export function useDirectMessageCandidates(term: string) {
7
7
  const apiClient = useApiClient()
8
8
  return useQuery({
9
9
  queryKey: ['chat', '/me/direct_message_candidates', term],
@@ -26,6 +26,6 @@ export function useDirectMessageCandidates(term: string, { throwOnError = true }
26
26
  }) as Promise<ApiCollection<DirectMessageCandidateResource>>,
27
27
  enabled: term.length >= 1,
28
28
  staleTime: 1000 * 60,
29
- throwOnError,
29
+ throwOnError: true,
30
30
  })
31
31
  }
@@ -0,0 +1,14 @@
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
+
5
+ type RouteName =
6
+ | keyof ReactNavigation.RootParamList
7
+ | keyof StaticParamList<typeof NewConversationStack>
8
+
9
+ export const PAGE_ERROR_FALLBACKS: Partial<Record<RouteName, PageErrorFallback>> = {
10
+ ConversationSelectDirectMessageRecipients: {
11
+ heading: "Couldn't load people right now",
12
+ body: 'Try again.',
13
+ },
14
+ }
@@ -4,12 +4,14 @@ import { Suspense } from 'react'
4
4
  import { DefaultLoading } from '../components/page/loading'
5
5
  import { PageErrorBoundary } from '../components/page/page_error_boundary'
6
6
  import { ChatAccessGate } from './chat_access_gate'
7
+ import { PAGE_ERROR_FALLBACKS } from './page_error_fallbacks'
7
8
 
8
9
  export function ScreenLayout({ children }: { children: React.ReactElement }) {
9
10
  const route = useRoute()
11
+ const genericFallback = PAGE_ERROR_FALLBACKS[route.name as keyof typeof PAGE_ERROR_FALLBACKS]
10
12
 
11
13
  return (
12
- <PageErrorBoundary screenName={route.name}>
14
+ <PageErrorBoundary screenName={route.name} genericFallback={genericFallback}>
13
15
  <Suspense fallback={<DefaultLoading />}>{children}</Suspense>
14
16
  </PageErrorBoundary>
15
17
  )
@@ -58,7 +58,11 @@ export function AgeCheckRequiredScreen() {
58
58
 
59
59
  return (
60
60
  <>
61
- <ScrollView style={styles.scrollView} contentContainerStyle={styles.container}>
61
+ <ScrollView
62
+ contentInsetAdjustmentBehavior="automatic"
63
+ style={styles.scrollView}
64
+ contentContainerStyle={styles.container}
65
+ >
62
66
  <View style={styles.header}>
63
67
  <View style={styles.heading}>
64
68
  <Icon name="general.exclamationTriangle" size={20} style={styles.warningIcon} />
@@ -1,12 +1,15 @@
1
1
  import { fireEvent, render } from '@testing-library/react-native'
2
2
  import React from 'react'
3
3
  import { SafeAreaProvider } from 'react-native-safe-area-context'
4
+ import { ScreenLayout } from '../../../navigation/screenLayout'
4
5
  import { Log } from '../../../utils/native_adapters/configuration'
6
+ import { ResponseError } from '../../../utils/response_error'
5
7
  import { ConversationSelectDirectMessageRecipientsScreen } from '../conversation_select_direct_message_recipients_screen'
6
8
 
7
9
  jest.mock('@react-navigation/native', () => ({
8
10
  ...jest.requireActual('@react-navigation/native'),
9
- useNavigation: () => ({ getParent: jest.fn() }),
11
+ useNavigation: () => ({ getParent: jest.fn(), goBack: jest.fn(), navigate: jest.fn() }),
12
+ useRoute: () => ({ name: 'ConversationSelectDirectMessageRecipients' }),
10
13
  }))
11
14
  jest.mock('../../../hooks/use_features', () => ({
12
15
  ...jest.requireActual('../../../hooks/use_features'),
@@ -33,10 +36,11 @@ jest.mock('../../../hooks/direct_messages/use_direct_message_affiliations', () =
33
36
  resultsDescription: null,
34
37
  }),
35
38
  }))
39
+ let mockSearchFailure: Error = new TypeError('Network request failed')
36
40
  jest.mock('../../../hooks/direct_messages/use_direct_message_candidates', () => ({
37
- useDirectMessageCandidates: (term: string, { throwOnError = true } = {}) => {
38
- if (term && throwOnError) throw new Error('Network request failed')
39
- return { data: undefined, isFetching: false, isError: term.length > 0 }
41
+ useDirectMessageCandidates: (term: string) => {
42
+ if (term) throw mockSearchFailure
43
+ return { data: undefined, isFetching: false }
40
44
  },
41
45
  }))
42
46
  jest.mock('../../../components/display/action_button', () => ({ ActionButton: () => null }))
@@ -53,7 +57,9 @@ const renderScreen = () =>
53
57
  insets: { top: 0, left: 0, right: 0, bottom: 0 },
54
58
  }}
55
59
  >
56
- <ConversationSelectDirectMessageRecipientsScreen route={{ params: {} } as never} />
60
+ <ScreenLayout>
61
+ <ConversationSelectDirectMessageRecipientsScreen route={{ params: {} } as never} />
62
+ </ScreenLayout>
57
63
  </SafeAreaProvider>
58
64
  )
59
65
 
@@ -71,13 +77,24 @@ describe('ConversationSelectDirectMessageRecipientsScreen', () => {
71
77
  consoleError.mockRestore()
72
78
  })
73
79
 
74
- it('reports a failed search and shows the banner while keeping the To field', () => {
80
+ it('hands a failed search to the page error view', () => {
81
+ mockSearchFailure = new TypeError('Network request failed')
75
82
  const view = renderScreen()
76
83
 
77
84
  fireEvent.changeText(view.getByPlaceholderText('Search'), 'pi')
78
85
 
79
- expect(view.getByText("Couldn't load people right now. Try again.")).toBeTruthy()
80
- expect(view.getByPlaceholderText('Search').props.value).toBe('pi')
86
+ expect(view.getByText('Problem connecting!')).toBeTruthy()
87
+ expect(view.queryByPlaceholderText('Search')).toBeNull()
81
88
  expect(reportError).toHaveBeenCalledTimes(1)
82
89
  })
90
+
91
+ it("uses the screen's own wording when the search fails for no known reason", () => {
92
+ mockSearchFailure = new ResponseError({ status: 500, statusText: 'x', errors: [] } as never)
93
+ const view = renderScreen()
94
+
95
+ fireEvent.changeText(view.getByPlaceholderText('Search'), 'pi')
96
+
97
+ expect(view.getByText("Couldn't load people right now")).toBeTruthy()
98
+ expect(view.queryByText('Oops!')).toBeNull()
99
+ })
83
100
  })
@@ -5,7 +5,6 @@ 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'
9
8
  import { useTheme } from '../../hooks'
10
9
  import { useDirectMessageAffiliations } from '../../hooks/direct_messages/use_direct_message_affiliations'
11
10
  import { useDirectMessageCandidates } from '../../hooks/direct_messages/use_direct_message_candidates'
@@ -215,13 +214,13 @@ function CandidateResults({
215
214
  header: ReactElement
216
215
  }) {
217
216
  const styles = useStyles()
218
- const { data, isFetching, isError } = useDirectMessageCandidates(term, { throwOnError: false })
217
+ const { data, isFetching } = useDirectMessageCandidates(term)
219
218
  const { groups, teams, resultsDescription } = useDirectMessageAffiliations()
220
219
 
221
220
  const unselectedCandidates = (data?.data ?? []).filter(c => !selectedPeople.has(c.id))
222
221
  const hasTruncated = (data?.meta.totalCount ?? 0) > (data?.data.length ?? 0)
223
222
  const isAtLimit = selectedPeople.size >= MAX_RECIPIENTS
224
- const showsResults = term.length >= 1 && !isAtLimit && !isError && unselectedCandidates.length > 0
223
+ const showsResults = term.length >= 1 && !isAtLimit && unselectedCandidates.length > 0
225
224
 
226
225
  const emptyState = (() => {
227
226
  if (showsResults) return null
@@ -240,23 +239,6 @@ function CandidateResults({
240
239
  )
241
240
  }
242
241
 
243
- if (isError) {
244
- return (
245
- <ComponentErrorBoundary
246
- key={term}
247
- fallback={
248
- <Banner
249
- appearance="error"
250
- description="Couldn't load people right now. Try again."
251
- style={styles.errorBanner}
252
- />
253
- }
254
- >
255
- <CandidateSearchError term={term} />
256
- </ComponentErrorBoundary>
257
- )
258
- }
259
-
260
242
  if (isAtLimit) {
261
243
  return (
262
244
  <View style={styles.emptyState}>
@@ -290,9 +272,8 @@ function CandidateResults({
290
272
  <CandidateList
291
273
  header={header}
292
274
  candidates={showsResults ? unselectedCandidates : []}
293
- hasTruncated={showsResults && hasTruncated}
294
- description={showsResults ? resultsDescription : null}
295
- showsHeading={showsResults}
275
+ hasTruncated={hasTruncated}
276
+ description={resultsDescription}
296
277
  emptyState={emptyState}
297
278
  groups={groups}
298
279
  teams={teams}
@@ -301,11 +282,6 @@ function CandidateResults({
301
282
  )
302
283
  }
303
284
 
304
- function CandidateSearchError({ term }: { term: string }) {
305
- useDirectMessageCandidates(term)
306
- return null
307
- }
308
-
309
285
  function candidateBadges(candidate: DirectMessageCandidateResource) {
310
286
  const badges = []
311
287
  if (candidate.directMessagesDisabled) badges.push({ title: 'DMs off' })
@@ -335,7 +311,6 @@ function CandidateList({
335
311
  candidates,
336
312
  hasTruncated,
337
313
  description,
338
- showsHeading,
339
314
  emptyState,
340
315
  groups,
341
316
  teams,
@@ -345,13 +320,13 @@ function CandidateList({
345
320
  candidates: DirectMessageCandidateResource[]
346
321
  hasTruncated: boolean
347
322
  description: string | null
348
- showsHeading: boolean
349
323
  emptyState: ReactElement | null
350
324
  groups: Map<number, string>
351
325
  teams: Map<number, string>
352
326
  onSelect: (candidate: DirectMessageCandidateResource) => void
353
327
  }) {
354
328
  const styles = useStyles()
329
+ const hasCandidates = candidates.length > 0
355
330
  const available = candidates.filter(c => !c.directMessagesDisabled)
356
331
  const dmDisabled = candidates.filter(c => c.directMessagesDisabled)
357
332
 
@@ -372,7 +347,7 @@ function CandidateList({
372
347
  ListHeaderComponent={
373
348
  <>
374
349
  {header}
375
- {showsHeading && <ResultsHeading description={description} />}
350
+ {hasCandidates && <ResultsHeading description={description} />}
376
351
  </>
377
352
  }
378
353
  ListEmptyComponent={emptyState}
@@ -396,7 +371,7 @@ function CandidateList({
396
371
  ))}
397
372
  </>
398
373
  )}
399
- {hasTruncated && (
374
+ {hasCandidates && hasTruncated && (
400
375
  <View style={styles.truncatedFooter}>
401
376
  <Text variant="secondary" style={styles.truncatedText}>
402
377
  Keep typing to narrow your results.
@@ -85,13 +85,16 @@ export function SearchResultsList({
85
85
  </>
86
86
  }
87
87
  ListEmptyComponent={
88
- <ListEmpty
89
- term={term}
90
- prompt={prompt}
91
- isError={isError}
92
- isPending={isPending}
93
- noResults={results.length === 0 && failedTypes.length === 0}
94
- />
88
+ searching ? (
89
+ <ListEmpty
90
+ term={term}
91
+ isError={isError}
92
+ isPending={isPending}
93
+ noResults={results.length === 0 && failedTypes.length === 0}
94
+ />
95
+ ) : (
96
+ <View style={styles.prompt}>{prompt}</View>
97
+ )
95
98
  }
96
99
  ListFooterComponent={
97
100
  <>
@@ -118,15 +121,12 @@ export function SearchResultsList({
118
121
 
119
122
  interface ListEmptyProps {
120
123
  term: string
121
- prompt: ReactElement
122
124
  isError: boolean
123
125
  isPending: boolean
124
126
  noResults: boolean
125
127
  }
126
128
 
127
- function ListEmpty({ term, prompt, isError, isPending, noResults }: ListEmptyProps) {
128
- if (term.trim().length === 0) return <View style={styles.prompt}>{prompt}</View>
129
-
129
+ function ListEmpty({ term, isError, isPending, noResults }: ListEmptyProps) {
130
130
  if (isError) {
131
131
  return <Banner appearance="error" description={SEARCH_ERROR_MESSAGE} style={styles.banner} />
132
132
  }