@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.
- package/build/components/conversation/message_form.d.ts.map +1 -1
- package/build/components/conversation/message_form.js +22 -1
- package/build/components/conversation/message_form.js.map +1 -1
- package/build/components/display/emoji_avatar.d.ts.map +1 -1
- package/build/components/display/emoji_avatar.js +2 -0
- package/build/components/display/emoji_avatar.js.map +1 -1
- package/build/components/display/icon_avatar.d.ts.map +1 -1
- package/build/components/display/icon_avatar.js +2 -0
- package/build/components/display/icon_avatar.js.map +1 -1
- package/build/components/display/utils/avatar_gradient_colors.d.ts +3 -0
- package/build/components/display/utils/avatar_gradient_colors.d.ts.map +1 -1
- package/build/components/display/utils/avatar_gradient_colors.js +8 -3
- package/build/components/display/utils/avatar_gradient_colors.js.map +1 -1
- package/build/components/primitive/avatar_primitive.d.ts +3 -1
- package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
- package/build/components/primitive/avatar_primitive.js +10 -2
- package/build/components/primitive/avatar_primitive.js.map +1 -1
- package/build/hooks/attachments/fallback_chat_configuration.d.ts +4 -0
- package/build/hooks/attachments/fallback_chat_configuration.d.ts.map +1 -0
- package/build/hooks/attachments/fallback_chat_configuration.js +59 -0
- package/build/hooks/attachments/fallback_chat_configuration.js.map +1 -0
- package/build/hooks/groups/use_groups_conversation_create.d.ts.map +1 -1
- package/build/hooks/groups/use_groups_conversation_create.js +1 -1
- package/build/hooks/groups/use_groups_conversation_create.js.map +1 -1
- package/build/hooks/services/use_find_or_create_services_conversation.d.ts +43 -11
- package/build/hooks/services/use_find_or_create_services_conversation.d.ts.map +1 -1
- package/build/hooks/services/use_find_or_create_services_conversation.js +5 -5
- package/build/hooks/services/use_find_or_create_services_conversation.js.map +1 -1
- package/build/hooks/use_attachment_uploader.d.ts.map +1 -1
- package/build/hooks/use_attachment_uploader.js +39 -14
- package/build/hooks/use_attachment_uploader.js.map +1 -1
- package/build/hooks/use_chat_configuration.d.ts +6 -0
- package/build/hooks/use_chat_configuration.d.ts.map +1 -0
- package/build/hooks/use_chat_configuration.js +41 -0
- package/build/hooks/use_chat_configuration.js.map +1 -0
- package/build/hooks/use_conversation_avatar_update.d.ts +26 -0
- package/build/hooks/use_conversation_avatar_update.d.ts.map +1 -0
- package/build/hooks/use_conversation_avatar_update.js +130 -0
- package/build/hooks/use_conversation_avatar_update.js.map +1 -0
- package/build/hooks/use_features.d.ts +1 -0
- package/build/hooks/use_features.d.ts.map +1 -1
- package/build/hooks/use_features.js +1 -0
- package/build/hooks/use_features.js.map +1 -1
- package/build/navigation/index.d.ts +16 -0
- package/build/navigation/index.d.ts.map +1 -1
- package/build/navigation/index.js +9 -0
- package/build/navigation/index.js.map +1 -1
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts +12 -0
- package/build/screens/avatar_picker/avatar_picker_screen.d.ts.map +1 -0
- package/build/screens/avatar_picker/avatar_picker_screen.js +193 -0
- package/build/screens/avatar_picker/avatar_picker_screen.js.map +1 -0
- package/build/screens/avatar_picker/avatar_picker_state.d.ts +38 -0
- package/build/screens/avatar_picker/avatar_picker_state.d.ts.map +1 -0
- package/build/screens/avatar_picker/avatar_picker_state.js +101 -0
- package/build/screens/avatar_picker/avatar_picker_state.js.map +1 -0
- package/build/screens/avatar_picker/avatar_preview.d.ts +9 -0
- package/build/screens/avatar_picker/avatar_preview.d.ts.map +1 -0
- package/build/screens/avatar_picker/avatar_preview.js +39 -0
- package/build/screens/avatar_picker/avatar_preview.js.map +1 -0
- package/build/screens/avatar_picker/color_picker.d.ts +9 -0
- package/build/screens/avatar_picker/color_picker.d.ts.map +1 -0
- package/build/screens/avatar_picker/color_picker.js +53 -0
- package/build/screens/avatar_picker/color_picker.js.map +1 -0
- package/build/screens/avatar_picker/constants.d.ts +3 -0
- package/build/screens/avatar_picker/constants.d.ts.map +1 -0
- package/build/screens/avatar_picker/constants.js +53 -0
- package/build/screens/avatar_picker/constants.js.map +1 -0
- package/build/screens/avatar_picker/emoji_tab.d.ts +7 -0
- package/build/screens/avatar_picker/emoji_tab.d.ts.map +1 -0
- package/build/screens/avatar_picker/emoji_tab.js +55 -0
- package/build/screens/avatar_picker/emoji_tab.js.map +1 -0
- package/build/screens/avatar_picker/icon_grid.d.ts +8 -0
- package/build/screens/avatar_picker/icon_grid.d.ts.map +1 -0
- package/build/screens/avatar_picker/icon_grid.js +48 -0
- package/build/screens/avatar_picker/icon_grid.js.map +1 -0
- package/build/screens/avatar_picker/upload_tab.d.ts +9 -0
- package/build/screens/avatar_picker/upload_tab.d.ts.map +1 -0
- package/build/screens/avatar_picker/upload_tab.js +39 -0
- package/build/screens/avatar_picker/upload_tab.js.map +1 -0
- package/build/screens/conversation_details_screen.d.ts.map +1 -1
- package/build/screens/conversation_details_screen.js +37 -1
- package/build/screens/conversation_details_screen.js.map +1 -1
- package/build/screens/conversation_new/components/avatar_selection_row.d.ts +12 -0
- package/build/screens/conversation_new/components/avatar_selection_row.d.ts.map +1 -0
- package/build/screens/conversation_new/components/avatar_selection_row.js +60 -0
- package/build/screens/conversation_new/components/avatar_selection_row.js.map +1 -0
- package/build/screens/conversation_new/components/gender_filter_toggle.d.ts.map +1 -1
- package/build/screens/conversation_new/components/gender_filter_toggle.js +3 -9
- package/build/screens/conversation_new/components/gender_filter_toggle.js.map +1 -1
- package/build/screens/conversation_new/components/groups_form.d.ts +3 -1
- package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
- package/build/screens/conversation_new/components/groups_form.js +22 -8
- package/build/screens/conversation_new/components/groups_form.js.map +1 -1
- package/build/screens/conversation_new/components/services_form.d.ts +3 -1
- package/build/screens/conversation_new/components/services_form.d.ts.map +1 -1
- package/build/screens/conversation_new/components/services_form.js +22 -8
- package/build/screens/conversation_new/components/services_form.js.map +1 -1
- package/build/screens/conversation_new/conversation_new_screen.d.ts +2 -0
- package/build/screens/conversation_new/conversation_new_screen.d.ts.map +1 -1
- package/build/screens/conversation_new/conversation_new_screen.js +3 -3
- package/build/screens/conversation_new/conversation_new_screen.js.map +1 -1
- package/build/screens/team_conversation_screen.d.ts.map +1 -1
- package/build/screens/team_conversation_screen.js +1 -1
- package/build/screens/team_conversation_screen.js.map +1 -1
- package/build/types/resources/chat_configuration_resource.d.ts +8 -0
- package/build/types/resources/chat_configuration_resource.d.ts.map +1 -0
- package/build/types/resources/chat_configuration_resource.js +2 -0
- package/build/types/resources/chat_configuration_resource.js.map +1 -0
- package/build/utils/native_adapters/configuration.d.ts +3 -0
- package/build/utils/native_adapters/configuration.d.ts.map +1 -1
- package/build/utils/native_adapters/configuration.js +8 -0
- package/build/utils/native_adapters/configuration.js.map +1 -1
- package/build/utils/native_adapters/document_picker.d.ts +21 -0
- package/build/utils/native_adapters/document_picker.d.ts.map +1 -0
- package/build/utils/native_adapters/document_picker.js +7 -0
- package/build/utils/native_adapters/document_picker.js.map +1 -0
- package/build/utils/native_adapters/image_picker.d.ts +7 -1
- package/build/utils/native_adapters/image_picker.d.ts.map +1 -1
- package/build/utils/native_adapters/image_picker.js.map +1 -1
- package/build/utils/native_adapters/index.d.ts +1 -0
- package/build/utils/native_adapters/index.d.ts.map +1 -1
- package/build/utils/native_adapters/index.js +1 -0
- package/build/utils/native_adapters/index.js.map +1 -1
- package/build/utils/request/get_chat_configuration.d.ts +10 -0
- package/build/utils/request/get_chat_configuration.d.ts.map +1 -0
- package/build/utils/request/get_chat_configuration.js +21 -0
- package/build/utils/request/get_chat_configuration.js.map +1 -0
- package/package.json +4 -3
- package/src/__tests__/hooks/use_attachment_uploader.test.tsx +219 -0
- package/src/__tests__/hooks/use_chat_configuration.test.tsx +80 -0
- package/src/__tests__/utils/native_adapters/configuration.ts +25 -1
- package/src/components/conversation/message_form.tsx +39 -1
- package/src/components/display/emoji_avatar.tsx +7 -2
- package/src/components/display/icon_avatar.tsx +7 -2
- package/src/components/display/utils/avatar_gradient_colors.ts +10 -3
- package/src/components/primitive/avatar_primitive.tsx +11 -2
- package/src/hooks/attachments/fallback_chat_configuration.ts +61 -0
- package/src/hooks/groups/use_groups_conversation_create.ts +2 -1
- package/src/hooks/services/use_find_or_create_services_conversation.ts +7 -7
- package/src/hooks/use_attachment_uploader.ts +39 -15
- package/src/hooks/use_chat_configuration.ts +54 -0
- package/src/hooks/use_conversation_avatar_update.ts +163 -0
- package/src/hooks/use_features.ts +1 -0
- package/src/navigation/index.tsx +13 -0
- package/src/screens/avatar_picker/__tests__/avatar_picker_state.test.ts +157 -0
- package/src/screens/avatar_picker/avatar_picker_screen.tsx +312 -0
- package/src/screens/avatar_picker/avatar_picker_state.ts +141 -0
- package/src/screens/avatar_picker/avatar_preview.tsx +46 -0
- package/src/screens/avatar_picker/color_picker.tsx +91 -0
- package/src/screens/avatar_picker/constants.ts +53 -0
- package/src/screens/avatar_picker/emoji_tab.tsx +76 -0
- package/src/screens/avatar_picker/icon_grid.tsx +81 -0
- package/src/screens/avatar_picker/upload_tab.tsx +62 -0
- package/src/screens/conversation_details_screen.tsx +60 -1
- package/src/screens/conversation_new/components/avatar_selection_row.tsx +82 -0
- package/src/screens/conversation_new/components/gender_filter_toggle.tsx +3 -9
- package/src/screens/conversation_new/components/groups_form.tsx +33 -6
- package/src/screens/conversation_new/components/services_form.tsx +37 -6
- package/src/screens/conversation_new/conversation_new_screen.tsx +17 -3
- package/src/screens/team_conversation_screen.tsx +2 -1
- package/src/types/resources/chat_configuration_resource.ts +11 -0
- package/src/utils/native_adapters/configuration.ts +10 -0
- package/src/utils/native_adapters/document_picker.ts +26 -0
- package/src/utils/native_adapters/image_picker.ts +8 -1
- package/src/utils/native_adapters/index.ts +1 -0
- package/src/utils/request/get_chat_configuration.ts +23 -0
- package/build/hooks/attachments/supported_extensions.d.ts +0 -2
- package/build/hooks/attachments/supported_extensions.d.ts.map +0 -1
- package/build/hooks/attachments/supported_extensions.js +0 -48
- package/build/hooks/attachments/supported_extensions.js.map +0 -1
- 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
|
|
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:
|
|
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 {
|
|
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
|
|
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
|
-
|
|
74
|
-
|
|
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 {
|
|
22
|
-
|
|
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
|
|
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: () =>
|
|
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
|
|
@@ -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 +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
|
-
]
|