@planningcenter/chat-react-native 3.15.0-rc.8 → 3.15.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.
- package/build/components/display/icon.d.ts +26 -13
- package/build/components/display/icon.d.ts.map +1 -1
- package/build/components/display/icon.js +0 -12
- package/build/components/display/icon.js.map +1 -1
- package/build/hooks/use_app_name.d.ts +3 -0
- package/build/hooks/use_app_name.d.ts.map +1 -0
- package/build/hooks/use_app_name.js +12 -0
- package/build/hooks/use_app_name.js.map +1 -0
- package/build/hooks/use_report_bug_action.d.ts +1 -1
- package/build/hooks/use_report_bug_action.d.ts.map +1 -1
- package/build/hooks/use_report_bug_action.js +1 -9
- package/build/hooks/use_report_bug_action.js.map +1 -1
- package/build/navigation/index.d.ts +20 -5
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +23 -15
- package/build/navigation/index.js.map +1 -1
- package/build/screens/bug_report_screen.d.ts.map +1 -1
- package/build/screens/bug_report_screen.js +62 -57
- package/build/screens/bug_report_screen.js.map +1 -1
- package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
- package/build/screens/conversations/conversations_screen.js +6 -6
- package/build/screens/conversations/conversations_screen.js.map +1 -1
- package/build/screens/design_system_screen.js +1 -1
- package/build/screens/design_system_screen.js.map +1 -1
- package/build/screens/get_help_screen.d.ts +5 -0
- package/build/screens/get_help_screen.d.ts.map +1 -0
- package/build/screens/get_help_screen.js +94 -0
- package/build/screens/get_help_screen.js.map +1 -0
- package/package.json +2 -2
- package/src/components/display/icon.tsx +17 -14
- package/src/hooks/use_app_name.ts +17 -0
- package/src/hooks/use_report_bug_action.ts +2 -10
- package/src/navigation/index.tsx +38 -25
- package/src/screens/bug_report_screen.tsx +79 -67
- package/src/screens/conversations/conversations_screen.tsx +7 -7
- package/src/screens/design_system_screen.tsx +1 -1
- package/src/screens/get_help_screen.tsx +131 -0
|
@@ -5,29 +5,17 @@ import { SvgXml } from 'react-native-svg'
|
|
|
5
5
|
import type { XmlProps } from 'react-native-svg'
|
|
6
6
|
import { useFontScale, useTheme } from '../../hooks'
|
|
7
7
|
|
|
8
|
-
// @ts-ignore
|
|
9
8
|
import * as accounts from '@planningcenter/icons/paths/accounts'
|
|
10
|
-
// @ts-ignore
|
|
11
9
|
import * as api from '@planningcenter/icons/paths/api'
|
|
12
|
-
// @ts-ignore
|
|
13
10
|
import * as brand from '@planningcenter/icons/paths/brand'
|
|
14
|
-
// @ts-ignore
|
|
15
11
|
import * as calendar from '@planningcenter/icons/paths/calendar'
|
|
16
|
-
// @ts-ignore
|
|
17
12
|
import * as chat from '@planningcenter/icons/paths/chat'
|
|
18
|
-
// @ts-ignore
|
|
19
13
|
import * as churchCenter from '@planningcenter/icons/paths/church-center'
|
|
20
|
-
// @ts-ignore
|
|
21
14
|
import * as general from '@planningcenter/icons/paths/general'
|
|
22
|
-
// @ts-ignore
|
|
23
15
|
import * as groups from '@planningcenter/icons/paths/groups'
|
|
24
|
-
// @ts-ignore
|
|
25
16
|
import * as logomark from '@planningcenter/icons/paths/logomark'
|
|
26
|
-
// @ts-ignore
|
|
27
17
|
import * as people from '@planningcenter/icons/paths/people'
|
|
28
|
-
// @ts-ignore
|
|
29
18
|
import * as services from '@planningcenter/icons/paths/services'
|
|
30
|
-
// @ts-ignore
|
|
31
19
|
import * as publishing from '@planningcenter/icons/paths/publishing'
|
|
32
20
|
|
|
33
21
|
// =================================
|
|
@@ -57,7 +45,22 @@ export type IconStyle = ViewStyle & {
|
|
|
57
45
|
}
|
|
58
46
|
|
|
59
47
|
export type IconSetName = keyof typeof ICONS
|
|
60
|
-
|
|
48
|
+
|
|
49
|
+
type IconName<T extends IconSetName> = keyof (typeof ICONS)[T] & string
|
|
50
|
+
|
|
51
|
+
export type IconString =
|
|
52
|
+
| `accounts.${IconName<'accounts'>}`
|
|
53
|
+
| `api.${IconName<'api'>}`
|
|
54
|
+
| `brand.${IconName<'brand'>}`
|
|
55
|
+
| `calendar.${IconName<'calendar'>}`
|
|
56
|
+
| `chat.${IconName<'chat'>}`
|
|
57
|
+
| `churchCenter.${IconName<'churchCenter'>}`
|
|
58
|
+
| `general.${IconName<'general'>}`
|
|
59
|
+
| `groups.${IconName<'groups'>}`
|
|
60
|
+
| `logomark.${IconName<'logomark'>}`
|
|
61
|
+
| `people.${IconName<'people'>}`
|
|
62
|
+
| `services.${IconName<'services'>}`
|
|
63
|
+
| `publishing.${IconName<'publishing'>}`
|
|
61
64
|
|
|
62
65
|
// =================================
|
|
63
66
|
// ====== Component ================
|
|
@@ -137,7 +140,7 @@ const useGetIconSize = (size?: number, style?: IconStyle, maxFontSizeMultiplier?
|
|
|
137
140
|
const getIconPath = (name: IconString): string => {
|
|
138
141
|
const [setName, iconName] = name.split('.')
|
|
139
142
|
|
|
140
|
-
return ICONS[setName as IconSetName]?.[iconName]
|
|
143
|
+
return (ICONS[setName as IconSetName] as Record<string, string>)?.[iconName]
|
|
141
144
|
}
|
|
142
145
|
|
|
143
146
|
// =================================
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import DeviceInfo from 'react-native-device-info'
|
|
2
|
+
|
|
3
|
+
export type AppName = 'chat' | 'churchcenter' | 'services'
|
|
4
|
+
|
|
5
|
+
export const useAppName = (): AppName => {
|
|
6
|
+
const applicationName = DeviceInfo.getApplicationName()
|
|
7
|
+
|
|
8
|
+
if (/churchcenter/i.test(applicationName)) {
|
|
9
|
+
return 'churchcenter'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (/services/i.test(applicationName)) {
|
|
13
|
+
return 'services'
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
return 'chat'
|
|
17
|
+
}
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { useMutation } from '@tanstack/react-query'
|
|
2
2
|
import { useApiClient } from './use_api_client'
|
|
3
|
-
import DeviceInfo from 'react-native-device-info'
|
|
4
|
-
const brand = DeviceInfo.getBrand()
|
|
5
|
-
const model = DeviceInfo.getModel()
|
|
6
|
-
const systemName = DeviceInfo.getSystemName()
|
|
7
|
-
const systemVersion = DeviceInfo.getSystemVersion()
|
|
8
|
-
const readableVersion = DeviceInfo.getReadableVersion()
|
|
9
|
-
const appName = DeviceInfo.getApplicationName()
|
|
10
3
|
|
|
11
4
|
export const useReportBugAction = () => {
|
|
12
5
|
const apiClient = useApiClient()
|
|
@@ -18,7 +11,7 @@ export const useReportBugAction = () => {
|
|
|
18
11
|
attachmentIds,
|
|
19
12
|
}: {
|
|
20
13
|
description: string
|
|
21
|
-
description_json: string
|
|
14
|
+
description_json: Record<string, any>
|
|
22
15
|
attachmentIds: string[]
|
|
23
16
|
}) => {
|
|
24
17
|
return apiClient.chat.post({
|
|
@@ -28,8 +21,7 @@ export const useReportBugAction = () => {
|
|
|
28
21
|
type: '',
|
|
29
22
|
attributes: {
|
|
30
23
|
description,
|
|
31
|
-
description_json,
|
|
32
|
-
device_info: `${appName}/${readableVersion} (${brand}, ${model}, ${systemName}, ${systemVersion})`,
|
|
24
|
+
description_json: JSON.stringify(description_json),
|
|
33
25
|
attachment_ids: attachmentIds,
|
|
34
26
|
},
|
|
35
27
|
},
|
package/src/navigation/index.tsx
CHANGED
|
@@ -4,47 +4,50 @@ import {
|
|
|
4
4
|
createNativeStackNavigator,
|
|
5
5
|
NativeStackHeaderRightProps,
|
|
6
6
|
} from '@react-navigation/native-stack'
|
|
7
|
+
import { CardStyleInterpolators } from '@react-navigation/stack'
|
|
7
8
|
import React from 'react'
|
|
9
|
+
import { Platform } from 'react-native'
|
|
8
10
|
import { Icon } from '../components'
|
|
11
|
+
import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
|
|
12
|
+
import {
|
|
13
|
+
AttachmentActionsScreen,
|
|
14
|
+
AttachmentActionsScreenOptions,
|
|
15
|
+
} from '../screens/attachment_actions/attachment_actions_screen'
|
|
16
|
+
import { BugReportScreen, BugReportScreenOptions } from '../screens/bug_report_screen'
|
|
17
|
+
import {
|
|
18
|
+
MessageReadReceiptsScreen,
|
|
19
|
+
MessageReadReceiptsScreenOptions,
|
|
20
|
+
} from '../screens/conversation/message_read_receipts_screen'
|
|
9
21
|
import { ConversationDetailsScreen } from '../screens/conversation_details_screen'
|
|
22
|
+
import {
|
|
23
|
+
ConversationFilterReceipientsScreenOptions,
|
|
24
|
+
ConversationFilterRecipientsScreen,
|
|
25
|
+
} from '../screens/conversation_filter_recipients/conversation_filter_recipients_screen'
|
|
26
|
+
import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
|
|
27
|
+
import {
|
|
28
|
+
ConversationFiltersScreen,
|
|
29
|
+
ConversationFiltersScreenOptions,
|
|
30
|
+
} from '../screens/conversation_filters_screen'
|
|
31
|
+
import { ConversationNewScreen } from '../screens/conversation_new/conversation_new_screen'
|
|
10
32
|
import {
|
|
11
33
|
ConversationRouteProps,
|
|
12
34
|
ConversationScreen,
|
|
13
35
|
ConversationScreenTitle,
|
|
14
36
|
} from '../screens/conversation_screen'
|
|
15
|
-
import {
|
|
16
|
-
import { ConversationNewScreen } from '../screens/conversation_new/conversation_new_screen'
|
|
17
|
-
import {
|
|
18
|
-
ConversationFilterReceipientsScreenOptions,
|
|
19
|
-
ConversationFilterRecipientsScreen,
|
|
20
|
-
} from '../screens/conversation_filter_recipients/conversation_filter_recipients_screen'
|
|
37
|
+
import { ConversationSelectGroupRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_group_recipients_screen'
|
|
21
38
|
import { ConversationSelectRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_recipients_screen'
|
|
39
|
+
import { ConversationSelectTeamsILeadRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
|
|
40
|
+
import { ConversationsScreen } from '../screens/conversations/conversations_screen'
|
|
41
|
+
import { GetHelpScreen } from '../screens/get_help_screen'
|
|
22
42
|
import {
|
|
23
43
|
MessageActionsScreen,
|
|
24
44
|
MessageActionsScreenOptions,
|
|
25
45
|
} from '../screens/message_actions_screen'
|
|
26
|
-
import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
|
|
27
46
|
import { NotFound } from '../screens/not_found'
|
|
28
47
|
import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
|
|
29
|
-
import {
|
|
30
|
-
import {
|
|
31
|
-
ConversationFiltersScreen,
|
|
32
|
-
ConversationFiltersScreenOptions,
|
|
33
|
-
} from '../screens/conversation_filters_screen'
|
|
34
|
-
import { ConversationFiltersParams } from '../screens/conversation_filters/screen_props'
|
|
35
|
-
import { ConversationSelectGroupRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_group_recipients_screen'
|
|
36
|
-
import { ConversationSelectTeamsILeadRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
|
|
37
|
-
import { AttachmentActionsScreenOptions } from '../screens/attachment_actions/attachment_actions_screen'
|
|
38
|
-
import { AttachmentActionsScreen } from '../screens/attachment_actions/attachment_actions_screen'
|
|
39
|
-
import { BugReportScreen, BugReportScreenOptions } from '../screens/bug_report_screen'
|
|
40
|
-
import {
|
|
41
|
-
MessageReadReceiptsScreen,
|
|
42
|
-
MessageReadReceiptsScreenOptions,
|
|
43
|
-
} from '../screens/conversation/message_read_receipts_screen'
|
|
44
|
-
import { Platform } from 'react-native'
|
|
45
|
-
import { HeaderTextButton } from '../components/display/platform_modal_header_buttons'
|
|
48
|
+
import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
|
|
46
49
|
import { TeamConversationScreen } from '../screens/team_conversation_screen'
|
|
47
|
-
import {
|
|
50
|
+
import { ScreenLayout } from './screenLayout'
|
|
48
51
|
|
|
49
52
|
const HEADER_BACK_BUTTON_LAYOUT_RESET_STYLES = {
|
|
50
53
|
marginLeft: Platform.select({ ios: -8, default: -3 }),
|
|
@@ -231,6 +234,16 @@ export const ChatStack = createNativeStackNavigator({
|
|
|
231
234
|
screen: BugReportScreen,
|
|
232
235
|
options: BugReportScreenOptions,
|
|
233
236
|
},
|
|
237
|
+
GetHelp: {
|
|
238
|
+
screen: GetHelpScreen,
|
|
239
|
+
options: ({ navigation }) => ({
|
|
240
|
+
headerTitle: 'Get help',
|
|
241
|
+
presentation: 'modal',
|
|
242
|
+
headerLeft: props => (
|
|
243
|
+
<HeaderTextButton {...props} onPress={navigation.goBack} title="Close" />
|
|
244
|
+
),
|
|
245
|
+
}),
|
|
246
|
+
},
|
|
234
247
|
NotFound: {
|
|
235
248
|
screen: NotFound,
|
|
236
249
|
options: {
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import React, { useCallback, useLayoutEffect, useState } from 'react'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
View,
|
|
4
|
+
StyleSheet,
|
|
5
|
+
TextInput,
|
|
6
|
+
Linking,
|
|
7
|
+
ScrollView,
|
|
8
|
+
TouchableOpacity,
|
|
9
|
+
Platform,
|
|
10
|
+
} from 'react-native'
|
|
3
11
|
import type {
|
|
4
12
|
NativeStackNavigationOptions,
|
|
5
13
|
NativeStackScreenProps,
|
|
@@ -27,19 +35,23 @@ import { DefaultLoading } from '../components/page/loading'
|
|
|
27
35
|
import { startsWith } from 'lodash'
|
|
28
36
|
import { VideoAttachmentPreview } from '../components/display/video_attachment_preview'
|
|
29
37
|
import { SafeAreaModal } from '../components/safe_area_modal'
|
|
38
|
+
import { useSafeAreaInsets } from 'react-native-safe-area-context'
|
|
39
|
+
import { useAppName } from '../hooks/use_app_name'
|
|
30
40
|
|
|
31
41
|
const MAX_DESCRIPTION_LENGTH = 2000
|
|
32
42
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
'
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
'
|
|
41
|
-
'
|
|
42
|
-
|
|
43
|
+
enum BUG_TYPE_OPTIONS {
|
|
44
|
+
Chat = 'Chat',
|
|
45
|
+
FindMyChurch = 'Find my church',
|
|
46
|
+
LoggingIn = 'Logging in',
|
|
47
|
+
UsingGroups = 'Using groups (events, resources, members)',
|
|
48
|
+
CheckingIn = 'Checking in',
|
|
49
|
+
MakingADonation = 'Making a donation',
|
|
50
|
+
RegisteringForAnEvent = 'Registering for an event',
|
|
51
|
+
MyProfileAndSchedule = 'My profile and schedule',
|
|
52
|
+
Directory = 'Directory',
|
|
53
|
+
Other = 'Other',
|
|
54
|
+
}
|
|
43
55
|
|
|
44
56
|
export const BugReportScreenOptions = ({
|
|
45
57
|
navigation,
|
|
@@ -55,57 +67,49 @@ interface Attachment {
|
|
|
55
67
|
type: string
|
|
56
68
|
}
|
|
57
69
|
|
|
70
|
+
enum QualifiedMobileAppName {
|
|
71
|
+
chat = 'Chat', // There is no app name for the mobile app
|
|
72
|
+
churchcenter = 'Church Center App',
|
|
73
|
+
services = 'Services Mobile',
|
|
74
|
+
}
|
|
75
|
+
|
|
58
76
|
export function BugReportScreen() {
|
|
59
77
|
const styles = useStyles()
|
|
60
78
|
const navigation = useNavigation()
|
|
61
|
-
const
|
|
79
|
+
const name = useAppName()
|
|
80
|
+
const appName = QualifiedMobileAppName[name]
|
|
81
|
+
const [bugType, setBugType] = useState<BUG_TYPE_OPTIONS>(BUG_TYPE_OPTIONS.Chat)
|
|
62
82
|
const [showBugTypePicker, setShowBugTypePicker] = useState(false)
|
|
63
83
|
const [whatWereDoing, setWhatWereDoing] = useState('')
|
|
64
84
|
const [whatExpected, setWhatExpected] = useState('')
|
|
65
|
-
const [stepsToResolve, setStepsToResolve] = useState('')
|
|
66
85
|
const uploadApi = useUploadClient()
|
|
67
86
|
const [uploading, setUploading] = useState(false)
|
|
68
87
|
const [attachment, setAttachment] = useState<Attachment | null>(null)
|
|
69
88
|
const [uploadError, setUploadError] = useState<string | null>(null)
|
|
70
|
-
const
|
|
71
|
-
const { mutate, status } = mutation
|
|
89
|
+
const { mutate: createBugReport, status } = useReportBugAction()
|
|
72
90
|
const formValid =
|
|
73
91
|
bugType.trim().length > 0 &&
|
|
74
92
|
whatWereDoing.trim().length > 0 &&
|
|
75
93
|
whatExpected.trim().length > 0 &&
|
|
76
|
-
stepsToResolve.trim().length > 0 &&
|
|
77
94
|
status === 'idle' &&
|
|
78
95
|
!uploading
|
|
79
96
|
const [imagePreviewURI, setImagePreviewURI] = useState<string>('')
|
|
80
|
-
|
|
81
97
|
const isImageAttachment = startsWith(attachment?.type, 'image/')
|
|
82
98
|
|
|
83
99
|
const handleSubmit = useCallback(() => {
|
|
84
|
-
const description =
|
|
85
|
-
|
|
86
|
-
## What kind of bug did you experience?
|
|
87
|
-
${bugType}
|
|
88
|
-
|
|
89
|
-
## What were you trying to do when you encountered the bug?
|
|
90
|
-
${whatWereDoing}
|
|
91
|
-
|
|
92
|
-
## What did you expect to happen? What actually happened?
|
|
93
|
-
${whatExpected}
|
|
100
|
+
const description = generateBugReportDescription(bugType, whatWereDoing, whatExpected)
|
|
94
101
|
|
|
95
|
-
|
|
96
|
-
${stepsToResolve}`
|
|
97
|
-
|
|
98
|
-
mutate({
|
|
102
|
+
createBugReport({
|
|
99
103
|
description,
|
|
100
|
-
description_json:
|
|
104
|
+
description_json: {
|
|
101
105
|
bugType,
|
|
102
106
|
whatWereDoing,
|
|
103
107
|
whatExpected,
|
|
104
|
-
|
|
105
|
-
}
|
|
108
|
+
appName: appName,
|
|
109
|
+
},
|
|
106
110
|
attachmentIds: attachment ? [attachment.id] : [],
|
|
107
111
|
})
|
|
108
|
-
}, [attachment, bugType, whatWereDoing, whatExpected,
|
|
112
|
+
}, [attachment, bugType, whatWereDoing, whatExpected, createBugReport, appName])
|
|
109
113
|
|
|
110
114
|
const handleRemoveAttachment = useCallback(() => {
|
|
111
115
|
setAttachment(null)
|
|
@@ -215,12 +219,10 @@ ${stepsToResolve}`
|
|
|
215
219
|
|
|
216
220
|
<View style={styles.textInputContainer}>
|
|
217
221
|
<Text style={styles.fieldLabel}>
|
|
218
|
-
|
|
222
|
+
Where did you experience the issue? <Text style={styles.required}>*</Text>
|
|
219
223
|
</Text>
|
|
220
224
|
<TouchableOpacity style={styles.pickerButton} onPress={() => setShowBugTypePicker(true)}>
|
|
221
|
-
<Text style={[styles.pickerText, !bugType && styles.pickerPlaceholder]}>
|
|
222
|
-
{bugType || 'Select the bug type'}
|
|
223
|
-
</Text>
|
|
225
|
+
<Text style={[styles.pickerText, !bugType && styles.pickerPlaceholder]}>{bugType}</Text>
|
|
224
226
|
<Icon
|
|
225
227
|
name="general.downChevron"
|
|
226
228
|
style={styles.pickerArrow}
|
|
@@ -242,7 +244,7 @@ ${stepsToResolve}`
|
|
|
242
244
|
<View style={styles.modalHeaderSpacer} />
|
|
243
245
|
</View>
|
|
244
246
|
<ScrollView style={styles.modalContent}>
|
|
245
|
-
{BUG_TYPE_OPTIONS.map(option => (
|
|
247
|
+
{Object.values(BUG_TYPE_OPTIONS).map(option => (
|
|
246
248
|
<TouchableOpacity
|
|
247
249
|
key={option}
|
|
248
250
|
style={styles.modalOption}
|
|
@@ -287,7 +289,7 @@ ${stepsToResolve}`
|
|
|
287
289
|
|
|
288
290
|
<View style={styles.textInputContainer}>
|
|
289
291
|
<Text style={styles.fieldLabel}>
|
|
290
|
-
What did you expect to happen?
|
|
292
|
+
What did you expect to happen? Please describe what actually happened.{' '}
|
|
291
293
|
<Text style={styles.required}>*</Text>
|
|
292
294
|
</Text>
|
|
293
295
|
<TextInput
|
|
@@ -305,25 +307,6 @@ ${stepsToResolve}`
|
|
|
305
307
|
)}
|
|
306
308
|
</View>
|
|
307
309
|
|
|
308
|
-
<View style={styles.textInputContainer}>
|
|
309
|
-
<Text style={styles.fieldLabel}>
|
|
310
|
-
What steps have you tried to resolve the issue? <Text style={styles.required}>*</Text>
|
|
311
|
-
</Text>
|
|
312
|
-
<TextInput
|
|
313
|
-
style={styles.textInput}
|
|
314
|
-
multiline
|
|
315
|
-
placeholder="Description"
|
|
316
|
-
value={stepsToResolve}
|
|
317
|
-
onChangeText={setStepsToResolve}
|
|
318
|
-
maxLength={MAX_DESCRIPTION_LENGTH}
|
|
319
|
-
/>
|
|
320
|
-
{stepsToResolve.length >= MAX_DESCRIPTION_LENGTH - 100 && (
|
|
321
|
-
<Text variant="footnote">
|
|
322
|
-
{stepsToResolve.length}/{MAX_DESCRIPTION_LENGTH}
|
|
323
|
-
</Text>
|
|
324
|
-
)}
|
|
325
|
-
</View>
|
|
326
|
-
|
|
327
310
|
<View style={styles.attachmentSection}>
|
|
328
311
|
<View style={styles.attachmentHeader}>
|
|
329
312
|
<Text style={styles.attachmentLabel}>
|
|
@@ -349,7 +332,7 @@ ${stepsToResolve}`
|
|
|
349
332
|
</View>
|
|
350
333
|
) : (
|
|
351
334
|
<Button
|
|
352
|
-
title="Attach a screenshot"
|
|
335
|
+
title="Attach a screenshot or recording"
|
|
353
336
|
accessibilityHint="Opens your device's image gallery"
|
|
354
337
|
iconNameLeft="general.paperclip"
|
|
355
338
|
onPress={pickImage}
|
|
@@ -359,14 +342,19 @@ ${stepsToResolve}`
|
|
|
359
342
|
disabled={uploading || Boolean(attachment)}
|
|
360
343
|
/>
|
|
361
344
|
)}
|
|
362
|
-
</View>
|
|
363
|
-
|
|
364
|
-
<View style={styles.footer}>
|
|
365
345
|
<Text variant="footnote">
|
|
366
|
-
|
|
367
|
-
|
|
346
|
+
Screenshots and screen recordings help us reproduce and fix issues faster.{' '}
|
|
347
|
+
<TextInlineButton
|
|
348
|
+
accessibilityRole="link"
|
|
349
|
+
variant="footnote"
|
|
350
|
+
onPress={() => Linking.openURL(VIDEO_RECORDING_HELP_URL)}
|
|
351
|
+
>
|
|
352
|
+
How to record your screen
|
|
353
|
+
</TextInlineButton>
|
|
368
354
|
</Text>
|
|
355
|
+
</View>
|
|
369
356
|
|
|
357
|
+
<View style={styles.footer}>
|
|
370
358
|
<Text variant="footnote">
|
|
371
359
|
For details on how we process your data and ensure its security, please refer to our{' '}
|
|
372
360
|
<TextInlineButton
|
|
@@ -384,12 +372,36 @@ ${stepsToResolve}`
|
|
|
384
372
|
)
|
|
385
373
|
}
|
|
386
374
|
|
|
375
|
+
const VIDEO_RECORDING_HELP_URL = Platform.select({
|
|
376
|
+
android: 'https://support.google.com/android/answer/6241341?hl=en',
|
|
377
|
+
default: 'https://support.apple.com/en-us/HT208721',
|
|
378
|
+
})
|
|
379
|
+
|
|
380
|
+
const generateBugReportDescription = (
|
|
381
|
+
bugType: BUG_TYPE_OPTIONS,
|
|
382
|
+
whatWereDoing: string,
|
|
383
|
+
whatExpected: string
|
|
384
|
+
) => {
|
|
385
|
+
return `${whatWereDoing.substring(0, 100)}
|
|
386
|
+
|
|
387
|
+
## What kind of bug did you experience?
|
|
388
|
+
${bugType}
|
|
389
|
+
|
|
390
|
+
## What were you trying to do when you encountered the bug?
|
|
391
|
+
${whatWereDoing}
|
|
392
|
+
|
|
393
|
+
## What did you expect to happen? What actually happened?
|
|
394
|
+
${whatExpected}
|
|
395
|
+
`
|
|
396
|
+
}
|
|
397
|
+
|
|
387
398
|
const useStyles = () => {
|
|
399
|
+
const { bottom } = useSafeAreaInsets()
|
|
388
400
|
const { colors } = useTheme()
|
|
389
401
|
return StyleSheet.create({
|
|
390
402
|
container: {
|
|
391
403
|
padding: 16,
|
|
392
|
-
paddingBottom: 16,
|
|
404
|
+
paddingBottom: 16 + bottom,
|
|
393
405
|
gap: 24,
|
|
394
406
|
},
|
|
395
407
|
fullHeight: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { StaticScreenProps, useNavigation } from '@react-navigation/native'
|
|
2
|
-
import React from 'react'
|
|
2
|
+
import React, { useCallback } from 'react'
|
|
3
3
|
import { StyleSheet, View } from 'react-native'
|
|
4
4
|
import { Conversations, TextButton } from '../../components'
|
|
5
5
|
import { ActionButton } from '../../components/display/action_button'
|
|
@@ -54,9 +54,9 @@ export function ConversationsScreen({ route }: ConversationsScreenProps) {
|
|
|
54
54
|
})
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
}
|
|
57
|
+
const handleGetHelp = useCallback(() => {
|
|
58
|
+
navigation.navigate('GetHelp')
|
|
59
|
+
}, [navigation])
|
|
60
60
|
|
|
61
61
|
return (
|
|
62
62
|
<View style={styles.container}>
|
|
@@ -71,12 +71,12 @@ export function ConversationsScreen({ route }: ConversationsScreenProps) {
|
|
|
71
71
|
secondaryButton={
|
|
72
72
|
<TextButton
|
|
73
73
|
variant="tertiary"
|
|
74
|
-
onPress={
|
|
74
|
+
onPress={handleGetHelp}
|
|
75
75
|
maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER_LANDMARK}
|
|
76
76
|
accessibilityShowsLargeContentViewer
|
|
77
|
-
accessibilityLargeContentTitle="
|
|
77
|
+
accessibilityLargeContentTitle="Get help"
|
|
78
78
|
>
|
|
79
|
-
|
|
79
|
+
Get help
|
|
80
80
|
</TextButton>
|
|
81
81
|
}
|
|
82
82
|
/>
|
|
@@ -863,7 +863,7 @@ function ImageIconsSection({ isLast }: SectionProps) {
|
|
|
863
863
|
description="Displays any icon from @planningcenter/icons. Missing icons will fallback to a grey circle. Styling with `fontSize` will allow it to scale with the device's text a11y size."
|
|
864
864
|
>
|
|
865
865
|
<Row>
|
|
866
|
-
{/* @ts-expect-error -
|
|
866
|
+
{/* @ts-expect-error - Testing missing icon fallback */}
|
|
867
867
|
<Icon name="missingIcon" size={20} />
|
|
868
868
|
<Icon name="general.textMessage" size={20} />
|
|
869
869
|
<Icon name="general.bell" size={20} color={colors.needsDesignPass} />
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { useNavigation } from '@react-navigation/native'
|
|
2
|
+
import { NativeStackScreenProps } from '@react-navigation/native-stack'
|
|
3
|
+
import { useCallback } from 'react'
|
|
4
|
+
import { Linking, StyleSheet, View } from 'react-native'
|
|
5
|
+
import { Heading, PressableRow, Text, TextInlineButton } from '../components'
|
|
6
|
+
import { useApiGet, useTheme } from '../hooks'
|
|
7
|
+
import { useAppName } from '../hooks/use_app_name'
|
|
8
|
+
import { ResourceObject } from '../types'
|
|
9
|
+
|
|
10
|
+
type GetHelpScreenProps = NativeStackScreenProps<{}>
|
|
11
|
+
|
|
12
|
+
interface OrganizationResource extends ResourceObject {
|
|
13
|
+
id: number
|
|
14
|
+
name: string
|
|
15
|
+
contactEmail: string
|
|
16
|
+
contactPhoneNumber: string
|
|
17
|
+
churchCenterChatHelpUrl: string
|
|
18
|
+
servicesChatHelpUrl: string
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const useOrganization = () => {
|
|
22
|
+
const { data: organization } = useApiGet<OrganizationResource>({
|
|
23
|
+
url: '/',
|
|
24
|
+
data: {
|
|
25
|
+
fields: {
|
|
26
|
+
Organization: [
|
|
27
|
+
'contact_phone_number',
|
|
28
|
+
'contact_email',
|
|
29
|
+
'name',
|
|
30
|
+
'church_center_chat_help_url',
|
|
31
|
+
'services_chat_help_url',
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
return organization
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export const GetHelpScreen = ({}: GetHelpScreenProps) => {
|
|
41
|
+
const styles = useStyles()
|
|
42
|
+
const appName = useAppName()
|
|
43
|
+
const isChurchCenter = appName === 'churchcenter'
|
|
44
|
+
const navigation = useNavigation()
|
|
45
|
+
const organization = useOrganization()
|
|
46
|
+
const contactPresent = organization?.contactEmail || organization?.contactPhoneNumber
|
|
47
|
+
const getHelpLink = isChurchCenter
|
|
48
|
+
? organization?.churchCenterChatHelpUrl
|
|
49
|
+
: organization?.servicesChatHelpUrl
|
|
50
|
+
|
|
51
|
+
const handleNavigateToBugReport = useCallback(() => {
|
|
52
|
+
navigation.navigate('BugReport')
|
|
53
|
+
}, [navigation])
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<View style={[styles.container]}>
|
|
57
|
+
<Heading variant="h2" style={[styles.heading, styles.headingBottomBorder]}>
|
|
58
|
+
How-to articles
|
|
59
|
+
</Heading>
|
|
60
|
+
<PressableRow
|
|
61
|
+
onPress={() => Linking.openURL(getHelpLink || '')}
|
|
62
|
+
text="Get help with chat"
|
|
63
|
+
isActive={true}
|
|
64
|
+
iconPath="general.newWindow"
|
|
65
|
+
/>
|
|
66
|
+
{contactPresent && (
|
|
67
|
+
<Heading variant="h2" style={[styles.heading, styles.headingBottomBorder]}>
|
|
68
|
+
Contact {organization?.name}
|
|
69
|
+
</Heading>
|
|
70
|
+
)}
|
|
71
|
+
<ContactRow email={organization?.contactEmail} />
|
|
72
|
+
<ContactRow phone={organization?.contactPhoneNumber} />
|
|
73
|
+
<Heading variant="h2" style={[styles.heading]}>
|
|
74
|
+
Report a bug
|
|
75
|
+
</Heading>
|
|
76
|
+
<View style={styles.text}>
|
|
77
|
+
<Text>
|
|
78
|
+
Having an issue?{' '}
|
|
79
|
+
<TextInlineButton onPress={handleNavigateToBugReport}>
|
|
80
|
+
Submit a bug report
|
|
81
|
+
</TextInlineButton>{' '}
|
|
82
|
+
to the development team.
|
|
83
|
+
</Text>
|
|
84
|
+
</View>
|
|
85
|
+
</View>
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const ContactRow = ({ email, phone }: { email?: string; phone?: string }) => {
|
|
90
|
+
if (!email && !phone) return null
|
|
91
|
+
|
|
92
|
+
const contact = email || phone
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<PressableRow
|
|
96
|
+
onPress={() => {}}
|
|
97
|
+
text={contact || ''}
|
|
98
|
+
isActive={true}
|
|
99
|
+
iconPath={email ? 'services.email' : 'general.phone'}
|
|
100
|
+
/>
|
|
101
|
+
)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const useStyles = () => {
|
|
105
|
+
const { colors } = useTheme()
|
|
106
|
+
|
|
107
|
+
return StyleSheet.create({
|
|
108
|
+
container: {
|
|
109
|
+
flex: 1,
|
|
110
|
+
},
|
|
111
|
+
text: {
|
|
112
|
+
paddingVertical: 4,
|
|
113
|
+
paddingHorizontal: 16,
|
|
114
|
+
},
|
|
115
|
+
heading: {
|
|
116
|
+
marginLeft: 16,
|
|
117
|
+
paddingTop: 24,
|
|
118
|
+
paddingBottom: 12,
|
|
119
|
+
},
|
|
120
|
+
headingBottomBorder: {
|
|
121
|
+
marginLeft: 16,
|
|
122
|
+
paddingLeft: 0,
|
|
123
|
+
borderBottomWidth: 1,
|
|
124
|
+
borderBottomColor: colors.borderColorDefaultBase,
|
|
125
|
+
},
|
|
126
|
+
headingAux: {
|
|
127
|
+
paddingTop: 24,
|
|
128
|
+
paddingHorizontal: 16,
|
|
129
|
+
},
|
|
130
|
+
})
|
|
131
|
+
}
|