@planningcenter/chat-react-native 3.38.0-rc.0 → 3.38.0-rc.10
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 +10 -0
- package/build/components/conversation/message_list.d.ts.map +1 -0
- package/build/components/conversation/message_list.js +13 -0
- package/build/components/conversation/message_list.js.map +1 -0
- package/build/components/conversations/conversations.d.ts.map +1 -1
- package/build/components/conversations/conversations.js +6 -16
- package/build/components/conversations/conversations.js.map +1 -1
- package/build/components/conversations/conversations_blank_state.d.ts +8 -0
- package/build/components/conversations/conversations_blank_state.d.ts.map +1 -0
- package/build/components/conversations/conversations_blank_state.js +25 -0
- package/build/components/conversations/conversations_blank_state.js.map +1 -0
- package/build/components/display/conversation_avatar.d.ts +2 -1
- package/build/components/display/conversation_avatar.d.ts.map +1 -1
- package/build/components/display/conversation_avatar.js +6 -5
- package/build/components/display/conversation_avatar.js.map +1 -1
- package/build/components/display/emoji_avatar.d.ts +3 -1
- package/build/components/display/emoji_avatar.d.ts.map +1 -1
- package/build/components/display/emoji_avatar.js +2 -2
- package/build/components/display/emoji_avatar.js.map +1 -1
- package/build/components/display/icon_avatar.d.ts +3 -1
- package/build/components/display/icon_avatar.d.ts.map +1 -1
- package/build/components/display/icon_avatar.js +2 -2
- package/build/components/display/icon_avatar.js.map +1 -1
- package/build/hooks/groups/use_group_chat_conversation_payload.d.ts.map +1 -1
- package/build/hooks/groups/use_group_chat_conversation_payload.js +1 -0
- package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -1
- package/build/hooks/index.d.ts +1 -0
- package/build/hooks/index.d.ts.map +1 -1
- package/build/hooks/index.js +1 -0
- package/build/hooks/index.js.map +1 -1
- package/build/hooks/use_preview_avatar_diameter.d.ts +2 -0
- package/build/hooks/use_preview_avatar_diameter.d.ts.map +1 -0
- package/build/hooks/use_preview_avatar_diameter.js +11 -0
- package/build/hooks/use_preview_avatar_diameter.js.map +1 -0
- package/build/jest.js +1 -1
- package/build/jest.js.map +1 -1
- package/build/screens/age_check/age_check_underage_screen.js +1 -1
- package/build/screens/age_check/age_check_underage_screen.js.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.js +11 -9
- package/build/screens/avatar_picker/avatar_picker_screen.js.map +1 -1
- package/build/screens/avatar_picker/avatar_preview.d.ts.map +1 -1
- package/build/screens/avatar_picker/avatar_preview.js +13 -5
- package/build/screens/avatar_picker/avatar_preview.js.map +1 -1
- package/build/screens/avatar_picker/emoji_tab.d.ts.map +1 -1
- package/build/screens/avatar_picker/emoji_tab.js +3 -7
- package/build/screens/avatar_picker/emoji_tab.js.map +1 -1
- package/build/screens/avatar_picker/upload_tab.d.ts.map +1 -1
- package/build/screens/avatar_picker/upload_tab.js +2 -1
- package/build/screens/avatar_picker/upload_tab.js.map +1 -1
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +5 -2
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/components/header_row.js +3 -2
- package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +47 -18
- package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +2 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +23 -26
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts +1 -1
- package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/types.js.map +1 -1
- package/build/screens/conversation_screen.d.ts.map +1 -1
- package/build/screens/conversation_screen.js +3 -7
- package/build/screens/conversation_screen.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js +3 -3
- package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.d.ts.map +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.js +1 -1
- package/build/screens/conversation_select_recipients/components/team_recipient_row.js.map +1 -1
- package/build/screens/team_conversation_screen.d.ts.map +1 -1
- package/build/screens/team_conversation_screen.js +24 -1
- package/build/screens/team_conversation_screen.js.map +1 -1
- package/build/utils/client/client.d.ts +1 -1
- package/build/utils/client/client.d.ts.map +1 -1
- package/build/utils/client/client.js +7 -6
- package/build/utils/client/client.js.map +1 -1
- package/build/utils/client/instrumented_fetch.js +3 -5
- package/build/utils/client/instrumented_fetch.js.map +1 -1
- package/package.json +4 -4
- package/src/__tests__/hooks/use_group_chat_conversation_payload.test.tsx +50 -0
- package/src/__tests__/jest.ts +1 -1
- package/src/__tests__/utils/client.ts +32 -0
- package/src/components/conversation/__tests__/message_list.test.tsx +14 -0
- package/src/components/conversation/message_list.tsx +42 -0
- package/src/components/conversations/conversations.tsx +9 -16
- package/src/components/conversations/conversations_blank_state.tsx +42 -0
- package/src/components/display/conversation_avatar.tsx +7 -5
- package/src/components/display/emoji_avatar.tsx +10 -2
- package/src/components/display/icon_avatar.tsx +10 -2
- package/src/hooks/groups/use_group_chat_conversation_payload.ts +1 -0
- package/src/hooks/index.ts +1 -0
- package/src/hooks/use_preview_avatar_diameter.ts +12 -0
- package/src/jest.ts +1 -1
- package/src/screens/age_check/age_check_underage_screen.tsx +1 -1
- package/src/screens/avatar_picker/avatar_picker_screen.tsx +25 -9
- package/src/screens/avatar_picker/avatar_preview.tsx +14 -5
- package/src/screens/avatar_picker/emoji_tab.tsx +3 -6
- package/src/screens/avatar_picker/upload_tab.tsx +2 -0
- package/src/screens/conversation_details_screen.tsx +10 -1
- package/src/screens/conversation_filter_recipients/components/header_row.tsx +3 -2
- package/src/screens/conversation_filter_recipients/hooks/__tests__/use_service_types_with_teams.test.ts +108 -0
- package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +46 -19
- package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +31 -29
- package/src/screens/conversation_filter_recipients/types.tsx +1 -1
- package/src/screens/conversation_screen.tsx +5 -14
- package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +6 -4
- package/src/screens/conversation_select_recipients/components/team_recipient_row.tsx +2 -1
- package/src/screens/team_conversation_screen.tsx +33 -1
- package/src/utils/client/__tests__/instrumented_fetch.test.ts +9 -5
- package/src/utils/client/client.ts +9 -7
- package/src/utils/client/instrumented_fetch.ts +3 -6
|
@@ -11,7 +11,7 @@ interface RecipientLinkRowProps {
|
|
|
11
11
|
accessibilityHint: string
|
|
12
12
|
imageUri?: string
|
|
13
13
|
title: string
|
|
14
|
-
subtitle
|
|
14
|
+
subtitle?: string
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
export const RecipientLinkRow = ({
|
|
@@ -40,9 +40,11 @@ export const RecipientLinkRow = ({
|
|
|
40
40
|
<Text style={styles.title} numberOfLines={2}>
|
|
41
41
|
{title}
|
|
42
42
|
</Text>
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
43
|
+
{subtitle && (
|
|
44
|
+
<Text variant="tertiary" numberOfLines={1}>
|
|
45
|
+
{subtitle}
|
|
46
|
+
</Text>
|
|
47
|
+
)}
|
|
46
48
|
</View>
|
|
47
49
|
{Platform.OS === 'ios' && (
|
|
48
50
|
<Icon name="general.rightChevron" size={16} style={styles.icon} />
|
|
@@ -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 =
|
|
12
|
+
const teamNames =
|
|
13
|
+
serviceType.id > 0 ? serviceType.teams.map(team => team.name).join(', ') : undefined
|
|
13
14
|
|
|
14
15
|
return (
|
|
15
16
|
<RecipientLinkRow
|
|
@@ -2,8 +2,10 @@ import { StackActions, StaticScreenProps, useNavigation } from '@react-navigatio
|
|
|
2
2
|
import { useQuery, useQueryClient } from '@tanstack/react-query'
|
|
3
3
|
import { useEffect } from 'react'
|
|
4
4
|
import { DefaultLoading } from '../components/page/loading'
|
|
5
|
+
import BlankState from '../components/primitive/blank_state_primitive'
|
|
5
6
|
import { useApiClient } from '../hooks'
|
|
6
7
|
import { findOrCreateServicesConversation } from '../hooks/services/use_find_or_create_services_conversation'
|
|
8
|
+
import { ResponseError } from '../utils/response_error'
|
|
7
9
|
|
|
8
10
|
export type TeamConversationRouteProps = {
|
|
9
11
|
plan_id?: number
|
|
@@ -16,7 +18,11 @@ export const TeamConversationScreen = ({ route }: TeamConversationScreenProps) =
|
|
|
16
18
|
const apiClient = useApiClient()
|
|
17
19
|
const queryClient = useQueryClient()
|
|
18
20
|
const navigation = useNavigation()
|
|
19
|
-
const {
|
|
21
|
+
const {
|
|
22
|
+
data: conversation,
|
|
23
|
+
isError,
|
|
24
|
+
error,
|
|
25
|
+
} = useQuery({
|
|
20
26
|
queryKey: ['team-conversation', route.params.team_ids, route.params.plan_id],
|
|
21
27
|
queryFn: () =>
|
|
22
28
|
findOrCreateServicesConversation({
|
|
@@ -24,6 +30,7 @@ export const TeamConversationScreen = ({ route }: TeamConversationScreenProps) =
|
|
|
24
30
|
teamIds: route.params.team_ids ?? [],
|
|
25
31
|
planId: route.params.plan_id,
|
|
26
32
|
}).then(r => r.conversation),
|
|
33
|
+
retry: (failureCount, err) => !(err instanceof ResponseError) && failureCount < 3,
|
|
27
34
|
})
|
|
28
35
|
|
|
29
36
|
useEffect(() => {
|
|
@@ -41,5 +48,30 @@ export const TeamConversationScreen = ({ route }: TeamConversationScreenProps) =
|
|
|
41
48
|
}
|
|
42
49
|
}, [conversation?.id, conversation?.title, navigation, queryClient])
|
|
43
50
|
|
|
51
|
+
if (isError) return <TeamConversationError error={error} onGoBack={navigation.goBack} />
|
|
52
|
+
|
|
44
53
|
return <DefaultLoading />
|
|
45
54
|
}
|
|
55
|
+
|
|
56
|
+
function TeamConversationError({ error, onGoBack }: { error: Error; onGoBack: () => void }) {
|
|
57
|
+
const detail =
|
|
58
|
+
error instanceof ResponseError
|
|
59
|
+
? error.errors
|
|
60
|
+
.map(e => e.detail)
|
|
61
|
+
.filter(Boolean)
|
|
62
|
+
.join('\n')
|
|
63
|
+
: ''
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
<BlankState.Root>
|
|
67
|
+
<BlankState.Imagery name="people.noTextMessage" />
|
|
68
|
+
<BlankState.Content>
|
|
69
|
+
<BlankState.Heading>Can't start this conversation</BlankState.Heading>
|
|
70
|
+
<BlankState.Text>
|
|
71
|
+
{detail || 'Something went wrong while starting this conversation.'}
|
|
72
|
+
</BlankState.Text>
|
|
73
|
+
</BlankState.Content>
|
|
74
|
+
<BlankState.Button title="Go back" onPress={onGoBack} size="md" accessibilityRole="link" />
|
|
75
|
+
</BlankState.Root>
|
|
76
|
+
)
|
|
77
|
+
}
|
|
@@ -5,15 +5,18 @@ const buildResponse = (status: number) => new Response('', { status })
|
|
|
5
5
|
|
|
6
6
|
describe('instrumentedFetch', () => {
|
|
7
7
|
let reportError: jest.SpyInstance
|
|
8
|
+
let warnSpy: jest.SpyInstance
|
|
8
9
|
let fetchSpy: jest.SpyInstance
|
|
9
10
|
|
|
10
11
|
beforeEach(() => {
|
|
11
12
|
reportError = jest.spyOn(Log, 'reportError').mockImplementation(() => {})
|
|
13
|
+
warnSpy = jest.spyOn(console, 'warn').mockImplementation(() => {})
|
|
12
14
|
fetchSpy = jest.spyOn(globalThis, 'fetch')
|
|
13
15
|
})
|
|
14
16
|
|
|
15
17
|
afterEach(() => {
|
|
16
18
|
reportError.mockRestore()
|
|
19
|
+
warnSpy.mockRestore()
|
|
17
20
|
fetchSpy.mockRestore()
|
|
18
21
|
})
|
|
19
22
|
|
|
@@ -27,6 +30,7 @@ describe('instrumentedFetch', () => {
|
|
|
27
30
|
|
|
28
31
|
expect(result).toBe(response)
|
|
29
32
|
expect(reportError).not.toHaveBeenCalled()
|
|
33
|
+
expect(warnSpy).not.toHaveBeenCalled()
|
|
30
34
|
})
|
|
31
35
|
|
|
32
36
|
it.each([400, 422, 500])(
|
|
@@ -63,7 +67,7 @@ describe('instrumentedFetch', () => {
|
|
|
63
67
|
expect(reportError).not.toHaveBeenCalled()
|
|
64
68
|
})
|
|
65
69
|
|
|
66
|
-
it('
|
|
70
|
+
it('warns on network failures instead of reporting them', async () => {
|
|
67
71
|
const networkError = new TypeError('Network request failed')
|
|
68
72
|
fetchSpy.mockRejectedValueOnce(networkError)
|
|
69
73
|
|
|
@@ -71,10 +75,10 @@ describe('instrumentedFetch', () => {
|
|
|
71
75
|
instrumentedFetch('https://api.example.com/conversations/123', { method: 'GET' })
|
|
72
76
|
).rejects.toBe(networkError)
|
|
73
77
|
|
|
74
|
-
expect(reportError).
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
expect(
|
|
78
|
+
expect(reportError).not.toHaveBeenCalled()
|
|
79
|
+
expect(warnSpy).toHaveBeenCalledTimes(1)
|
|
80
|
+
const [message, context] = warnSpy.mock.calls[0]
|
|
81
|
+
expect(message).toContain('Network failure GET /conversations/:id')
|
|
78
82
|
expect(context.tags).toMatchObject({
|
|
79
83
|
'http.method': 'GET',
|
|
80
84
|
'http.path': '/conversations/:id',
|
|
@@ -105,16 +105,18 @@ export class Client {
|
|
|
105
105
|
return makeRequest(requestArgs).catch(this.handleNotOk)
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
handleNotOk = async (response: Response) => {
|
|
108
|
+
handleNotOk = async (response: Response | Error) => {
|
|
109
|
+
if (!(response instanceof Response)) return Promise.reject(response)
|
|
110
|
+
|
|
111
|
+
const errorData = await this.parseErrorResponse(response)
|
|
112
|
+
const notOkResponse = response.clone() as FailedResponse
|
|
113
|
+
notOkResponse.errors = errorData.errors || []
|
|
114
|
+
|
|
109
115
|
if (response.status === 401) {
|
|
110
|
-
|
|
111
|
-
this.onUnauthorizedResponse?.({
|
|
112
|
-
...response,
|
|
113
|
-
errors: errorData.errors || [],
|
|
114
|
-
} as FailedResponse)
|
|
116
|
+
this.onUnauthorizedResponse?.(notOkResponse)
|
|
115
117
|
}
|
|
116
118
|
|
|
117
|
-
return Promise.reject(
|
|
119
|
+
return Promise.reject(notOkResponse)
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
parseErrorResponse = async (response: Response): Promise<Partial<FailedResponse>> => {
|
|
@@ -14,7 +14,7 @@ export async function instrumentedFetch(url: string, init: RequestInit): Promise
|
|
|
14
14
|
if (!response.ok) reportHttpError(response, method, url)
|
|
15
15
|
return response
|
|
16
16
|
} catch (networkError) {
|
|
17
|
-
|
|
17
|
+
warnNetworkError(networkError as Error, method, url)
|
|
18
18
|
throw networkError
|
|
19
19
|
}
|
|
20
20
|
}
|
|
@@ -38,12 +38,9 @@ function reportHttpError(response: Response, method: string, url: string) {
|
|
|
38
38
|
})
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
function
|
|
41
|
+
function warnNetworkError(networkError: Error, method: string, url: string) {
|
|
42
42
|
const path = templatePath(url)
|
|
43
|
-
|
|
44
|
-
error.name = 'NetworkError'
|
|
45
|
-
|
|
46
|
-
Log.reportError(error, {
|
|
43
|
+
console.warn(`Network failure ${method} ${path}: ${networkError.message}`, {
|
|
47
44
|
scope: 'http',
|
|
48
45
|
tags: {
|
|
49
46
|
...SHARED_TAGS,
|