@planningcenter/chat-react-native 3.32.1-rc.1 → 3.33.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.
Files changed (171) hide show
  1. package/build/components/conversation/message_form.d.ts.map +1 -1
  2. package/build/components/conversation/message_form.js +22 -1
  3. package/build/components/conversation/message_form.js.map +1 -1
  4. package/build/components/display/emoji_avatar.d.ts.map +1 -1
  5. package/build/components/display/emoji_avatar.js +2 -0
  6. package/build/components/display/emoji_avatar.js.map +1 -1
  7. package/build/components/display/icon_avatar.d.ts.map +1 -1
  8. package/build/components/display/icon_avatar.js +2 -0
  9. package/build/components/display/icon_avatar.js.map +1 -1
  10. package/build/components/display/utils/avatar_gradient_colors.d.ts +3 -0
  11. package/build/components/display/utils/avatar_gradient_colors.d.ts.map +1 -1
  12. package/build/components/display/utils/avatar_gradient_colors.js +8 -3
  13. package/build/components/display/utils/avatar_gradient_colors.js.map +1 -1
  14. package/build/components/primitive/avatar_primitive.d.ts +3 -1
  15. package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
  16. package/build/components/primitive/avatar_primitive.js +10 -2
  17. package/build/components/primitive/avatar_primitive.js.map +1 -1
  18. package/build/hooks/attachments/fallback_chat_configuration.d.ts +4 -0
  19. package/build/hooks/attachments/fallback_chat_configuration.d.ts.map +1 -0
  20. package/build/hooks/attachments/fallback_chat_configuration.js +59 -0
  21. package/build/hooks/attachments/fallback_chat_configuration.js.map +1 -0
  22. package/build/hooks/groups/use_groups_conversation_create.d.ts.map +1 -1
  23. package/build/hooks/groups/use_groups_conversation_create.js +1 -1
  24. package/build/hooks/groups/use_groups_conversation_create.js.map +1 -1
  25. package/build/hooks/services/use_find_or_create_services_conversation.d.ts +43 -11
  26. package/build/hooks/services/use_find_or_create_services_conversation.d.ts.map +1 -1
  27. package/build/hooks/services/use_find_or_create_services_conversation.js +5 -5
  28. package/build/hooks/services/use_find_or_create_services_conversation.js.map +1 -1
  29. package/build/hooks/use_attachment_uploader.d.ts.map +1 -1
  30. package/build/hooks/use_attachment_uploader.js +39 -14
  31. package/build/hooks/use_attachment_uploader.js.map +1 -1
  32. package/build/hooks/use_chat_configuration.d.ts +6 -0
  33. package/build/hooks/use_chat_configuration.d.ts.map +1 -0
  34. package/build/hooks/use_chat_configuration.js +41 -0
  35. package/build/hooks/use_chat_configuration.js.map +1 -0
  36. package/build/hooks/use_conversation_avatar_update.d.ts +26 -0
  37. package/build/hooks/use_conversation_avatar_update.d.ts.map +1 -0
  38. package/build/hooks/use_conversation_avatar_update.js +130 -0
  39. package/build/hooks/use_conversation_avatar_update.js.map +1 -0
  40. package/build/hooks/use_features.d.ts +1 -0
  41. package/build/hooks/use_features.d.ts.map +1 -1
  42. package/build/hooks/use_features.js +1 -0
  43. package/build/hooks/use_features.js.map +1 -1
  44. package/build/navigation/index.d.ts +16 -0
  45. package/build/navigation/index.d.ts.map +1 -1
  46. package/build/navigation/index.js +9 -0
  47. package/build/navigation/index.js.map +1 -1
  48. package/build/screens/avatar_picker/avatar_picker_screen.d.ts +12 -0
  49. package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -0
  50. package/build/screens/avatar_picker/avatar_picker_screen.js +193 -0
  51. package/build/screens/avatar_picker/avatar_picker_screen.js.map +1 -0
  52. package/build/screens/avatar_picker/avatar_picker_state.d.ts +38 -0
  53. package/build/screens/avatar_picker/avatar_picker_state.d.ts.map +1 -0
  54. package/build/screens/avatar_picker/avatar_picker_state.js +101 -0
  55. package/build/screens/avatar_picker/avatar_picker_state.js.map +1 -0
  56. package/build/screens/avatar_picker/avatar_preview.d.ts +9 -0
  57. package/build/screens/avatar_picker/avatar_preview.d.ts.map +1 -0
  58. package/build/screens/avatar_picker/avatar_preview.js +39 -0
  59. package/build/screens/avatar_picker/avatar_preview.js.map +1 -0
  60. package/build/screens/avatar_picker/color_picker.d.ts +9 -0
  61. package/build/screens/avatar_picker/color_picker.d.ts.map +1 -0
  62. package/build/screens/avatar_picker/color_picker.js +53 -0
  63. package/build/screens/avatar_picker/color_picker.js.map +1 -0
  64. package/build/screens/avatar_picker/constants.d.ts +3 -0
  65. package/build/screens/avatar_picker/constants.d.ts.map +1 -0
  66. package/build/screens/avatar_picker/constants.js +53 -0
  67. package/build/screens/avatar_picker/constants.js.map +1 -0
  68. package/build/screens/avatar_picker/emoji_tab.d.ts +7 -0
  69. package/build/screens/avatar_picker/emoji_tab.d.ts.map +1 -0
  70. package/build/screens/avatar_picker/emoji_tab.js +55 -0
  71. package/build/screens/avatar_picker/emoji_tab.js.map +1 -0
  72. package/build/screens/avatar_picker/icon_grid.d.ts +8 -0
  73. package/build/screens/avatar_picker/icon_grid.d.ts.map +1 -0
  74. package/build/screens/avatar_picker/icon_grid.js +48 -0
  75. package/build/screens/avatar_picker/icon_grid.js.map +1 -0
  76. package/build/screens/avatar_picker/upload_tab.d.ts +9 -0
  77. package/build/screens/avatar_picker/upload_tab.d.ts.map +1 -0
  78. package/build/screens/avatar_picker/upload_tab.js +39 -0
  79. package/build/screens/avatar_picker/upload_tab.js.map +1 -0
  80. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  81. package/build/screens/conversation_details_screen.js +37 -1
  82. package/build/screens/conversation_details_screen.js.map +1 -1
  83. package/build/screens/conversation_new/components/avatar_selection_row.d.ts +12 -0
  84. package/build/screens/conversation_new/components/avatar_selection_row.d.ts.map +1 -0
  85. package/build/screens/conversation_new/components/avatar_selection_row.js +60 -0
  86. package/build/screens/conversation_new/components/avatar_selection_row.js.map +1 -0
  87. package/build/screens/conversation_new/components/gender_filter_toggle.d.ts.map +1 -1
  88. package/build/screens/conversation_new/components/gender_filter_toggle.js +3 -9
  89. package/build/screens/conversation_new/components/gender_filter_toggle.js.map +1 -1
  90. package/build/screens/conversation_new/components/groups_form.d.ts +3 -1
  91. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  92. package/build/screens/conversation_new/components/groups_form.js +22 -8
  93. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  94. package/build/screens/conversation_new/components/services_form.d.ts +3 -1
  95. package/build/screens/conversation_new/components/services_form.d.ts.map +1 -1
  96. package/build/screens/conversation_new/components/services_form.js +22 -8
  97. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  98. package/build/screens/conversation_new/conversation_new_screen.d.ts +2 -0
  99. package/build/screens/conversation_new/conversation_new_screen.d.ts.map +1 -1
  100. package/build/screens/conversation_new/conversation_new_screen.js +3 -3
  101. package/build/screens/conversation_new/conversation_new_screen.js.map +1 -1
  102. package/build/screens/team_conversation_screen.d.ts.map +1 -1
  103. package/build/screens/team_conversation_screen.js +1 -1
  104. package/build/screens/team_conversation_screen.js.map +1 -1
  105. package/build/types/resources/chat_configuration_resource.d.ts +8 -0
  106. package/build/types/resources/chat_configuration_resource.d.ts.map +1 -0
  107. package/build/types/resources/chat_configuration_resource.js +2 -0
  108. package/build/types/resources/chat_configuration_resource.js.map +1 -0
  109. package/build/utils/native_adapters/configuration.d.ts +3 -0
  110. package/build/utils/native_adapters/configuration.d.ts.map +1 -1
  111. package/build/utils/native_adapters/configuration.js +8 -0
  112. package/build/utils/native_adapters/configuration.js.map +1 -1
  113. package/build/utils/native_adapters/document_picker.d.ts +21 -0
  114. package/build/utils/native_adapters/document_picker.d.ts.map +1 -0
  115. package/build/utils/native_adapters/document_picker.js +7 -0
  116. package/build/utils/native_adapters/document_picker.js.map +1 -0
  117. package/build/utils/native_adapters/image_picker.d.ts +7 -1
  118. package/build/utils/native_adapters/image_picker.d.ts.map +1 -1
  119. package/build/utils/native_adapters/image_picker.js.map +1 -1
  120. package/build/utils/native_adapters/index.d.ts +1 -0
  121. package/build/utils/native_adapters/index.d.ts.map +1 -1
  122. package/build/utils/native_adapters/index.js +1 -0
  123. package/build/utils/native_adapters/index.js.map +1 -1
  124. package/build/utils/request/get_chat_configuration.d.ts +10 -0
  125. package/build/utils/request/get_chat_configuration.d.ts.map +1 -0
  126. package/build/utils/request/get_chat_configuration.js +21 -0
  127. package/build/utils/request/get_chat_configuration.js.map +1 -0
  128. package/package.json +4 -3
  129. package/src/__tests__/hooks/use_attachment_uploader.test.tsx +219 -0
  130. package/src/__tests__/hooks/use_chat_configuration.test.tsx +80 -0
  131. package/src/__tests__/utils/native_adapters/configuration.ts +25 -1
  132. package/src/components/conversation/message_form.tsx +39 -1
  133. package/src/components/display/emoji_avatar.tsx +7 -2
  134. package/src/components/display/icon_avatar.tsx +7 -2
  135. package/src/components/display/utils/avatar_gradient_colors.ts +10 -3
  136. package/src/components/primitive/avatar_primitive.tsx +11 -2
  137. package/src/hooks/attachments/fallback_chat_configuration.ts +61 -0
  138. package/src/hooks/groups/use_groups_conversation_create.ts +2 -1
  139. package/src/hooks/services/use_find_or_create_services_conversation.ts +7 -7
  140. package/src/hooks/use_attachment_uploader.ts +39 -15
  141. package/src/hooks/use_chat_configuration.ts +54 -0
  142. package/src/hooks/use_conversation_avatar_update.ts +163 -0
  143. package/src/hooks/use_features.ts +1 -0
  144. package/src/navigation/index.tsx +13 -0
  145. package/src/screens/avatar_picker/__tests__/avatar_picker_state.test.ts +157 -0
  146. package/src/screens/avatar_picker/avatar_picker_screen.tsx +312 -0
  147. package/src/screens/avatar_picker/avatar_picker_state.ts +141 -0
  148. package/src/screens/avatar_picker/avatar_preview.tsx +46 -0
  149. package/src/screens/avatar_picker/color_picker.tsx +91 -0
  150. package/src/screens/avatar_picker/constants.ts +53 -0
  151. package/src/screens/avatar_picker/emoji_tab.tsx +76 -0
  152. package/src/screens/avatar_picker/icon_grid.tsx +81 -0
  153. package/src/screens/avatar_picker/upload_tab.tsx +62 -0
  154. package/src/screens/conversation_details_screen.tsx +60 -1
  155. package/src/screens/conversation_new/components/avatar_selection_row.tsx +82 -0
  156. package/src/screens/conversation_new/components/gender_filter_toggle.tsx +3 -9
  157. package/src/screens/conversation_new/components/groups_form.tsx +33 -6
  158. package/src/screens/conversation_new/components/services_form.tsx +37 -6
  159. package/src/screens/conversation_new/conversation_new_screen.tsx +17 -3
  160. package/src/screens/team_conversation_screen.tsx +2 -1
  161. package/src/types/resources/chat_configuration_resource.ts +11 -0
  162. package/src/utils/native_adapters/configuration.ts +10 -0
  163. package/src/utils/native_adapters/document_picker.ts +26 -0
  164. package/src/utils/native_adapters/image_picker.ts +8 -1
  165. package/src/utils/native_adapters/index.ts +1 -0
  166. package/src/utils/request/get_chat_configuration.ts +23 -0
  167. package/build/hooks/attachments/supported_extensions.d.ts +0 -2
  168. package/build/hooks/attachments/supported_extensions.d.ts.map +0 -1
  169. package/build/hooks/attachments/supported_extensions.js +0 -48
  170. package/build/hooks/attachments/supported_extensions.js.map +0 -1
  171. package/src/hooks/attachments/supported_extensions.ts +0 -47
@@ -4,30 +4,42 @@ 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'
7
- import { useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'
7
+ import { useApiClient, useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'
8
8
  import {
9
9
  GroupMembersForNewConversationResult,
10
10
  useGroupMembersForNewConversation,
11
11
  } from '../../../hooks/groups/use_group_members_for_new_conversation'
12
12
  import { useGroupsConversationCreate } from '../../../hooks/groups/use_groups_conversation_create'
13
+ import {
14
+ type AvatarUpdatePayload,
15
+ patchConversationAvatar,
16
+ } from '../../../hooks/use_conversation_avatar_update'
17
+ import { availableFeatures, useFeatures } from '../../../hooks/use_features'
13
18
  import { useMyGender } from '../../../hooks/use_my_gender'
19
+ import { useUploadClient } from '../../../hooks/use_upload_client'
14
20
  import { GroupsGroupResource } from '../../../types'
15
21
  import { GraphId } from '../../../types/resources/group_resource'
16
22
  import { pluralize } from '../../../utils'
17
23
  import { genderDisplayLabel } from '../../../utils/gender_display_label'
18
24
  import { Haptic } from '../../../utils/native_adapters'
25
+ import { AvatarSelectionRow } from './avatar_selection_row'
19
26
  import { Divider, FormList } from './form_list'
20
27
  import { GenderFilterToggle } from './gender_filter_toggle'
21
28
 
22
29
  type GroupsFormProps = {
23
30
  groupId: number
24
31
  chat_group_graph_id?: GraphId
32
+ avatarSelection?: AvatarUpdatePayload
25
33
  }
26
34
 
27
- export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) => {
35
+ export const GroupsForm = ({ groupId, chat_group_graph_id, avatarSelection }: GroupsFormProps) => {
28
36
  const navigation = useNavigation()
37
+ const apiClient = useApiClient()
38
+ const uploadClient = useUploadClient()
29
39
  const [title, setTitle] = useState('')
30
40
  const [genderFilterEnabled, setGenderFilterEnabled] = useState(false)
41
+ const { featureEnabled } = useFeatures()
42
+ const customAvatarsEnabled = featureEnabled(availableFeatures.custom_conversation_avatars)
31
43
  const {
32
44
  isFeatureEnabled: genderFilterAvailable,
33
45
  genderId,
@@ -67,9 +79,8 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
67
79
  }
68
80
  }
69
81
 
70
- const redirectToConversation = useCallback(
82
+ const handleCreateSuccess = useCallback(
71
83
  (conversationId: number) => {
72
- // navigate to the conversation screen
73
84
  navigation.dispatch(
74
85
  StackActions.popTo('Conversation', {
75
86
  conversation_id: conversationId,
@@ -77,15 +88,19 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
77
88
  })
78
89
  )
79
90
  Haptic.notificationSuccess()
91
+
92
+ if (avatarSelection && avatarSelection.kind !== 'clear') {
93
+ patchConversationAvatar(apiClient, uploadClient, conversationId, avatarSelection)
94
+ }
80
95
  },
81
- [chat_group_graph_id, navigation]
96
+ [apiClient, avatarSelection, chat_group_graph_id, navigation, uploadClient]
82
97
  )
83
98
 
84
99
  const { mutate: handleSave, isPending } = useGroupsConversationCreate({
85
100
  groupId,
86
101
  title,
87
102
  genderId: activeGenderId,
88
- onSuccess: redirectToConversation,
103
+ onSuccess: handleCreateSuccess,
89
104
  })
90
105
 
91
106
  return (
@@ -106,6 +121,8 @@ export const GroupsForm = ({ groupId, chat_group_graph_id }: GroupsFormProps) =>
106
121
  onGenderToggle={handleGenderToggle}
107
122
  groupMemberships={groupMemberships}
108
123
  filteredMemberCount={groupMemberships.adultMembers.length}
124
+ avatarSelection={avatarSelection}
125
+ customAvatarsEnabled={customAvatarsEnabled}
109
126
  />
110
127
  }
111
128
  />
@@ -130,6 +147,8 @@ interface FormContentProps {
130
147
  onGenderToggle: (enabled: boolean) => void
131
148
  groupMemberships: GroupMembersForNewConversationResult
132
149
  filteredMemberCount: number
150
+ avatarSelection?: AvatarUpdatePayload
151
+ customAvatarsEnabled: boolean
133
152
  }
134
153
 
135
154
  function FormContent({
@@ -143,6 +162,8 @@ function FormContent({
143
162
  onGenderToggle,
144
163
  groupMemberships,
145
164
  filteredMemberCount,
165
+ avatarSelection,
166
+ customAvatarsEnabled,
146
167
  }: FormContentProps) {
147
168
  const styles = useStyles()
148
169
  const inputRef = useRef<TextInput>(null)
@@ -185,6 +206,12 @@ function FormContent({
185
206
  />
186
207
  </Pressable>
187
208
  <Divider />
209
+ {customAvatarsEnabled && (
210
+ <>
211
+ <AvatarSelectionRow avatarSelection={avatarSelection} />
212
+ <Divider />
213
+ </>
214
+ )}
188
215
  {genderFilterAvailable && (
189
216
  <>
190
217
  <GenderFilterToggle
@@ -4,14 +4,22 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'
4
4
  import { StyleSheet, View } from 'react-native'
5
5
  import { Badge, Banner, ChildNotice, Heading, Switch, TextButton } from '../../../components'
6
6
  import { ActionButton } from '../../../components/display/action_button'
7
+ import { useApiClient } from '../../../hooks'
7
8
  import { useFindOrCreateServicesConversation } from '../../../hooks/services/use_find_or_create_services_conversation'
8
9
  import { useServicesTeams } from '../../../hooks/services/use_services_team'
9
10
  import { useTeamMembersForNewConversation } from '../../../hooks/services/use_team_members_for_new_conversation'
10
- import { ConversationResource, MemberResource } from '../../../types'
11
+ import {
12
+ type AvatarUpdatePayload,
13
+ patchConversationAvatar,
14
+ } from '../../../hooks/use_conversation_avatar_update'
15
+ import { availableFeatures, useFeatures } from '../../../hooks/use_features'
16
+ import { useUploadClient } from '../../../hooks/use_upload_client'
17
+ import { MemberResource } from '../../../types'
11
18
  import { pluralize } from '../../../utils'
12
19
  import { Haptic } from '../../../utils/native_adapters'
13
20
  import { tokens } from '../../../vendor/tapestry/tokens'
14
21
  import { TeamFilterTypes } from '../../conversation_filter_recipients/types'
22
+ import { AvatarSelectionRow } from './avatar_selection_row'
15
23
  import { FilterByPlan } from './filter_by_plan'
16
24
  import { Divider, FormList } from './form_list'
17
25
 
@@ -19,14 +27,20 @@ type ServicesFormProps = {
19
27
  initialTeamIds?: number[]
20
28
  initialPlanId?: number
21
29
  teamFilterType?: TeamFilterTypes
30
+ avatarSelection?: AvatarUpdatePayload
22
31
  }
23
32
 
24
33
  export const ServicesForm = ({
25
34
  initialTeamIds,
26
35
  initialPlanId,
27
36
  teamFilterType,
37
+ avatarSelection,
28
38
  }: ServicesFormProps) => {
29
39
  const styles = useStyles()
40
+ const apiClient = useApiClient()
41
+ const uploadClient = useUploadClient()
42
+ const { featureEnabled } = useFeatures()
43
+ const customAvatarsEnabled = featureEnabled(availableFeatures.custom_conversation_avatars)
30
44
  const [selectedPlanId, setSelectedPlanId] = useState<number | undefined>(initialPlanId)
31
45
  const initialState = useMemo(() => uniq(initialTeamIds) || [], [initialTeamIds]) // Uniq here because services can send duplicates in the teams_i_lead response.
32
46
  const [selectedTeamIds, setSelectedTeamIds] = useState<number[]>(initialState)
@@ -61,17 +75,19 @@ export const ServicesForm = ({
61
75
  } = useFindOrCreateServicesConversation({
62
76
  teamIds: selectedTeamIds,
63
77
  planId: filerByPlan ? selectedPlanId : undefined,
64
- onSuccess: (conversation: ConversationResource) => {
65
- // exit from the create stack
78
+ onSuccess: (conversation, { created }) => {
66
79
  navigation.getParent()?.goBack()
67
- // navigate to the conversation screen
68
80
  navigation.dispatch(
69
81
  StackActions.push('Conversation', {
70
82
  conversation_id: conversation.id,
71
83
  })
72
84
  )
73
- // Only trigger success haptic if creating a new conversation
74
- if (!selectionHasConversation) Haptic.notificationSuccess()
85
+ if (created) {
86
+ Haptic.notificationSuccess()
87
+ if (avatarSelection && avatarSelection.kind !== 'clear') {
88
+ patchConversationAvatar(apiClient, uploadClient, conversation.id, avatarSelection)
89
+ }
90
+ }
75
91
  },
76
92
  })
77
93
 
@@ -90,6 +106,9 @@ export const ServicesForm = ({
90
106
  members={members}
91
107
  isMemberError={isMemberError}
92
108
  teamFilterType={teamFilterType}
109
+ avatarSelection={avatarSelection}
110
+ selectionHasConversation={selectionHasConversation}
111
+ customAvatarsEnabled={customAvatarsEnabled}
93
112
  />
94
113
  }
95
114
  />
@@ -114,6 +133,9 @@ interface FormContentProps {
114
133
  members: MemberResource[]
115
134
  isMemberError: boolean
116
135
  teamFilterType?: TeamFilterTypes
136
+ avatarSelection?: AvatarUpdatePayload
137
+ selectionHasConversation: boolean
138
+ customAvatarsEnabled: boolean
117
139
  }
118
140
 
119
141
  function FormContent({
@@ -126,6 +148,9 @@ function FormContent({
126
148
  members,
127
149
  isMemberError,
128
150
  teamFilterType,
151
+ avatarSelection,
152
+ selectionHasConversation,
153
+ customAvatarsEnabled,
129
154
  }: FormContentProps) {
130
155
  const navigation = useNavigation()
131
156
  const servicesTeams = useServicesTeams()
@@ -205,6 +230,12 @@ function FormContent({
205
230
  )}
206
231
  </View>
207
232
  <Divider />
233
+ {!selectionHasConversation && customAvatarsEnabled && (
234
+ <>
235
+ <AvatarSelectionRow avatarSelection={avatarSelection} />
236
+ <Divider />
237
+ </>
238
+ )}
208
239
  <View style={styles.memberSection}>
209
240
  <Heading variant="h3">{pluralize(memberCount, 'member')} selected</Heading>
210
241
  {hasChildren && (
@@ -1,5 +1,6 @@
1
1
  import { StaticScreenProps } from '@react-navigation/native'
2
2
  import React from 'react'
3
+ import type { AvatarUpdatePayload } from '../../hooks/use_conversation_avatar_update'
3
4
  import { AppName } from '../../types/resources/app_name'
4
5
  import { GraphId } from '../../types/resources/group_resource'
5
6
  import { TeamFilterTypes } from '../conversation_filter_recipients/types'
@@ -15,16 +16,28 @@ type ConversationNewScreenProps = StaticScreenProps<{
15
16
  source_app_name: AppName
16
17
  chat_group_graph_id?: GraphId
17
18
  group_source_app_name?: AppName
19
+ avatar_selection?: AvatarUpdatePayload
18
20
  }>
19
21
 
20
22
  export const ConversationNewScreen = ({ route }: ConversationNewScreenProps) => {
21
- const { group_id, team_ids, source_app_name, plan_id, chat_group_graph_id, team_filter_type } =
22
- route.params
23
+ const {
24
+ group_id,
25
+ team_ids,
26
+ source_app_name,
27
+ plan_id,
28
+ chat_group_graph_id,
29
+ team_filter_type,
30
+ avatar_selection,
31
+ } = route.params
23
32
 
24
33
  switch (source_app_name) {
25
34
  case 'Groups':
26
35
  return group_id ? (
27
- <GroupsForm groupId={group_id} chat_group_graph_id={chat_group_graph_id} />
36
+ <GroupsForm
37
+ groupId={group_id}
38
+ chat_group_graph_id={chat_group_graph_id}
39
+ avatarSelection={avatar_selection}
40
+ />
28
41
  ) : (
29
42
  <SourceAppErrorCard />
30
43
  )
@@ -34,6 +47,7 @@ export const ConversationNewScreen = ({ route }: ConversationNewScreenProps) =>
34
47
  initialTeamIds={team_ids}
35
48
  initialPlanId={plan_id}
36
49
  teamFilterType={team_filter_type}
50
+ avatarSelection={avatar_selection}
37
51
  />
38
52
  )
39
53
  default:
@@ -22,7 +22,8 @@ export const TeamConversationScreen = ({ route }: TeamConversationScreenProps) =
22
22
  const teamAndPlanParams = buildTeamAndPlanParams(route.params.team_ids, route.params.plan_id)
23
23
  const { data: conversation } = useQuery({
24
24
  queryKey: ['team-conversation', route.params.team_ids, route.params.plan_id],
25
- queryFn: () => findOrCreateServicesConversation(apiClient, teamAndPlanParams),
25
+ queryFn: () =>
26
+ findOrCreateServicesConversation(apiClient, teamAndPlanParams).then(r => r.conversation),
26
27
  })
27
28
 
28
29
  useEffect(() => {
@@ -0,0 +1,11 @@
1
+ // Shape after transform_response flattens attributes and camelCases keys.
2
+ // The wire format uses snake_case nested under attributes (see the Rails
3
+ // ChatConfigurationVertex); the JS client transforms it before consumers
4
+ // see it.
5
+ export interface ChatConfigurationResource {
6
+ type: 'ChatConfiguration'
7
+ id: string
8
+ allowedFileExtensions: string[]
9
+ maxFileSizeInBytes: number
10
+ maxAttachmentsPerMessage: number
11
+ }
@@ -2,6 +2,7 @@ import AsyncStorage from '@react-native-async-storage/async-storage'
2
2
  import { Linking as RNLinking } from 'react-native'
3
3
  import { AudioAdapter } from './audio'
4
4
  import { ClipboardAdapter } from './clipboard'
5
+ import { DocumentPickerAdapter } from './document_picker'
5
6
  import { HapticAdapter } from './haptic'
6
7
  import { ImagePickerAdapter } from './image_picker'
7
8
  import { LinkingAdapter } from './linking'
@@ -14,6 +15,7 @@ type ChatConfigurations = {
14
15
  audio: AudioAdapter
15
16
  video: VideoAdapter
16
17
  imagePicker: ImagePickerAdapter
18
+ documentPicker: DocumentPickerAdapter
17
19
  log?: LogAdapter
18
20
  linking?: LinkingAdapter
19
21
  haptic?: HapticAdapter
@@ -25,6 +27,7 @@ export class ChatAdapters {
25
27
  Audio = configurations.audio
26
28
  Video = configurations.video
27
29
  ImagePicker = configurations.imagePicker
30
+ DocumentPicker = configurations.documentPicker
28
31
  Log = configurations.log || new LogAdapter()
29
32
  Linking = configurations.linking || new LinkingAdapter(RNLinking)
30
33
  Haptic = configurations.haptic || new HapticAdapter()
@@ -71,6 +74,13 @@ export let ImagePicker: ImagePickerAdapter = new ImagePickerAdapter({
71
74
  },
72
75
  })
73
76
 
77
+ export let DocumentPicker: DocumentPickerAdapter = new DocumentPickerAdapter({
78
+ openAsync: async () => {
79
+ methodMissing()
80
+ return { canceled: true, assets: null }
81
+ },
82
+ })
83
+
74
84
  export let Log: LogAdapter = new LogAdapter()
75
85
 
76
86
  export let Linking: LinkingAdapter = new LinkingAdapter(RNLinking)
@@ -0,0 +1,26 @@
1
+ export type DocumentPickerAsset = {
2
+ uri: string
3
+ name: string
4
+ size?: number
5
+ mimeType?: string
6
+ }
7
+
8
+ type DocumentPickerSuccessResult = {
9
+ canceled: false
10
+ assets: DocumentPickerAsset[]
11
+ }
12
+
13
+ type DocumentPickerCanceledResult = {
14
+ canceled: true
15
+ assets: null
16
+ }
17
+
18
+ export type DocumentPickerResult = DocumentPickerSuccessResult | DocumentPickerCanceledResult
19
+
20
+ export class DocumentPickerAdapter {
21
+ openAsync: () => Promise<DocumentPickerResult>
22
+
23
+ constructor(methods: DocumentPickerAdapter) {
24
+ this.openAsync = methods.openAsync
25
+ }
26
+ }
@@ -20,9 +20,16 @@ type ImagePickerCanceledResult = {
20
20
 
21
21
  export type ImagePickerResult = ImagePickerSuccessResult | ImagePickerCanceledResult
22
22
 
23
+ export interface ImagePickerOptions {
24
+ selectionLimit?: number
25
+ allowsEditing?: boolean
26
+ allowsMultipleSelection?: boolean
27
+ mediaTypes?: Array<'images' | 'videos' | 'livePhotos'>
28
+ }
29
+
23
30
  export class ImagePickerAdapter {
24
31
  openCameraAsync: () => Promise<ImagePickerResult>
25
- openImageLibraryAsync: () => Promise<ImagePickerResult>
32
+ openImageLibraryAsync: (options?: ImagePickerOptions) => Promise<ImagePickerResult>
26
33
 
27
34
  constructor(methods: ImagePickerAdapter) {
28
35
  this.openCameraAsync = methods.openCameraAsync
@@ -1,6 +1,7 @@
1
1
  export * from './audio'
2
2
  export * from './clipboard'
3
3
  export * from './configuration'
4
+ export * from './document_picker'
4
5
  export * from './image_picker'
5
6
  export * from './linking'
6
7
  export * from './log'
@@ -0,0 +1,23 @@
1
+ import { getRequestQueryKey } from '../../hooks/use_suspense_api'
2
+
3
+ export const getChatConfigurationRequestArgs = () => {
4
+ const url = '/me/chat_configuration'
5
+
6
+ return {
7
+ url,
8
+ data: {
9
+ fields: {
10
+ ChatConfiguration: [
11
+ 'allowed_file_extensions',
12
+ 'max_file_size_in_bytes',
13
+ 'max_attachments_per_message',
14
+ ],
15
+ },
16
+ },
17
+ }
18
+ }
19
+
20
+ export const getChatConfigurationQueryKey = () => {
21
+ const requestArgs = getChatConfigurationRequestArgs()
22
+ return getRequestQueryKey(requestArgs)
23
+ }
@@ -1,2 +0,0 @@
1
- export declare const SUPPORTED_EXTENSIONS: string[];
2
- //# sourceMappingURL=supported_extensions.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"supported_extensions.d.ts","sourceRoot":"","sources":["../../../src/hooks/attachments/supported_extensions.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,oBAAoB,UA8ChC,CAAA"}
@@ -1,48 +0,0 @@
1
- export const SUPPORTED_EXTENSIONS = [
2
- '.3ga',
3
- '.3gp',
4
- '.aac',
5
- '.amr',
6
- '.avi',
7
- '.bmp',
8
- '.doc',
9
- '.docx',
10
- '.gif',
11
- '.h263',
12
- '.h264',
13
- '.heic',
14
- '.heif',
15
- '.jpeg',
16
- '.jpg',
17
- '.key',
18
- '.m4a',
19
- '.m4b',
20
- '.m4p',
21
- '.m4r',
22
- '.m4v',
23
- '.mkv',
24
- '.mov',
25
- '.mp3',
26
- '.mp4',
27
- '.mp4-latm',
28
- '.mpeg',
29
- '.mpeg4',
30
- '.mpg',
31
- '.numbers',
32
- '.ogg',
33
- '.pages',
34
- '.pdf',
35
- '.png',
36
- '.ppt',
37
- '.pptx',
38
- '.rtf',
39
- '.txt',
40
- '.vcf',
41
- '.wav',
42
- '.webm',
43
- '.webp',
44
- '.wmv',
45
- '.xls',
46
- '.xlsx',
47
- ];
48
- //# sourceMappingURL=supported_extensions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"supported_extensions.js","sourceRoot":"","sources":["../../../src/hooks/attachments/supported_extensions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,oBAAoB,GAAG;IAClC,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,WAAW;IACX,OAAO;IACP,QAAQ;IACR,MAAM;IACN,UAAU;IACV,MAAM;IACN,QAAQ;IACR,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,MAAM;IACN,MAAM;IACN,MAAM;IACN,MAAM;IACN,OAAO;IACP,OAAO;IACP,MAAM;IACN,MAAM;IACN,OAAO;CACR,CAAA","sourcesContent":["export const SUPPORTED_EXTENSIONS = [\n '.3ga',\n '.3gp',\n '.aac',\n '.amr',\n '.avi',\n '.bmp',\n '.doc',\n '.docx',\n '.gif',\n '.h263',\n '.h264',\n '.heic',\n '.heif',\n '.jpeg',\n '.jpg',\n '.key',\n '.m4a',\n '.m4b',\n '.m4p',\n '.m4r',\n '.m4v',\n '.mkv',\n '.mov',\n '.mp3',\n '.mp4',\n '.mp4-latm',\n '.mpeg',\n '.mpeg4',\n '.mpg',\n '.numbers',\n '.ogg',\n '.pages',\n '.pdf',\n '.png',\n '.ppt',\n '.pptx',\n '.rtf',\n '.txt',\n '.vcf',\n '.wav',\n '.webm',\n '.webp',\n '.wmv',\n '.xls',\n '.xlsx',\n]\n"]}
@@ -1,47 +0,0 @@
1
- export const SUPPORTED_EXTENSIONS = [
2
- '.3ga',
3
- '.3gp',
4
- '.aac',
5
- '.amr',
6
- '.avi',
7
- '.bmp',
8
- '.doc',
9
- '.docx',
10
- '.gif',
11
- '.h263',
12
- '.h264',
13
- '.heic',
14
- '.heif',
15
- '.jpeg',
16
- '.jpg',
17
- '.key',
18
- '.m4a',
19
- '.m4b',
20
- '.m4p',
21
- '.m4r',
22
- '.m4v',
23
- '.mkv',
24
- '.mov',
25
- '.mp3',
26
- '.mp4',
27
- '.mp4-latm',
28
- '.mpeg',
29
- '.mpeg4',
30
- '.mpg',
31
- '.numbers',
32
- '.ogg',
33
- '.pages',
34
- '.pdf',
35
- '.png',
36
- '.ppt',
37
- '.pptx',
38
- '.rtf',
39
- '.txt',
40
- '.vcf',
41
- '.wav',
42
- '.webm',
43
- '.webp',
44
- '.wmv',
45
- '.xls',
46
- '.xlsx',
47
- ]