@planningcenter/chat-react-native 3.12.0-rc.9 → 3.12.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.
@@ -19,4 +19,5 @@ export * from './text_button';
19
19
  export * from './text_inline_button';
20
20
  export * from './text';
21
21
  export * from './toggle_button';
22
+ export * from './keyboard_view';
22
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,sBAAsB,CAAA;AACpC,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,sBAAsB,CAAA;AACpC,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA"}
@@ -19,4 +19,5 @@ export * from './text_button';
19
19
  export * from './text_inline_button';
20
20
  export * from './text';
21
21
  export * from './toggle_button';
22
+ export * from './keyboard_view';
22
23
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,sBAAsB,CAAA;AACpC,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA","sourcesContent":["export * from './avatar_group'\nexport * from './avatar'\nexport * from './badge'\nexport * from './banner_collapsible'\nexport * from './banner'\nexport * from './blank_state'\nexport * from './button'\nexport * from './child_notice'\nexport * from './heading'\nexport * from './icon_button'\nexport * from './icon'\nexport * from './image'\nexport * from './image_attachment_preview'\nexport * from './video_attachment_preview'\nexport * from './person'\nexport * from './spinner'\nexport * from './switch'\nexport * from './text_button'\nexport * from './text_inline_button'\nexport * from './text'\nexport * from './toggle_button'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/components/display/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,UAAU,CAAA;AACxB,cAAc,SAAS,CAAA;AACvB,cAAc,sBAAsB,CAAA;AACpC,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,gBAAgB,CAAA;AAC9B,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,QAAQ,CAAA;AACtB,cAAc,SAAS,CAAA;AACvB,cAAc,4BAA4B,CAAA;AAC1C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,UAAU,CAAA;AACxB,cAAc,eAAe,CAAA;AAC7B,cAAc,sBAAsB,CAAA;AACpC,cAAc,QAAQ,CAAA;AACtB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,iBAAiB,CAAA","sourcesContent":["export * from './avatar_group'\nexport * from './avatar'\nexport * from './badge'\nexport * from './banner_collapsible'\nexport * from './banner'\nexport * from './blank_state'\nexport * from './button'\nexport * from './child_notice'\nexport * from './heading'\nexport * from './icon_button'\nexport * from './icon'\nexport * from './image'\nexport * from './image_attachment_preview'\nexport * from './video_attachment_preview'\nexport * from './person'\nexport * from './spinner'\nexport * from './switch'\nexport * from './text_button'\nexport * from './text_inline_button'\nexport * from './text'\nexport * from './toggle_button'\nexport * from './keyboard_view'\n"]}
@@ -1,5 +1,6 @@
1
1
  export declare const useReportBugAction: () => import("@tanstack/react-query").UseMutationResult<import("..").ApiCollection | import("..").ApiResource, Error, {
2
2
  description: string;
3
+ description_json: string;
3
4
  attachmentIds: string[];
4
5
  }, unknown>;
5
6
  //# sourceMappingURL=use_report_bug_action.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_report_bug_action.d.ts","sourceRoot":"","sources":["../../src/hooks/use_report_bug_action.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,kBAAkB;iBAQZ,MAAM;mBACJ,MAAM,EAAE;WAiB5B,CAAA"}
1
+ {"version":3,"file":"use_report_bug_action.d.ts","sourceRoot":"","sources":["../../src/hooks/use_report_bug_action.ts"],"names":[],"mappings":"AAUA,eAAO,MAAM,kBAAkB;iBASZ,MAAM;sBACD,MAAM;mBACT,MAAM,EAAE;WAkB5B,CAAA"}
@@ -10,7 +10,7 @@ const appName = DeviceInfo.getApplicationName();
10
10
  export const useReportBugAction = () => {
11
11
  const apiClient = useApiClient();
12
12
  return useMutation({
13
- mutationFn: async ({ description, attachmentIds, }) => {
13
+ mutationFn: async ({ description, description_json, attachmentIds, }) => {
14
14
  return apiClient.chat.post({
15
15
  url: `/me/report_bug`,
16
16
  data: {
@@ -18,6 +18,7 @@ export const useReportBugAction = () => {
18
18
  type: '',
19
19
  attributes: {
20
20
  description,
21
+ description_json,
21
22
  device_info: `${appName}/${readableVersion} (${brand}, ${model}, ${systemName}, ${systemVersion})`,
22
23
  attachment_ids: attachmentIds,
23
24
  },
@@ -1 +1 @@
1
- {"version":3,"file":"use_report_bug_action.js","sourceRoot":"","sources":["../../src/hooks/use_report_bug_action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,UAAU,MAAM,0BAA0B,CAAA;AACjD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAA;AACnC,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAA;AACnC,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,EAAE,CAAA;AAC7C,MAAM,aAAa,GAAG,UAAU,CAAC,gBAAgB,EAAE,CAAA;AACnD,MAAM,eAAe,GAAG,UAAU,CAAC,kBAAkB,EAAE,CAAA;AACvD,MAAM,OAAO,GAAG,UAAU,CAAC,kBAAkB,EAAE,CAAA;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,EAAE;IACrC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,OAAO,WAAW,CAAC;QACjB,UAAU,EAAE,KAAK,EAAE,EACjB,WAAW,EACX,aAAa,GAId,EAAE,EAAE;YACH,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzB,GAAG,EAAE,gBAAgB;gBACrB,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE;4BACV,WAAW;4BACX,WAAW,EAAE,GAAG,OAAO,IAAI,eAAe,KAAK,KAAK,KAAK,KAAK,KAAK,UAAU,KAAK,aAAa,GAAG;4BAClG,cAAc,EAAE,aAAa;yBAC9B;qBACF;iBACF;aACF,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useMutation } from '@tanstack/react-query'\nimport { useApiClient } from './use_api_client'\nimport DeviceInfo from 'react-native-device-info'\nconst brand = DeviceInfo.getBrand()\nconst model = DeviceInfo.getModel()\nconst systemName = DeviceInfo.getSystemName()\nconst systemVersion = DeviceInfo.getSystemVersion()\nconst readableVersion = DeviceInfo.getReadableVersion()\nconst appName = DeviceInfo.getApplicationName()\n\nexport const useReportBugAction = () => {\n const apiClient = useApiClient()\n\n return useMutation({\n mutationFn: async ({\n description,\n attachmentIds,\n }: {\n description: string\n attachmentIds: string[]\n }) => {\n return apiClient.chat.post({\n url: `/me/report_bug`,\n data: {\n data: {\n type: '',\n attributes: {\n description,\n device_info: `${appName}/${readableVersion} (${brand}, ${model}, ${systemName}, ${systemVersion})`,\n attachment_ids: attachmentIds,\n },\n },\n },\n })\n },\n })\n}\n"]}
1
+ {"version":3,"file":"use_report_bug_action.js","sourceRoot":"","sources":["../../src/hooks/use_report_bug_action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,UAAU,MAAM,0BAA0B,CAAA;AACjD,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAA;AACnC,MAAM,KAAK,GAAG,UAAU,CAAC,QAAQ,EAAE,CAAA;AACnC,MAAM,UAAU,GAAG,UAAU,CAAC,aAAa,EAAE,CAAA;AAC7C,MAAM,aAAa,GAAG,UAAU,CAAC,gBAAgB,EAAE,CAAA;AACnD,MAAM,eAAe,GAAG,UAAU,CAAC,kBAAkB,EAAE,CAAA;AACvD,MAAM,OAAO,GAAG,UAAU,CAAC,kBAAkB,EAAE,CAAA;AAE/C,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,EAAE;IACrC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAEhC,OAAO,WAAW,CAAC;QACjB,UAAU,EAAE,KAAK,EAAE,EACjB,WAAW,EACX,gBAAgB,EAChB,aAAa,GAKd,EAAE,EAAE;YACH,OAAO,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC;gBACzB,GAAG,EAAE,gBAAgB;gBACrB,IAAI,EAAE;oBACJ,IAAI,EAAE;wBACJ,IAAI,EAAE,EAAE;wBACR,UAAU,EAAE;4BACV,WAAW;4BACX,gBAAgB;4BAChB,WAAW,EAAE,GAAG,OAAO,IAAI,eAAe,KAAK,KAAK,KAAK,KAAK,KAAK,UAAU,KAAK,aAAa,GAAG;4BAClG,cAAc,EAAE,aAAa;yBAC9B;qBACF;iBACF;aACF,CAAC,CAAA;QACJ,CAAC;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useMutation } from '@tanstack/react-query'\nimport { useApiClient } from './use_api_client'\nimport DeviceInfo from 'react-native-device-info'\nconst brand = DeviceInfo.getBrand()\nconst model = DeviceInfo.getModel()\nconst systemName = DeviceInfo.getSystemName()\nconst systemVersion = DeviceInfo.getSystemVersion()\nconst readableVersion = DeviceInfo.getReadableVersion()\nconst appName = DeviceInfo.getApplicationName()\n\nexport const useReportBugAction = () => {\n const apiClient = useApiClient()\n\n return useMutation({\n mutationFn: async ({\n description,\n description_json,\n attachmentIds,\n }: {\n description: string\n description_json: string\n attachmentIds: string[]\n }) => {\n return apiClient.chat.post({\n url: `/me/report_bug`,\n data: {\n data: {\n type: '',\n attributes: {\n description,\n description_json,\n device_info: `${appName}/${readableVersion} (${brand}, ${model}, ${systemName}, ${systemVersion})`,\n attachment_ids: attachmentIds,\n },\n },\n },\n })\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"bug_report_screen.d.ts","sourceRoot":"","sources":["../../src/screens/bug_report_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAErE,OAAO,KAAK,EACV,4BAA4B,EAC5B,sBAAsB,EACvB,MAAM,gCAAgC,CAAA;AAyBvC,eAAO,MAAM,sBAAsB,oBAEhC,sBAAsB,CAAC,GAAG,CAAC,KAAG,4BAI/B,CAAA;AAQF,wBAAgB,eAAe,sBAsM9B"}
1
+ {"version":3,"file":"bug_report_screen.d.ts","sourceRoot":"","sources":["../../src/screens/bug_report_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAUrE,OAAO,KAAK,EACV,4BAA4B,EAC5B,sBAAsB,EACvB,MAAM,gCAAgC,CAAA;AAsCvC,eAAO,MAAM,sBAAsB,oBAEhC,sBAAsB,CAAC,GAAG,CAAC,KAAG,4BAI/B,CAAA;AAQF,wBAAgB,eAAe,sBAqU9B"}
@@ -1,7 +1,7 @@
1
1
  import React, { useCallback, useLayoutEffect, useState } from 'react';
2
- import { View, StyleSheet, TextInput, Linking, ScrollView } from 'react-native';
2
+ import { View, StyleSheet, TextInput, Linking, ScrollView, TouchableOpacity, Modal, } from 'react-native';
3
3
  import { useNavigation } from '@react-navigation/native';
4
- import { Button, Spinner, Text, TextInlineButton, ImageAttachmentPreview, BlankState, } from '../components';
4
+ import { Button, Spinner, Text, TextInlineButton, ImageAttachmentPreview, BlankState, Icon, KeyboardView, } from '../components';
5
5
  import { useTheme } from '../hooks';
6
6
  import { useUploadClient } from '../hooks/use_upload_client';
7
7
  import { ImagePicker, platformFontWeightBold } from '../utils';
@@ -11,7 +11,17 @@ import { useSafeAreaInsets } from 'react-native-safe-area-context';
11
11
  import { DefaultLoading } from '../components/page/loading';
12
12
  import { startsWith } from 'lodash';
13
13
  import { VideoAttachmentPreview } from '../components/display/video_attachment_preview';
14
- const MAX_DESCRIPTION_LENGTH = 5000;
14
+ const MAX_DESCRIPTION_LENGTH = 2000;
15
+ const BUG_TYPE_OPTIONS = [
16
+ 'Issues sending or receiving messages',
17
+ 'Trouble starting a new conversation',
18
+ "Notifications aren't working",
19
+ 'Incorrect read receipts or unread counts',
20
+ 'Problems with file attachments',
21
+ "Something isn't displaying properly",
22
+ 'App is slow or crashes',
23
+ 'Other',
24
+ ];
15
25
  export const BugReportScreenOptions = ({ navigation, }) => ({
16
26
  presentation: 'modal',
17
27
  title: 'Report a bug',
@@ -20,23 +30,50 @@ export const BugReportScreenOptions = ({ navigation, }) => ({
20
30
  export function BugReportScreen() {
21
31
  const styles = useStyles();
22
32
  const navigation = useNavigation();
23
- const [description, setDescription] = useState('');
33
+ const [bugType, setBugType] = useState('');
34
+ const [showBugTypePicker, setShowBugTypePicker] = useState(false);
35
+ const [whatWereDoing, setWhatWereDoing] = useState('');
36
+ const [whatExpected, setWhatExpected] = useState('');
37
+ const [stepsToResolve, setStepsToResolve] = useState('');
24
38
  const uploadApi = useUploadClient();
25
39
  const [uploading, setUploading] = useState(false);
26
40
  const [attachment, setAttachment] = useState(null);
27
41
  const [uploadError, setUploadError] = useState(null);
28
42
  const mutation = useReportBugAction();
29
43
  const { mutate, status } = mutation;
30
- const formValid = description.trim().length > 0 && status === 'idle' && !uploading;
44
+ const formValid = bugType.trim().length > 0 &&
45
+ whatWereDoing.trim().length > 0 &&
46
+ whatExpected.trim().length > 0 &&
47
+ stepsToResolve.trim().length > 0 &&
48
+ status === 'idle' &&
49
+ !uploading;
31
50
  const [imagePreviewURI, setImagePreviewURI] = useState('');
32
- const nearMaxDescription = description.length >= MAX_DESCRIPTION_LENGTH - 100;
33
51
  const isImageAttachment = startsWith(attachment?.type, 'image/');
34
52
  const handleSubmit = useCallback(() => {
53
+ const description = `${whatWereDoing.substring(0, 100)}
54
+
55
+ ## What kind of bug did you experience?
56
+ ${bugType}
57
+
58
+ ## What were you trying to do when you encountered the bug?
59
+ ${whatWereDoing}
60
+
61
+ ## What did you expect to happen? What actually happened?
62
+ ${whatExpected}
63
+
64
+ ## What steps have you tried to resolve the issue?
65
+ ${stepsToResolve}`;
35
66
  mutate({
36
67
  description,
68
+ description_json: JSON.stringify({
69
+ bugType,
70
+ whatWereDoing,
71
+ whatExpected,
72
+ stepsToResolve,
73
+ }),
37
74
  attachmentIds: attachment ? [attachment.id] : [],
38
75
  });
39
- }, [attachment, description, mutate]);
76
+ }, [attachment, bugType, whatWereDoing, whatExpected, stepsToResolve, mutate]);
40
77
  const handleRemoveAttachment = useCallback(() => {
41
78
  setAttachment(null);
42
79
  setImagePreviewURI('');
@@ -103,46 +140,105 @@ export function BugReportScreen() {
103
140
  <Button title="Return to chat" onPress={navigation.goBack} variant="fill" size="lg"/>
104
141
  </View>);
105
142
  }
106
- return (<ScrollView contentContainerStyle={styles.container}>
107
- <Text style={styles.description}>
108
- Thanks for helping us improve chat! Please provide details about the issue you’ve
109
- encountered. We read every submission and your feedback helps us improve the experience.
110
- </Text>
111
- <View style={styles.textInputContainer}>
112
- <TextInput style={styles.textInput} multiline placeholder="Details about the problem" value={description} onChangeText={setDescription} maxLength={MAX_DESCRIPTION_LENGTH}/>
113
- {nearMaxDescription && (<Text variant="footnote">
114
- {description.length}/{MAX_DESCRIPTION_LENGTH}
115
- </Text>)}
116
- </View>
143
+ return (<KeyboardView>
144
+ <ScrollView contentContainerStyle={styles.container}>
145
+ <Text style={styles.description}>
146
+ Thanks for helping us improve chat. Please provide details about the issue you've
147
+ encountered. We read every submission and your feedback helps us improve the experience.
148
+ </Text>
117
149
 
118
- <View style={styles.attachmentSection}>
119
- <View style={styles.attachmentHeader}>
120
- <Text style={styles.attachmentLabel}>
121
- Attachment <Text style={styles.subLabel}>(optional)</Text>
150
+ <View style={styles.textInputContainer}>
151
+ <Text style={styles.fieldLabel}>
152
+ What kind of bug did you experience? <Text style={styles.required}>*</Text>
122
153
  </Text>
123
- {uploading && <Spinner />}
154
+ <TouchableOpacity style={styles.pickerButton} onPress={() => setShowBugTypePicker(true)}>
155
+ <Text style={[styles.pickerText, !bugType && styles.pickerPlaceholder]}>
156
+ {bugType || 'Select the bug type'}
157
+ </Text>
158
+ <Icon name="general.downChevron" style={styles.pickerArrow} accessibilityElementsHidden/>
159
+ </TouchableOpacity>
124
160
  </View>
125
- {uploadError && <Text style={styles.attachmentErrorText}>{uploadError}</Text>}
126
- {attachment ? (<View style={styles.attachmentPreviewContainer}>
127
- {isImageAttachment ? (<ImageAttachmentPreview uri={imagePreviewURI} fileName={attachment.name} onRemovePress={handleRemoveAttachment}/>) : (<VideoAttachmentPreview name={attachment.name} onRemovePress={handleRemoveAttachment}/>)}
128
- </View>) : (<Button title="Attach a screenshot" accessibilityHint="Opens your device's image gallery" iconNameLeft="general.paperclip" onPress={pickImage} size="sm" variant="outline" style={styles.attachButton} disabled={uploading || Boolean(attachment)}/>)}
129
- </View>
130
161
 
131
- <View style={styles.footer}>
132
- <Text variant="footnote">
133
- We can’t respond to every submission, but we may reach out if we have additional
134
- questions.
135
- </Text>
162
+ <Modal visible={showBugTypePicker} animationType="slide" presentationStyle="pageSheet" onRequestClose={() => setShowBugTypePicker(false)}>
163
+ <View style={styles.modalContainer}>
164
+ <View style={styles.modalHeader}>
165
+ <HeaderCancelButton title="Cancel" onPress={() => setShowBugTypePicker(false)}/>
166
+ <Text style={styles.modalTitle}>Select Bug Type</Text>
167
+ <View style={styles.modalHeaderSpacer}/>
168
+ </View>
169
+ <ScrollView style={styles.modalContent}>
170
+ {BUG_TYPE_OPTIONS.map(option => (<TouchableOpacity key={option} style={styles.modalOption} onPress={() => {
171
+ setBugType(option);
172
+ setShowBugTypePicker(false);
173
+ }}>
174
+ <Text style={styles.modalOptionText}>{option}</Text>
175
+ {bugType === option && (<Icon name="general.check" style={styles.modalCheckmark} accessibilityElementsHidden/>)}
176
+ </TouchableOpacity>))}
177
+ </ScrollView>
178
+ </View>
179
+ </Modal>
136
180
 
137
- <Text variant="footnote">
138
- For details on how we process your data and ensure its security, please refer to our{' '}
139
- <TextInlineButton accessibilityRole="link" variant="footnote" onPress={() => Linking.openURL('https://www.planningcenter.com/privacy')}>
140
- Privacy Policy
141
- </TextInlineButton>
142
- .
143
- </Text>
144
- </View>
145
- </ScrollView>);
181
+ <View style={styles.textInputContainer}>
182
+ <Text style={styles.fieldLabel}>
183
+ What were you trying to do when you encountered the bug?{' '}
184
+ <Text style={styles.required}>*</Text>
185
+ </Text>
186
+ <TextInput style={styles.textInput} multiline placeholder="Description" value={whatWereDoing} onChangeText={setWhatWereDoing} maxLength={MAX_DESCRIPTION_LENGTH}/>
187
+ {whatWereDoing.length >= MAX_DESCRIPTION_LENGTH - 100 && (<Text variant="footnote">
188
+ {whatWereDoing.length}/{MAX_DESCRIPTION_LENGTH}
189
+ </Text>)}
190
+ </View>
191
+
192
+ <View style={styles.textInputContainer}>
193
+ <Text style={styles.fieldLabel}>
194
+ What did you expect to happen? What actually happened?{' '}
195
+ <Text style={styles.required}>*</Text>
196
+ </Text>
197
+ <TextInput style={styles.textInput} multiline placeholder="Description" value={whatExpected} onChangeText={setWhatExpected} maxLength={MAX_DESCRIPTION_LENGTH}/>
198
+ {whatExpected.length >= MAX_DESCRIPTION_LENGTH - 100 && (<Text variant="footnote">
199
+ {whatExpected.length}/{MAX_DESCRIPTION_LENGTH}
200
+ </Text>)}
201
+ </View>
202
+
203
+ <View style={styles.textInputContainer}>
204
+ <Text style={styles.fieldLabel}>
205
+ What steps have you tried to resolve the issue? <Text style={styles.required}>*</Text>
206
+ </Text>
207
+ <TextInput style={styles.textInput} multiline placeholder="Description" value={stepsToResolve} onChangeText={setStepsToResolve} maxLength={MAX_DESCRIPTION_LENGTH}/>
208
+ {stepsToResolve.length >= MAX_DESCRIPTION_LENGTH - 100 && (<Text variant="footnote">
209
+ {stepsToResolve.length}/{MAX_DESCRIPTION_LENGTH}
210
+ </Text>)}
211
+ </View>
212
+
213
+ <View style={styles.attachmentSection}>
214
+ <View style={styles.attachmentHeader}>
215
+ <Text style={styles.attachmentLabel}>
216
+ Attachment <Text style={styles.subLabel}>(optional)</Text>
217
+ </Text>
218
+ {uploading && <Spinner />}
219
+ </View>
220
+ {uploadError && <Text style={styles.attachmentErrorText}>{uploadError}</Text>}
221
+ {attachment ? (<View style={styles.attachmentPreviewContainer}>
222
+ {isImageAttachment ? (<ImageAttachmentPreview uri={imagePreviewURI} fileName={attachment.name} onRemovePress={handleRemoveAttachment}/>) : (<VideoAttachmentPreview name={attachment.name} onRemovePress={handleRemoveAttachment}/>)}
223
+ </View>) : (<Button title="Attach a screenshot" accessibilityHint="Opens your device's image gallery" iconNameLeft="general.paperclip" onPress={pickImage} size="sm" variant="outline" style={styles.attachButton} disabled={uploading || Boolean(attachment)}/>)}
224
+ </View>
225
+
226
+ <View style={styles.footer}>
227
+ <Text variant="footnote">
228
+ We can’t respond to every submission, but we may reach out if we have additional
229
+ questions.
230
+ </Text>
231
+
232
+ <Text variant="footnote">
233
+ For details on how we process your data and ensure its security, please refer to our{' '}
234
+ <TextInlineButton accessibilityRole="link" variant="footnote" onPress={() => Linking.openURL('https://www.planningcenter.com/privacy')}>
235
+ Privacy Policy
236
+ </TextInlineButton>
237
+ .
238
+ </Text>
239
+ </View>
240
+ </ScrollView>
241
+ </KeyboardView>);
146
242
  }
147
243
  const useStyles = () => {
148
244
  const { colors } = useTheme();
@@ -160,13 +256,81 @@ const useStyles = () => {
160
256
  color: colors.textColorDefaultSecondary,
161
257
  },
162
258
  textInputContainer: {
163
- borderTopWidth: 1,
164
- borderBottomWidth: 1,
259
+ gap: 8,
260
+ },
261
+ fieldLabel: {
262
+ fontSize: 16,
263
+ fontWeight: platformFontWeightBold,
264
+ color: colors.textColorDefaultPrimary,
265
+ },
266
+ required: {
267
+ color: colors.statusErrorText,
268
+ },
269
+ pickerButton: {
270
+ flexDirection: 'row',
271
+ alignItems: 'center',
272
+ justifyContent: 'space-between',
273
+ borderWidth: 1,
165
274
  borderColor: colors.borderColorDefaultBase,
275
+ borderRadius: 8,
276
+ paddingHorizontal: 16,
166
277
  paddingVertical: 12,
278
+ backgroundColor: colors.surfaceColor100,
279
+ minHeight: 48,
280
+ },
281
+ pickerText: {
282
+ fontSize: 16,
283
+ color: colors.textColorDefaultPrimary,
284
+ flex: 1,
285
+ },
286
+ pickerPlaceholder: {
287
+ color: colors.textColorDefaultSecondary,
288
+ },
289
+ pickerArrow: {
290
+ fontSize: 12,
291
+ color: colors.iconColorDefaultSecondary,
292
+ marginLeft: 8,
293
+ },
294
+ modalContainer: {
295
+ flex: 1,
296
+ backgroundColor: colors.surfaceColor100,
297
+ },
298
+ modalHeader: {
299
+ flexDirection: 'row',
300
+ alignItems: 'center',
301
+ justifyContent: 'space-between',
302
+ padding: 16,
303
+ borderBottomWidth: 1,
304
+ borderBottomColor: colors.borderColorDefaultBase,
305
+ },
306
+ modalTitle: {
307
+ fontSize: 18,
308
+ fontWeight: platformFontWeightBold,
309
+ color: colors.textColorDefaultPrimary,
310
+ },
311
+ modalHeaderSpacer: {
312
+ width: 50, // Same width as cancel button to center title
313
+ },
314
+ modalContent: {
315
+ flex: 1,
316
+ },
317
+ modalOption: {
318
+ flexDirection: 'row',
319
+ alignItems: 'center',
320
+ justifyContent: 'space-between',
167
321
  paddingHorizontal: 16,
168
- marginHorizontal: -16,
169
- gap: 8,
322
+ paddingVertical: 16,
323
+ borderBottomWidth: 1,
324
+ borderBottomColor: colors.borderColorDefaultBase,
325
+ },
326
+ modalOptionText: {
327
+ fontSize: 16,
328
+ color: colors.textColorDefaultPrimary,
329
+ flex: 1,
330
+ },
331
+ modalCheckmark: {
332
+ fontSize: 16,
333
+ color: colors.statusSuccessIcon,
170
334
  },
171
335
  textInput: {
172
336
  color: colors.textColorDefaultPrimary,
@@ -174,6 +338,12 @@ const useStyles = () => {
174
338
  textAlignVertical: 'top',
175
339
  minHeight: 120,
176
340
  maxHeight: 200,
341
+ borderWidth: 1,
342
+ borderColor: colors.borderColorDefaultBase,
343
+ borderRadius: 8,
344
+ paddingHorizontal: 16,
345
+ paddingVertical: 12,
346
+ backgroundColor: colors.surfaceColor100,
177
347
  },
178
348
  attachmentSection: {
179
349
  gap: 8,
@@ -1 +1 @@
1
- {"version":3,"file":"bug_report_screen.js","sourceRoot":"","sources":["../../src/screens/bug_report_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import React, { useCallback, useLayoutEffect, useState } from 'react'\nimport { View, StyleSheet, TextInput, Linking, ScrollView } from 'react-native'\nimport type {\n NativeStackNavigationOptions,\n NativeStackScreenProps,\n} from '@react-navigation/native-stack'\nimport { useNavigation } from '@react-navigation/native'\nimport {\n Button,\n Spinner,\n Text,\n TextInlineButton,\n ImageAttachmentPreview,\n BlankState,\n} from '../components'\nimport { useTheme } from '../hooks'\nimport { useUploadClient } from '../hooks/use_upload_client'\nimport { ImagePicker, ImagePickerResult, platformFontWeightBold } from '../utils'\nimport { useReportBugAction } from '../hooks/use_report_bug_action'\nimport {\n HeaderCancelButton,\n HeaderSubmitButton,\n} from '../components/display/platform_modal_header_buttons'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { DefaultLoading } from '../components/page/loading'\nimport { startsWith } from 'lodash'\nimport { VideoAttachmentPreview } from '../components/display/video_attachment_preview'\n\nconst MAX_DESCRIPTION_LENGTH = 5000\n\nexport const BugReportScreenOptions = ({\n navigation,\n}: NativeStackScreenProps<any>): NativeStackNavigationOptions => ({\n presentation: 'modal',\n title: 'Report a bug',\n headerLeft: () => <HeaderCancelButton title=\"Cancel\" onPress={() => navigation.goBack()} />,\n})\n\ninterface Attachment {\n id: string\n name: string\n type: string\n}\n\nexport function BugReportScreen() {\n const styles = useStyles()\n const navigation = useNavigation()\n const [description, setDescription] = useState('')\n const uploadApi = useUploadClient()\n const [uploading, setUploading] = useState(false)\n const [attachment, setAttachment] = useState<Attachment | null>(null)\n const [uploadError, setUploadError] = useState<string | null>(null)\n const mutation = useReportBugAction()\n const { mutate, status } = mutation\n const formValid = description.trim().length > 0 && status === 'idle' && !uploading\n const [imagePreviewURI, setImagePreviewURI] = useState<string>('')\n\n const nearMaxDescription = description.length >= MAX_DESCRIPTION_LENGTH - 100\n const isImageAttachment = startsWith(attachment?.type, 'image/')\n\n const handleSubmit = useCallback(() => {\n mutate({\n description,\n attachmentIds: attachment ? [attachment.id] : [],\n })\n }, [attachment, description, mutate])\n\n const handleRemoveAttachment = useCallback(() => {\n setAttachment(null)\n setImagePreviewURI('')\n }, [])\n\n function uploadImagePickerResult(result: ImagePickerResult) {\n if (result.canceled || result.assets.length === 0) {\n setUploading(false)\n return\n }\n\n const asset = result.assets[0]\n\n uploadApi\n ?.uploadFile({\n uri: asset.uri,\n name: asset.fileName as string,\n type: asset.mimeType as string,\n })\n .then(uploadedResource => {\n setUploading(false)\n setImagePreviewURI(asset.uri)\n setAttachment({\n id: uploadedResource.id,\n name: asset.fileName || 'File',\n type: asset.mimeType as string,\n })\n })\n .catch(() => {\n setUploading(false)\n setUploadError(`Failed to upload attachment`)\n })\n }\n\n function pickImage() {\n setUploading(true)\n return ImagePicker.openImageLibraryAsync().then(result => uploadImagePickerResult(result))\n }\n\n useLayoutEffect(() => {\n navigation.setOptions({\n // eslint-disable-next-line react/no-unstable-nested-components\n headerRight: () => (\n <HeaderSubmitButton title=\"Submit\" onPress={handleSubmit} disabled={!formValid} />\n ),\n })\n }, [formValid, handleSubmit, navigation])\n\n if (status === 'pending') {\n return (\n <View style={[styles.container, styles.fullHeight]}>\n <DefaultLoading />\n </View>\n )\n }\n\n if (status === 'success') {\n return (\n <BlankState\n iconName=\"general.checkCircle\"\n iconStyle={styles.successIcon}\n title=\"Thank you!\"\n titleStyle={styles.successTitle}\n subtitle=\"We appreciate you taking the time to help improve chat! We'll take a look at the issue you reported.\"\n subtitleStyle={styles.successSubtitle}\n buttonProps={{\n title: 'Return to chat',\n onPress: navigation.goBack,\n size: 'lg',\n variant: 'fill',\n }}\n />\n )\n }\n\n if (status === 'error') {\n return (\n <View style={styles.container}>\n <Text>\n This is embarrassing, we can't submit your bug report right now. If you still need help or\n would like to submit this bug report another way please{' '}\n <TextInlineButton\n accessibilityRole=\"link\"\n onPress={() =>\n Linking.openURL('https://support.planningcenteronline.com/hc/en-us/requests/new')\n }\n >\n contact our help center\n </TextInlineButton>\n .\n </Text>\n <Button title=\"Return to chat\" onPress={navigation.goBack} variant=\"fill\" size=\"lg\" />\n </View>\n )\n }\n\n return (\n <ScrollView contentContainerStyle={styles.container}>\n <Text style={styles.description}>\n Thanks for helping us improve chat! Please provide details about the issue you’ve\n encountered. We read every submission and your feedback helps us improve the experience.\n </Text>\n <View style={styles.textInputContainer}>\n <TextInput\n style={styles.textInput}\n multiline\n placeholder=\"Details about the problem\"\n value={description}\n onChangeText={setDescription}\n maxLength={MAX_DESCRIPTION_LENGTH}\n />\n {nearMaxDescription && (\n <Text variant=\"footnote\">\n {description.length}/{MAX_DESCRIPTION_LENGTH}\n </Text>\n )}\n </View>\n\n <View style={styles.attachmentSection}>\n <View style={styles.attachmentHeader}>\n <Text style={styles.attachmentLabel}>\n Attachment <Text style={styles.subLabel}>(optional)</Text>\n </Text>\n {uploading && <Spinner />}\n </View>\n {uploadError && <Text style={styles.attachmentErrorText}>{uploadError}</Text>}\n {attachment ? (\n <View style={styles.attachmentPreviewContainer}>\n {isImageAttachment ? (\n <ImageAttachmentPreview\n uri={imagePreviewURI}\n fileName={attachment.name}\n onRemovePress={handleRemoveAttachment}\n />\n ) : (\n <VideoAttachmentPreview\n name={attachment.name}\n onRemovePress={handleRemoveAttachment}\n />\n )}\n </View>\n ) : (\n <Button\n title=\"Attach a screenshot\"\n accessibilityHint=\"Opens your device's image gallery\"\n iconNameLeft=\"general.paperclip\"\n onPress={pickImage}\n size=\"sm\"\n variant=\"outline\"\n style={styles.attachButton}\n disabled={uploading || Boolean(attachment)}\n />\n )}\n </View>\n\n <View style={styles.footer}>\n <Text variant=\"footnote\">\n We can’t respond to every submission, but we may reach out if we have additional\n questions.\n </Text>\n\n <Text variant=\"footnote\">\n For details on how we process your data and ensure its security, please refer to our{' '}\n <TextInlineButton\n accessibilityRole=\"link\"\n variant=\"footnote\"\n onPress={() => Linking.openURL('https://www.planningcenter.com/privacy')}\n >\n Privacy Policy\n </TextInlineButton>\n .\n </Text>\n </View>\n </ScrollView>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const { bottom } = useSafeAreaInsets()\n return StyleSheet.create({\n container: {\n padding: 16,\n paddingBottom: bottom + 16,\n gap: 24,\n },\n fullHeight: {\n flex: 1,\n },\n description: {\n color: colors.textColorDefaultSecondary,\n },\n textInputContainer: {\n borderTopWidth: 1,\n borderBottomWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n paddingVertical: 12,\n paddingHorizontal: 16,\n marginHorizontal: -16,\n gap: 8,\n },\n textInput: {\n color: colors.textColorDefaultPrimary,\n fontSize: 16,\n textAlignVertical: 'top',\n minHeight: 120,\n maxHeight: 200,\n },\n attachmentSection: {\n gap: 8,\n },\n attachmentHeader: {\n flexDirection: 'row',\n gap: 4,\n alignItems: 'center',\n },\n attachmentLabel: { fontWeight: platformFontWeightBold },\n subLabel: { fontWeight: 'normal', color: colors.textColorDefaultSecondary },\n attachmentPreviewContainer: {\n gap: 4,\n },\n attachmentErrorText: {\n color: colors.statusErrorText,\n },\n attachButton: {\n alignSelf: 'flex-start',\n },\n footer: { gap: 8 },\n successIcon: {\n color: colors.statusSuccessIcon,\n fontSize: 48,\n },\n successTitle: {\n fontSize: 24,\n marginBottom: 4,\n },\n successSubtitle: {\n fontSize: 16,\n marginBottom: 4,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"bug_report_screen.js","sourceRoot":"","sources":["../../src/screens/bug_report_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACrE,OAAO,EACL,IAAI,EACJ,UAAU,EACV,SAAS,EACT,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,KAAK,GACN,MAAM,cAAc,CAAA;AAKrB,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAA;AACxD,OAAO,EACL,MAAM,EACN,OAAO,EACP,IAAI,EACJ,gBAAgB,EAChB,sBAAsB,EACtB,UAAU,EACV,IAAI,EACJ,YAAY,GACb,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AAC5D,OAAO,EAAE,WAAW,EAAqB,sBAAsB,EAAE,MAAM,UAAU,CAAA;AACjF,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,qDAAqD,CAAA;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAA;AAClE,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAA;AAC3D,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAA;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,gDAAgD,CAAA;AAEvF,MAAM,sBAAsB,GAAG,IAAI,CAAA;AAEnC,MAAM,gBAAgB,GAAG;IACvB,sCAAsC;IACtC,qCAAqC;IACrC,8BAA8B;IAC9B,0CAA0C;IAC1C,gCAAgC;IAChC,qCAAqC;IACrC,wBAAwB;IACxB,OAAO;CACR,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,CAAC,EACrC,UAAU,GACkB,EAAgC,EAAE,CAAC,CAAC;IAChE,YAAY,EAAE,OAAO;IACrB,KAAK,EAAE,cAAc;IACrB,UAAU,EAAE,GAAG,EAAE,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC,EAAG;CAC5F,CAAC,CAAA;AAQF,MAAM,UAAU,eAAe;IAC7B,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,UAAU,GAAG,aAAa,EAAE,CAAA;IAClC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC1C,MAAM,CAAC,iBAAiB,EAAE,oBAAoB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjE,MAAM,CAAC,aAAa,EAAE,gBAAgB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACpD,MAAM,CAAC,cAAc,EAAE,iBAAiB,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACxD,MAAM,SAAS,GAAG,eAAe,EAAE,CAAA;IACnC,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACjD,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAoB,IAAI,CAAC,CAAA;IACrE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAgB,IAAI,CAAC,CAAA;IACnE,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAA;IACnC,MAAM,SAAS,GACb,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QACzB,aAAa,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAC/B,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAC9B,cAAc,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC;QAChC,MAAM,KAAK,MAAM;QACjB,CAAC,SAAS,CAAA;IACZ,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAS,EAAE,CAAC,CAAA;IAElE,MAAM,iBAAiB,GAAG,UAAU,CAAC,UAAU,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;IAEhE,MAAM,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;QACpC,MAAM,WAAW,GAAG,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC;;;EAGxD,OAAO;;;EAGP,aAAa;;;EAGb,YAAY;;;EAGZ,cAAc,EAAE,CAAA;QAEd,MAAM,CAAC;YACL,WAAW;YACX,gBAAgB,EAAE,IAAI,CAAC,SAAS,CAAC;gBAC/B,OAAO;gBACP,aAAa;gBACb,YAAY;gBACZ,cAAc;aACf,CAAC;YACF,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;SACjD,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC,CAAA;IAE9E,MAAM,sBAAsB,GAAG,WAAW,CAAC,GAAG,EAAE;QAC9C,aAAa,CAAC,IAAI,CAAC,CAAA;QACnB,kBAAkB,CAAC,EAAE,CAAC,CAAA;IACxB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,SAAS,uBAAuB,CAAC,MAAyB;QACxD,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClD,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,OAAM;QACR,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAE9B,SAAS;YACP,EAAE,UAAU,CAAC;YACX,GAAG,EAAE,KAAK,CAAC,GAAG;YACd,IAAI,EAAE,KAAK,CAAC,QAAkB;YAC9B,IAAI,EAAE,KAAK,CAAC,QAAkB;SAC/B,CAAC;aACD,IAAI,CAAC,gBAAgB,CAAC,EAAE;YACvB,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,kBAAkB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC7B,aAAa,CAAC;gBACZ,EAAE,EAAE,gBAAgB,CAAC,EAAE;gBACvB,IAAI,EAAE,KAAK,CAAC,QAAQ,IAAI,MAAM;gBAC9B,IAAI,EAAE,KAAK,CAAC,QAAkB;aAC/B,CAAC,CAAA;QACJ,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,YAAY,CAAC,KAAK,CAAC,CAAA;YACnB,cAAc,CAAC,6BAA6B,CAAC,CAAA;QAC/C,CAAC,CAAC,CAAA;IACN,CAAC;IAED,SAAS,SAAS;QAChB,YAAY,CAAC,IAAI,CAAC,CAAA;QAClB,OAAO,WAAW,CAAC,qBAAqB,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC,CAAA;IAC5F,CAAC;IAED,eAAe,CAAC,GAAG,EAAE;QACnB,UAAU,CAAC,UAAU,CAAC;YACpB,+DAA+D;YAC/D,WAAW,EAAE,GAAG,EAAE,CAAC,CACjB,CAAC,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAC,EAAG,CACnF;SACF,CAAC,CAAA;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC,CAAA;IAEzC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,CACjD;QAAA,CAAC,cAAc,CAAC,AAAD,EACjB;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QACzB,OAAO,CACL,CAAC,UAAU,CACT,QAAQ,CAAC,qBAAqB,CAC9B,SAAS,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B,KAAK,CAAC,YAAY,CAClB,UAAU,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAChC,QAAQ,CAAC,sGAAsG,CAC/G,aAAa,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CACtC,WAAW,CAAC,CAAC;gBACX,KAAK,EAAE,gBAAgB;gBACvB,OAAO,EAAE,UAAU,CAAC,MAAM;gBAC1B,IAAI,EAAE,IAAI;gBACV,OAAO,EAAE,MAAM;aAChB,CAAC,EACF,CACH,CAAA;IACH,CAAC;IAED,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;QACvB,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;QAAA,CAAC,IAAI,CACH;;iEACuD,CAAC,GAAG,CAC3D;UAAA,CAAC,gBAAgB,CACf,iBAAiB,CAAC,MAAM,CACxB,OAAO,CAAC,CAAC,GAAG,EAAE,CACZ,OAAO,CAAC,OAAO,CAAC,gEAAgE,CAClF,CAAC,CAED;;UACF,EAAE,gBAAgB,CAClB;;QACF,EAAE,IAAI,CACN;QAAA,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,EACrF;MAAA,EAAE,IAAI,CAAC,CACR,CAAA;IACH,CAAC;IAED,OAAO,CACL,CAAC,YAAY,CACX;MAAA,CAAC,UAAU,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAClD;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;;;QAEF,EAAE,IAAI,CAEN;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CACrC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7B;iDAAqC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CAC5E;UAAA,EAAE,IAAI,CACN;UAAA,CAAC,gBAAgB,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,IAAI,CAAC,CAAC,CACtF;YAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,OAAO,IAAI,MAAM,CAAC,iBAAiB,CAAC,CAAC,CACrE;cAAA,CAAC,OAAO,IAAI,qBAAqB,CACnC;YAAA,EAAE,IAAI,CACN;YAAA,CAAC,IAAI,CACH,IAAI,CAAC,qBAAqB,CAC1B,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC1B,2BAA2B,EAE/B;UAAA,EAAE,gBAAgB,CACpB;QAAA,EAAE,IAAI,CAEN;;QAAA,CAAC,KAAK,CACJ,OAAO,CAAC,CAAC,iBAAiB,CAAC,CAC3B,aAAa,CAAC,OAAO,CACrB,iBAAiB,CAAC,WAAW,CAC7B,cAAc,CAAC,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,CAElD;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CACjC;YAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC9B;cAAA,CAAC,kBAAkB,CAAC,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,oBAAoB,CAAC,KAAK,CAAC,CAAC,EAC9E;cAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,eAAe,EAAE,IAAI,CACrD;cAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,EACxC;YAAA,EAAE,IAAI,CACN;YAAA,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CACrC;cAAA,CAAC,gBAAgB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAC9B,CAAC,gBAAgB,CACf,GAAG,CAAC,CAAC,MAAM,CAAC,CACZ,KAAK,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,CAC1B,OAAO,CAAC,CAAC,GAAG,EAAE;gBACZ,UAAU,CAAC,MAAM,CAAC,CAAA;gBAClB,oBAAoB,CAAC,KAAK,CAAC,CAAA;YAC7B,CAAC,CAAC,CAEF;kBAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,CACnD;kBAAA,CAAC,OAAO,KAAK,MAAM,IAAI,CACrB,CAAC,IAAI,CACH,IAAI,CAAC,eAAe,CACpB,KAAK,CAAC,CAAC,MAAM,CAAC,cAAc,CAAC,CAC7B,2BAA2B,EAC3B,CACH,CACH;gBAAA,EAAE,gBAAgB,CAAC,CACpB,CAAC,CACJ;YAAA,EAAE,UAAU,CACd;UAAA,EAAE,IAAI,CACR;QAAA,EAAE,KAAK,CAEP;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CACrC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7B;oEAAwD,CAAC,GAAG,CAC5D;YAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CACvC;UAAA,EAAE,IAAI,CACN;UAAA,CAAC,SAAS,CACR,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACxB,SAAS,CACT,WAAW,CAAC,aAAa,CACzB,KAAK,CAAC,CAAC,aAAa,CAAC,CACrB,YAAY,CAAC,CAAC,gBAAgB,CAAC,CAC/B,SAAS,CAAC,CAAC,sBAAsB,CAAC,EAEpC;UAAA,CAAC,aAAa,CAAC,MAAM,IAAI,sBAAsB,GAAG,GAAG,IAAI,CACvD,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CACtB;cAAA,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAChD;YAAA,EAAE,IAAI,CAAC,CACR,CACH;QAAA,EAAE,IAAI,CAEN;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CACrC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7B;kEAAsD,CAAC,GAAG,CAC1D;YAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CACvC;UAAA,EAAE,IAAI,CACN;UAAA,CAAC,SAAS,CACR,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACxB,SAAS,CACT,WAAW,CAAC,aAAa,CACzB,KAAK,CAAC,CAAC,YAAY,CAAC,CACpB,YAAY,CAAC,CAAC,eAAe,CAAC,CAC9B,SAAS,CAAC,CAAC,sBAAsB,CAAC,EAEpC;UAAA,CAAC,YAAY,CAAC,MAAM,IAAI,sBAAsB,GAAG,GAAG,IAAI,CACtD,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CACtB;cAAA,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CAC/C;YAAA,EAAE,IAAI,CAAC,CACR,CACH;QAAA,EAAE,IAAI,CAEN;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,kBAAkB,CAAC,CACrC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAC7B;4DAAgD,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,IAAI,CACvF;UAAA,EAAE,IAAI,CACN;UAAA,CAAC,SAAS,CACR,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CACxB,SAAS,CACT,WAAW,CAAC,aAAa,CACzB,KAAK,CAAC,CAAC,cAAc,CAAC,CACtB,YAAY,CAAC,CAAC,iBAAiB,CAAC,CAChC,SAAS,CAAC,CAAC,sBAAsB,CAAC,EAEpC;UAAA,CAAC,cAAc,CAAC,MAAM,IAAI,sBAAsB,GAAG,GAAG,IAAI,CACxD,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CACtB;cAAA,CAAC,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,sBAAsB,CACjD;YAAA,EAAE,IAAI,CAAC,CACR,CACH;QAAA,EAAE,IAAI,CAEN;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CACpC;UAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,gBAAgB,CAAC,CACnC;YAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC,CAClC;yBAAW,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,UAAU,EAAE,IAAI,CAC3D;YAAA,EAAE,IAAI,CACN;YAAA,CAAC,SAAS,IAAI,CAAC,OAAO,CAAC,AAAD,EAAG,CAC3B;UAAA,EAAE,IAAI,CACN;UAAA,CAAC,WAAW,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC,WAAW,CAAC,EAAE,IAAI,CAAC,CAC7E;UAAA,CAAC,UAAU,CAAC,CAAC,CAAC,CACZ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,0BAA0B,CAAC,CAC7C;cAAA,CAAC,iBAAiB,CAAC,CAAC,CAAC,CACnB,CAAC,sBAAsB,CACrB,GAAG,CAAC,CAAC,eAAe,CAAC,CACrB,QAAQ,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAC1B,aAAa,CAAC,CAAC,sBAAsB,CAAC,EACtC,CACH,CAAC,CAAC,CAAC,CACF,CAAC,sBAAsB,CACrB,IAAI,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CACtB,aAAa,CAAC,CAAC,sBAAsB,CAAC,EACtC,CACH,CACH;YAAA,EAAE,IAAI,CAAC,CACR,CAAC,CAAC,CAAC,CACF,CAAC,MAAM,CACL,KAAK,CAAC,qBAAqB,CAC3B,iBAAiB,CAAC,mCAAmC,CACrD,YAAY,CAAC,mBAAmB,CAChC,OAAO,CAAC,CAAC,SAAS,CAAC,CACnB,IAAI,CAAC,IAAI,CACT,OAAO,CAAC,SAAS,CACjB,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAC3B,QAAQ,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,EAC3C,CACH,CACH;QAAA,EAAE,IAAI,CAEN;;QAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CACzB;UAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CACtB;;;UAEF,EAAE,IAAI,CAEN;;UAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CACtB;gGAAoF,CAAC,GAAG,CACxF;YAAA,CAAC,gBAAgB,CACf,iBAAiB,CAAC,MAAM,CACxB,OAAO,CAAC,UAAU,CAClB,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,wCAAwC,CAAC,CAAC,CAEzE;;YACF,EAAE,gBAAgB,CAClB;;UACF,EAAE,IAAI,CACR;QAAA,EAAE,IAAI,CACR;MAAA,EAAE,UAAU,CACd;IAAA,EAAE,YAAY,CAAC,CAChB,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,MAAM,EAAE,MAAM,EAAE,GAAG,iBAAiB,EAAE,CAAA;IACtC,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,OAAO,EAAE,EAAE;YACX,aAAa,EAAE,MAAM,GAAG,EAAE;YAC1B,GAAG,EAAE,EAAE;SACR;QACD,UAAU,EAAE;YACV,IAAI,EAAE,CAAC;SACR;QACD,WAAW,EAAE;YACX,KAAK,EAAE,MAAM,CAAC,yBAAyB;SACxC;QACD,kBAAkB,EAAE;YAClB,GAAG,EAAE,CAAC;SACP;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,sBAAsB;YAClC,KAAK,EAAE,MAAM,CAAC,uBAAuB;SACtC;QACD,QAAQ,EAAE;YACR,KAAK,EAAE,MAAM,CAAC,eAAe;SAC9B;QACD,YAAY,EAAE;YACZ,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,MAAM,CAAC,sBAAsB;YAC1C,YAAY,EAAE,CAAC;YACf,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;YACnB,eAAe,EAAE,MAAM,CAAC,eAAe;YACvC,SAAS,EAAE,EAAE;SACd;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,uBAAuB;YACrC,IAAI,EAAE,CAAC;SACR;QACD,iBAAiB,EAAE;YACjB,KAAK,EAAE,MAAM,CAAC,yBAAyB;SACxC;QACD,WAAW,EAAE;YACX,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,yBAAyB;YACvC,UAAU,EAAE,CAAC;SACd;QACD,cAAc,EAAE;YACd,IAAI,EAAE,CAAC;YACP,eAAe,EAAE,MAAM,CAAC,eAAe;SACxC;QACD,WAAW,EAAE;YACX,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,OAAO,EAAE,EAAE;YACX,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,MAAM,CAAC,sBAAsB;SACjD;QACD,UAAU,EAAE;YACV,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,sBAAsB;YAClC,KAAK,EAAE,MAAM,CAAC,uBAAuB;SACtC;QACD,iBAAiB,EAAE;YACjB,KAAK,EAAE,EAAE,EAAE,8CAA8C;SAC1D;QACD,YAAY,EAAE;YACZ,IAAI,EAAE,CAAC;SACR;QACD,WAAW,EAAE;YACX,aAAa,EAAE,KAAK;YACpB,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,eAAe;YAC/B,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;YACnB,iBAAiB,EAAE,CAAC;YACpB,iBAAiB,EAAE,MAAM,CAAC,sBAAsB;SACjD;QACD,eAAe,EAAE;YACf,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,uBAAuB;YACrC,IAAI,EAAE,CAAC;SACR;QACD,cAAc,EAAE;YACd,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,MAAM,CAAC,iBAAiB;SAChC;QACD,SAAS,EAAE;YACT,KAAK,EAAE,MAAM,CAAC,uBAAuB;YACrC,QAAQ,EAAE,EAAE;YACZ,iBAAiB,EAAE,KAAK;YACxB,SAAS,EAAE,GAAG;YACd,SAAS,EAAE,GAAG;YACd,WAAW,EAAE,CAAC;YACd,WAAW,EAAE,MAAM,CAAC,sBAAsB;YAC1C,YAAY,EAAE,CAAC;YACf,iBAAiB,EAAE,EAAE;YACrB,eAAe,EAAE,EAAE;YACnB,eAAe,EAAE,MAAM,CAAC,eAAe;SACxC;QACD,iBAAiB,EAAE;YACjB,GAAG,EAAE,CAAC;SACP;QACD,gBAAgB,EAAE;YAChB,aAAa,EAAE,KAAK;YACpB,GAAG,EAAE,CAAC;YACN,UAAU,EAAE,QAAQ;SACrB;QACD,eAAe,EAAE,EAAE,UAAU,EAAE,sBAAsB,EAAE;QACvD,QAAQ,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,yBAAyB,EAAE;QAC3E,0BAA0B,EAAE;YAC1B,GAAG,EAAE,CAAC;SACP;QACD,mBAAmB,EAAE;YACnB,KAAK,EAAE,MAAM,CAAC,eAAe;SAC9B;QACD,YAAY,EAAE;YACZ,SAAS,EAAE,YAAY;SACxB;QACD,MAAM,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE;QAClB,WAAW,EAAE;YACX,KAAK,EAAE,MAAM,CAAC,iBAAiB;YAC/B,QAAQ,EAAE,EAAE;SACb;QACD,YAAY,EAAE;YACZ,QAAQ,EAAE,EAAE;YACZ,YAAY,EAAE,CAAC;SAChB;QACD,eAAe,EAAE;YACf,QAAQ,EAAE,EAAE;YACZ,YAAY,EAAE,CAAC;SAChB;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React, { useCallback, useLayoutEffect, useState } from 'react'\nimport {\n View,\n StyleSheet,\n TextInput,\n Linking,\n ScrollView,\n TouchableOpacity,\n Modal,\n} from 'react-native'\nimport type {\n NativeStackNavigationOptions,\n NativeStackScreenProps,\n} from '@react-navigation/native-stack'\nimport { useNavigation } from '@react-navigation/native'\nimport {\n Button,\n Spinner,\n Text,\n TextInlineButton,\n ImageAttachmentPreview,\n BlankState,\n Icon,\n KeyboardView,\n} from '../components'\nimport { useTheme } from '../hooks'\nimport { useUploadClient } from '../hooks/use_upload_client'\nimport { ImagePicker, ImagePickerResult, platformFontWeightBold } from '../utils'\nimport { useReportBugAction } from '../hooks/use_report_bug_action'\nimport {\n HeaderCancelButton,\n HeaderSubmitButton,\n} from '../components/display/platform_modal_header_buttons'\nimport { useSafeAreaInsets } from 'react-native-safe-area-context'\nimport { DefaultLoading } from '../components/page/loading'\nimport { startsWith } from 'lodash'\nimport { VideoAttachmentPreview } from '../components/display/video_attachment_preview'\n\nconst MAX_DESCRIPTION_LENGTH = 2000\n\nconst BUG_TYPE_OPTIONS = [\n 'Issues sending or receiving messages',\n 'Trouble starting a new conversation',\n \"Notifications aren't working\",\n 'Incorrect read receipts or unread counts',\n 'Problems with file attachments',\n \"Something isn't displaying properly\",\n 'App is slow or crashes',\n 'Other',\n]\n\nexport const BugReportScreenOptions = ({\n navigation,\n}: NativeStackScreenProps<any>): NativeStackNavigationOptions => ({\n presentation: 'modal',\n title: 'Report a bug',\n headerLeft: () => <HeaderCancelButton title=\"Cancel\" onPress={() => navigation.goBack()} />,\n})\n\ninterface Attachment {\n id: string\n name: string\n type: string\n}\n\nexport function BugReportScreen() {\n const styles = useStyles()\n const navigation = useNavigation()\n const [bugType, setBugType] = useState('')\n const [showBugTypePicker, setShowBugTypePicker] = useState(false)\n const [whatWereDoing, setWhatWereDoing] = useState('')\n const [whatExpected, setWhatExpected] = useState('')\n const [stepsToResolve, setStepsToResolve] = useState('')\n const uploadApi = useUploadClient()\n const [uploading, setUploading] = useState(false)\n const [attachment, setAttachment] = useState<Attachment | null>(null)\n const [uploadError, setUploadError] = useState<string | null>(null)\n const mutation = useReportBugAction()\n const { mutate, status } = mutation\n const formValid =\n bugType.trim().length > 0 &&\n whatWereDoing.trim().length > 0 &&\n whatExpected.trim().length > 0 &&\n stepsToResolve.trim().length > 0 &&\n status === 'idle' &&\n !uploading\n const [imagePreviewURI, setImagePreviewURI] = useState<string>('')\n\n const isImageAttachment = startsWith(attachment?.type, 'image/')\n\n const handleSubmit = useCallback(() => {\n const description = `${whatWereDoing.substring(0, 100)}\n\n## What kind of bug did you experience?\n${bugType}\n\n## What were you trying to do when you encountered the bug?\n${whatWereDoing}\n\n## What did you expect to happen? What actually happened?\n${whatExpected}\n\n## What steps have you tried to resolve the issue?\n${stepsToResolve}`\n\n mutate({\n description,\n description_json: JSON.stringify({\n bugType,\n whatWereDoing,\n whatExpected,\n stepsToResolve,\n }),\n attachmentIds: attachment ? [attachment.id] : [],\n })\n }, [attachment, bugType, whatWereDoing, whatExpected, stepsToResolve, mutate])\n\n const handleRemoveAttachment = useCallback(() => {\n setAttachment(null)\n setImagePreviewURI('')\n }, [])\n\n function uploadImagePickerResult(result: ImagePickerResult) {\n if (result.canceled || result.assets.length === 0) {\n setUploading(false)\n return\n }\n\n const asset = result.assets[0]\n\n uploadApi\n ?.uploadFile({\n uri: asset.uri,\n name: asset.fileName as string,\n type: asset.mimeType as string,\n })\n .then(uploadedResource => {\n setUploading(false)\n setImagePreviewURI(asset.uri)\n setAttachment({\n id: uploadedResource.id,\n name: asset.fileName || 'File',\n type: asset.mimeType as string,\n })\n })\n .catch(() => {\n setUploading(false)\n setUploadError(`Failed to upload attachment`)\n })\n }\n\n function pickImage() {\n setUploading(true)\n return ImagePicker.openImageLibraryAsync().then(result => uploadImagePickerResult(result))\n }\n\n useLayoutEffect(() => {\n navigation.setOptions({\n // eslint-disable-next-line react/no-unstable-nested-components\n headerRight: () => (\n <HeaderSubmitButton title=\"Submit\" onPress={handleSubmit} disabled={!formValid} />\n ),\n })\n }, [formValid, handleSubmit, navigation])\n\n if (status === 'pending') {\n return (\n <View style={[styles.container, styles.fullHeight]}>\n <DefaultLoading />\n </View>\n )\n }\n\n if (status === 'success') {\n return (\n <BlankState\n iconName=\"general.checkCircle\"\n iconStyle={styles.successIcon}\n title=\"Thank you!\"\n titleStyle={styles.successTitle}\n subtitle=\"We appreciate you taking the time to help improve chat! We'll take a look at the issue you reported.\"\n subtitleStyle={styles.successSubtitle}\n buttonProps={{\n title: 'Return to chat',\n onPress: navigation.goBack,\n size: 'lg',\n variant: 'fill',\n }}\n />\n )\n }\n\n if (status === 'error') {\n return (\n <View style={styles.container}>\n <Text>\n This is embarrassing, we can't submit your bug report right now. If you still need help or\n would like to submit this bug report another way please{' '}\n <TextInlineButton\n accessibilityRole=\"link\"\n onPress={() =>\n Linking.openURL('https://support.planningcenteronline.com/hc/en-us/requests/new')\n }\n >\n contact our help center\n </TextInlineButton>\n .\n </Text>\n <Button title=\"Return to chat\" onPress={navigation.goBack} variant=\"fill\" size=\"lg\" />\n </View>\n )\n }\n\n return (\n <KeyboardView>\n <ScrollView contentContainerStyle={styles.container}>\n <Text style={styles.description}>\n Thanks for helping us improve chat. Please provide details about the issue you've\n encountered. We read every submission and your feedback helps us improve the experience.\n </Text>\n\n <View style={styles.textInputContainer}>\n <Text style={styles.fieldLabel}>\n What kind of bug did you experience? <Text style={styles.required}>*</Text>\n </Text>\n <TouchableOpacity style={styles.pickerButton} onPress={() => setShowBugTypePicker(true)}>\n <Text style={[styles.pickerText, !bugType && styles.pickerPlaceholder]}>\n {bugType || 'Select the bug type'}\n </Text>\n <Icon\n name=\"general.downChevron\"\n style={styles.pickerArrow}\n accessibilityElementsHidden\n />\n </TouchableOpacity>\n </View>\n\n <Modal\n visible={showBugTypePicker}\n animationType=\"slide\"\n presentationStyle=\"pageSheet\"\n onRequestClose={() => setShowBugTypePicker(false)}\n >\n <View style={styles.modalContainer}>\n <View style={styles.modalHeader}>\n <HeaderCancelButton title=\"Cancel\" onPress={() => setShowBugTypePicker(false)} />\n <Text style={styles.modalTitle}>Select Bug Type</Text>\n <View style={styles.modalHeaderSpacer} />\n </View>\n <ScrollView style={styles.modalContent}>\n {BUG_TYPE_OPTIONS.map(option => (\n <TouchableOpacity\n key={option}\n style={styles.modalOption}\n onPress={() => {\n setBugType(option)\n setShowBugTypePicker(false)\n }}\n >\n <Text style={styles.modalOptionText}>{option}</Text>\n {bugType === option && (\n <Icon\n name=\"general.check\"\n style={styles.modalCheckmark}\n accessibilityElementsHidden\n />\n )}\n </TouchableOpacity>\n ))}\n </ScrollView>\n </View>\n </Modal>\n\n <View style={styles.textInputContainer}>\n <Text style={styles.fieldLabel}>\n What were you trying to do when you encountered the bug?{' '}\n <Text style={styles.required}>*</Text>\n </Text>\n <TextInput\n style={styles.textInput}\n multiline\n placeholder=\"Description\"\n value={whatWereDoing}\n onChangeText={setWhatWereDoing}\n maxLength={MAX_DESCRIPTION_LENGTH}\n />\n {whatWereDoing.length >= MAX_DESCRIPTION_LENGTH - 100 && (\n <Text variant=\"footnote\">\n {whatWereDoing.length}/{MAX_DESCRIPTION_LENGTH}\n </Text>\n )}\n </View>\n\n <View style={styles.textInputContainer}>\n <Text style={styles.fieldLabel}>\n What did you expect to happen? What actually happened?{' '}\n <Text style={styles.required}>*</Text>\n </Text>\n <TextInput\n style={styles.textInput}\n multiline\n placeholder=\"Description\"\n value={whatExpected}\n onChangeText={setWhatExpected}\n maxLength={MAX_DESCRIPTION_LENGTH}\n />\n {whatExpected.length >= MAX_DESCRIPTION_LENGTH - 100 && (\n <Text variant=\"footnote\">\n {whatExpected.length}/{MAX_DESCRIPTION_LENGTH}\n </Text>\n )}\n </View>\n\n <View style={styles.textInputContainer}>\n <Text style={styles.fieldLabel}>\n What steps have you tried to resolve the issue? <Text style={styles.required}>*</Text>\n </Text>\n <TextInput\n style={styles.textInput}\n multiline\n placeholder=\"Description\"\n value={stepsToResolve}\n onChangeText={setStepsToResolve}\n maxLength={MAX_DESCRIPTION_LENGTH}\n />\n {stepsToResolve.length >= MAX_DESCRIPTION_LENGTH - 100 && (\n <Text variant=\"footnote\">\n {stepsToResolve.length}/{MAX_DESCRIPTION_LENGTH}\n </Text>\n )}\n </View>\n\n <View style={styles.attachmentSection}>\n <View style={styles.attachmentHeader}>\n <Text style={styles.attachmentLabel}>\n Attachment <Text style={styles.subLabel}>(optional)</Text>\n </Text>\n {uploading && <Spinner />}\n </View>\n {uploadError && <Text style={styles.attachmentErrorText}>{uploadError}</Text>}\n {attachment ? (\n <View style={styles.attachmentPreviewContainer}>\n {isImageAttachment ? (\n <ImageAttachmentPreview\n uri={imagePreviewURI}\n fileName={attachment.name}\n onRemovePress={handleRemoveAttachment}\n />\n ) : (\n <VideoAttachmentPreview\n name={attachment.name}\n onRemovePress={handleRemoveAttachment}\n />\n )}\n </View>\n ) : (\n <Button\n title=\"Attach a screenshot\"\n accessibilityHint=\"Opens your device's image gallery\"\n iconNameLeft=\"general.paperclip\"\n onPress={pickImage}\n size=\"sm\"\n variant=\"outline\"\n style={styles.attachButton}\n disabled={uploading || Boolean(attachment)}\n />\n )}\n </View>\n\n <View style={styles.footer}>\n <Text variant=\"footnote\">\n We can’t respond to every submission, but we may reach out if we have additional\n questions.\n </Text>\n\n <Text variant=\"footnote\">\n For details on how we process your data and ensure its security, please refer to our{' '}\n <TextInlineButton\n accessibilityRole=\"link\"\n variant=\"footnote\"\n onPress={() => Linking.openURL('https://www.planningcenter.com/privacy')}\n >\n Privacy Policy\n </TextInlineButton>\n .\n </Text>\n </View>\n </ScrollView>\n </KeyboardView>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n const { bottom } = useSafeAreaInsets()\n return StyleSheet.create({\n container: {\n padding: 16,\n paddingBottom: bottom + 16,\n gap: 24,\n },\n fullHeight: {\n flex: 1,\n },\n description: {\n color: colors.textColorDefaultSecondary,\n },\n textInputContainer: {\n gap: 8,\n },\n fieldLabel: {\n fontSize: 16,\n fontWeight: platformFontWeightBold,\n color: colors.textColorDefaultPrimary,\n },\n required: {\n color: colors.statusErrorText,\n },\n pickerButton: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n borderWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n borderRadius: 8,\n paddingHorizontal: 16,\n paddingVertical: 12,\n backgroundColor: colors.surfaceColor100,\n minHeight: 48,\n },\n pickerText: {\n fontSize: 16,\n color: colors.textColorDefaultPrimary,\n flex: 1,\n },\n pickerPlaceholder: {\n color: colors.textColorDefaultSecondary,\n },\n pickerArrow: {\n fontSize: 12,\n color: colors.iconColorDefaultSecondary,\n marginLeft: 8,\n },\n modalContainer: {\n flex: 1,\n backgroundColor: colors.surfaceColor100,\n },\n modalHeader: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n padding: 16,\n borderBottomWidth: 1,\n borderBottomColor: colors.borderColorDefaultBase,\n },\n modalTitle: {\n fontSize: 18,\n fontWeight: platformFontWeightBold,\n color: colors.textColorDefaultPrimary,\n },\n modalHeaderSpacer: {\n width: 50, // Same width as cancel button to center title\n },\n modalContent: {\n flex: 1,\n },\n modalOption: {\n flexDirection: 'row',\n alignItems: 'center',\n justifyContent: 'space-between',\n paddingHorizontal: 16,\n paddingVertical: 16,\n borderBottomWidth: 1,\n borderBottomColor: colors.borderColorDefaultBase,\n },\n modalOptionText: {\n fontSize: 16,\n color: colors.textColorDefaultPrimary,\n flex: 1,\n },\n modalCheckmark: {\n fontSize: 16,\n color: colors.statusSuccessIcon,\n },\n textInput: {\n color: colors.textColorDefaultPrimary,\n fontSize: 16,\n textAlignVertical: 'top',\n minHeight: 120,\n maxHeight: 200,\n borderWidth: 1,\n borderColor: colors.borderColorDefaultBase,\n borderRadius: 8,\n paddingHorizontal: 16,\n paddingVertical: 12,\n backgroundColor: colors.surfaceColor100,\n },\n attachmentSection: {\n gap: 8,\n },\n attachmentHeader: {\n flexDirection: 'row',\n gap: 4,\n alignItems: 'center',\n },\n attachmentLabel: { fontWeight: platformFontWeightBold },\n subLabel: { fontWeight: 'normal', color: colors.textColorDefaultSecondary },\n attachmentPreviewContainer: {\n gap: 4,\n },\n attachmentErrorText: {\n color: colors.statusErrorText,\n },\n attachButton: {\n alignSelf: 'flex-start',\n },\n footer: { gap: 8 },\n successIcon: {\n color: colors.statusSuccessIcon,\n fontSize: 48,\n },\n successTitle: {\n fontSize: 24,\n marginBottom: 4,\n },\n successSubtitle: {\n fontSize: 16,\n marginBottom: 4,\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"groups_form.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAyC,MAAM,OAAO,CAAA;AAY7D,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAA;AAIjE,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,UAAU,qCAAsC,eAAe,sBAyD3E,CAAA"}
1
+ {"version":3,"file":"groups_form.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/groups_form.tsx"],"names":[],"mappings":"AACA,OAAO,KAAiD,MAAM,OAAO,CAAA;AAYrE,OAAO,EAAE,OAAO,EAAE,MAAM,yCAAyC,CAAA;AAIjE,KAAK,eAAe,GAAG;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B,CAAA;AAED,eAAO,MAAM,UAAU,qCAAsC,eAAe,sBAyD3E,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { StackActions, useNavigation } from '@react-navigation/native';
2
- import React, { useCallback, useMemo, useState } from 'react';
3
- import { Platform, StyleSheet, TextInput, View } from 'react-native';
2
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
3
+ import { Platform, Pressable, StyleSheet, TextInput, View } from 'react-native';
4
4
  import { Banner, ChildNotice, Heading, Text } from '../../../components';
5
5
  import { ActionButton } from '../../../components/display/action_button';
6
6
  import { KeyboardView } from '../../../components/display/keyboard_view';
@@ -41,6 +41,7 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }) => {
41
41
  };
42
42
  function FormContent({ group, title, setTitle, groupMemberships }) {
43
43
  const styles = useStyles();
44
+ const inputRef = useRef(null);
44
45
  const currentPerson = useCurrentPerson();
45
46
  const { name, membershipsCount } = group;
46
47
  const myGroupsMembership = useMemo(() => groupMemberships.data.find(m => m.id === currentPerson.id), [groupMemberships.data, currentPerson.id]);
@@ -49,16 +50,19 @@ function FormContent({ group, title, setTitle, groupMemberships }) {
49
50
  const hasChildren = childMembers.length > 0;
50
51
  const memberHeaderLabel = `${pluralize(membershipsCount, 'member')} selected`;
51
52
  const showMemberError = groupMemberships.isError;
53
+ const handleTitleSectionPress = useCallback(() => {
54
+ inputRef.current?.focus();
55
+ }, []);
52
56
  return (<View style={styles.formContent}>
53
57
  <View style={styles.toSection}>
54
58
  <Heading variant="h3">To:</Heading>
55
59
  <Text style={styles.groupName}>{name}</Text>
56
60
  </View>
57
61
  <Divider />
58
- <View style={styles.titleSection}>
62
+ <Pressable style={styles.titleSection} onPress={handleTitleSectionPress}>
59
63
  <Heading variant="h3">Title</Heading>
60
- <TextInput placeholder="Topic of conversation (required)" value={title} onChangeText={setTitle} style={styles.titleInput} autoFocus={true}/>
61
- </View>
64
+ <TextInput placeholder="Topic of conversation (required)" value={title} onChangeText={setTitle} style={styles.titleInput} autoFocus={true} ref={inputRef}/>
65
+ </Pressable>
62
66
  <Divider />
63
67
  <View style={styles.memberSection}>
64
68
  <Heading variant="h3">{memberHeaderLabel}</Heading>
@@ -73,7 +77,7 @@ const useStyles = () => {
73
77
  const inputPadding = 8;
74
78
  return StyleSheet.create({
75
79
  formContent: {
76
- paddingVertical: sectionPadding,
80
+ paddingBottom: sectionPadding,
77
81
  flex: 1,
78
82
  },
79
83
  toSection: {
@@ -83,6 +87,7 @@ const useStyles = () => {
83
87
  },
84
88
  groupName: {
85
89
  fontSize: 18,
90
+ flex: 1,
86
91
  },
87
92
  titleSection: {
88
93
  padding: sectionPadding,