@planningcenter/chat-react-native 3.2.0 → 3.4.0-rc.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/hooks/services/use_find_or_create_services_conversation.d.ts +9 -0
- package/build/hooks/services/use_find_or_create_services_conversation.d.ts.map +1 -0
- package/build/hooks/services/use_find_or_create_services_conversation.js +72 -0
- package/build/hooks/services/use_find_or_create_services_conversation.js.map +1 -0
- package/build/hooks/services/use_team_members_for_new_conversation.d.ts +176 -0
- package/build/hooks/services/use_team_members_for_new_conversation.d.ts.map +1 -0
- package/build/hooks/services/use_team_members_for_new_conversation.js +29 -0
- package/build/hooks/services/use_team_members_for_new_conversation.js.map +1 -0
- package/build/hooks/services/use_team_plans.d.ts +8 -0
- package/build/hooks/services/use_team_plans.d.ts.map +1 -0
- package/build/hooks/services/use_team_plans.js +37 -0
- package/build/hooks/services/use_team_plans.js.map +1 -0
- package/build/hooks/services/use_teams_i_lead.d.ts +8 -0
- package/build/hooks/services/use_teams_i_lead.d.ts.map +1 -0
- package/build/hooks/services/use_teams_i_lead.js +34 -0
- package/build/hooks/services/use_teams_i_lead.js.map +1 -0
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -1
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +4 -28
- package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -1
- package/build/screens/conversation_new/components/filter_by_plan_options.d.ts +8 -0
- package/build/screens/conversation_new/components/filter_by_plan_options.d.ts.map +1 -0
- package/build/screens/conversation_new/components/filter_by_plan_options.js +37 -0
- package/build/screens/conversation_new/components/filter_by_plan_options.js.map +1 -0
- package/build/screens/conversation_new/components/services_form.d.ts +8 -0
- package/build/screens/conversation_new/components/services_form.d.ts.map +1 -0
- package/build/screens/conversation_new/components/services_form.js +137 -0
- package/build/screens/conversation_new/components/services_form.js.map +1 -0
- package/build/screens/conversation_new/conversation_new_screen.js +2 -2
- package/build/screens/conversation_new/conversation_new_screen.js.map +1 -1
- package/build/types/resources/services/team_resource.d.ts +6 -3
- package/build/types/resources/services/team_resource.d.ts.map +1 -1
- package/build/types/resources/services/team_resource.js.map +1 -1
- package/package.json +2 -2
- package/src/hooks/services/use_find_or_create_services_conversation.ts +97 -0
- package/src/hooks/services/use_team_members_for_new_conversation.ts +40 -0
- package/src/hooks/services/use_team_plans.ts +42 -0
- package/src/hooks/services/use_teams_i_lead.ts +44 -0
- package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +5 -48
- package/src/screens/conversation_new/components/filter_by_plan_options.tsx +64 -0
- package/src/screens/conversation_new/components/services_form.tsx +229 -0
- package/src/screens/conversation_new/conversation_new_screen.tsx +2 -2
- package/src/types/resources/services/team_resource.ts +7 -3
- package/build/screens/conversation_new/components/team_form.d.ts +0 -8
- package/build/screens/conversation_new/components/team_form.d.ts.map +0 -1
- package/build/screens/conversation_new/components/team_form.js +0 -11
- package/build/screens/conversation_new/components/team_form.js.map +0 -1
- package/src/screens/conversation_new/components/team_form.tsx +0 -18
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { StackActions, useNavigation } from '@react-navigation/native'
|
|
2
|
+
import React, { useCallback, useMemo, useState } from 'react'
|
|
3
|
+
import { StyleSheet, View } from 'react-native'
|
|
4
|
+
import { Badge, Banner, ChildNotice, Heading, Switch, Text } from '../../../components'
|
|
5
|
+
import { ActionButton } from '../../../components/display/action_button'
|
|
6
|
+
import { Divider, FormList } from './form_list'
|
|
7
|
+
import { pluralize } from '../../../utils'
|
|
8
|
+
import { uniq } from 'lodash'
|
|
9
|
+
import { useTeamsILead } from '../../../hooks/services/use_teams_i_lead'
|
|
10
|
+
import { FilterByPlanOptions } from './filter_by_plan_options'
|
|
11
|
+
import { useTeamMembersForNewConversation } from '../../../hooks/services/use_team_members_for_new_conversation'
|
|
12
|
+
import { useFindOrCreateServicesConversation } from '../../../hooks/services/use_find_or_create_services_conversation'
|
|
13
|
+
import { ConversationResource, MemberResource } from '../../../types'
|
|
14
|
+
|
|
15
|
+
type ServicesFormProps = {
|
|
16
|
+
initialTeamIds?: number[]
|
|
17
|
+
initialPlanId?: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const ServicesForm = ({ initialTeamIds, initialPlanId }: ServicesFormProps) => {
|
|
21
|
+
const styles = useStyles()
|
|
22
|
+
const [selectedPlanId, setSelectedPlanId] = useState<number | undefined>(initialPlanId)
|
|
23
|
+
const initialState = uniq(initialTeamIds) || [] // Uniq here because services can send duplicates in the teams_i_lead response.
|
|
24
|
+
const [selectedTeamIds, setSelectedTeamIds] = useState<number[]>(initialState)
|
|
25
|
+
|
|
26
|
+
const removeSelection = useCallback(
|
|
27
|
+
(teamId: number) => {
|
|
28
|
+
setSelectedTeamIds(selectedTeamIds.filter(id => id !== teamId))
|
|
29
|
+
},
|
|
30
|
+
[selectedTeamIds]
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
const [filerByPlan, setFilterByPlan] = useState(false)
|
|
34
|
+
|
|
35
|
+
const { members, isError: isMemberError } = useTeamMembersForNewConversation({
|
|
36
|
+
teamIds: selectedTeamIds,
|
|
37
|
+
planId: selectedPlanId,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
const navigation = useNavigation()
|
|
41
|
+
const { mutate: createConversation } = useFindOrCreateServicesConversation({
|
|
42
|
+
teamIds: selectedTeamIds,
|
|
43
|
+
planId: filerByPlan ? selectedPlanId : undefined,
|
|
44
|
+
onSuccess: (conversation: ConversationResource) => {
|
|
45
|
+
// exit from the create stack
|
|
46
|
+
navigation.getParent()?.goBack()
|
|
47
|
+
// navigate to the conversation screen
|
|
48
|
+
navigation.dispatch(
|
|
49
|
+
StackActions.push('Conversation', {
|
|
50
|
+
conversation_id: conversation.id,
|
|
51
|
+
})
|
|
52
|
+
)
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
return (
|
|
57
|
+
<View style={styles.formContainer}>
|
|
58
|
+
<FormList
|
|
59
|
+
memberData={members}
|
|
60
|
+
FormContent={
|
|
61
|
+
<FormContent
|
|
62
|
+
selectedTeamIds={selectedTeamIds}
|
|
63
|
+
removeSelection={removeSelection}
|
|
64
|
+
selectedPlanId={selectedPlanId}
|
|
65
|
+
setSelectedPlanId={setSelectedPlanId}
|
|
66
|
+
filterByPlan={filerByPlan}
|
|
67
|
+
setFilterByPlan={setFilterByPlan}
|
|
68
|
+
members={members}
|
|
69
|
+
isMemberError={isMemberError}
|
|
70
|
+
/>
|
|
71
|
+
}
|
|
72
|
+
/>
|
|
73
|
+
<ActionButton
|
|
74
|
+
disabled={!selectedTeamIds.length}
|
|
75
|
+
title="Start Conversation"
|
|
76
|
+
onPress={createConversation}
|
|
77
|
+
infoText="Conversation will be automatically updated if any members are added or removed from included teams."
|
|
78
|
+
/>
|
|
79
|
+
</View>
|
|
80
|
+
)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface FormContentProps {
|
|
84
|
+
selectedTeamIds: number[]
|
|
85
|
+
removeSelection: (teamId: number) => void
|
|
86
|
+
selectedPlanId?: number
|
|
87
|
+
setSelectedPlanId: (planId: number | undefined) => void
|
|
88
|
+
filterByPlan: boolean
|
|
89
|
+
setFilterByPlan: (value: boolean) => void
|
|
90
|
+
members: MemberResource[]
|
|
91
|
+
isMemberError: boolean
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function FormContent({
|
|
95
|
+
selectedTeamIds,
|
|
96
|
+
removeSelection,
|
|
97
|
+
selectedPlanId,
|
|
98
|
+
setSelectedPlanId,
|
|
99
|
+
filterByPlan,
|
|
100
|
+
setFilterByPlan,
|
|
101
|
+
members,
|
|
102
|
+
isMemberError,
|
|
103
|
+
}: FormContentProps) {
|
|
104
|
+
const { teamsILead } = useTeamsILead()
|
|
105
|
+
const selectedTeamsILead = useMemo(() => {
|
|
106
|
+
return teamsILead.filter(team => selectedTeamIds.includes(team.value.teamId))
|
|
107
|
+
}, [selectedTeamIds, teamsILead])
|
|
108
|
+
|
|
109
|
+
const styles = useStyles()
|
|
110
|
+
const teamCountHeader = pluralize(selectedTeamIds.length, 'team')
|
|
111
|
+
const memberCount = members.length
|
|
112
|
+
const childMembers = members.filter(member => member.child)
|
|
113
|
+
const hasChildren = childMembers.length > 0
|
|
114
|
+
const multipleServiceTypes =
|
|
115
|
+
uniq(selectedTeamsILead.map(team => team.value.serviceTypeId)).length > 1
|
|
116
|
+
const firstTeamId = selectedTeamIds[0]
|
|
117
|
+
filterByPlan = filterByPlan && !!firstTeamId && !multipleServiceTypes
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<View style={styles.formContent}>
|
|
121
|
+
<View style={styles.toSection}>
|
|
122
|
+
<View style={styles.toSectionRow}>
|
|
123
|
+
<Heading variant="h3">To:</Heading>
|
|
124
|
+
<Text>{teamCountHeader}</Text>
|
|
125
|
+
</View>
|
|
126
|
+
<View style={styles.toSectionRow}>
|
|
127
|
+
{selectedTeamsILead.map(team => (
|
|
128
|
+
<View key={team.value.teamId} style={styles.badgeRow}>
|
|
129
|
+
<Badge
|
|
130
|
+
iconNameRight="general.x"
|
|
131
|
+
label={team.name}
|
|
132
|
+
onPress={() => removeSelection(team.value.teamId)}
|
|
133
|
+
/>
|
|
134
|
+
</View>
|
|
135
|
+
))}
|
|
136
|
+
</View>
|
|
137
|
+
</View>
|
|
138
|
+
<Divider />
|
|
139
|
+
<View style={styles.filterByPlanSection}>
|
|
140
|
+
<View style={styles.filterByPlanSectionLead}>
|
|
141
|
+
<Heading variant="h3">Filter by plan</Heading>
|
|
142
|
+
<Switch
|
|
143
|
+
value={filterByPlan}
|
|
144
|
+
onValueChange={setFilterByPlan}
|
|
145
|
+
disabled={multipleServiceTypes}
|
|
146
|
+
/>
|
|
147
|
+
</View>
|
|
148
|
+
{multipleServiceTypes ? (
|
|
149
|
+
<Banner
|
|
150
|
+
appearance="neutral"
|
|
151
|
+
description="Plan filtering is not possible using teams from multiple service types. Try choosing teams above with only one service type."
|
|
152
|
+
/>
|
|
153
|
+
) : filterByPlan ? (
|
|
154
|
+
<FilterByPlanOptions
|
|
155
|
+
teamIds={selectedTeamIds}
|
|
156
|
+
planId={selectedPlanId}
|
|
157
|
+
onChange={setSelectedPlanId}
|
|
158
|
+
/>
|
|
159
|
+
) : null}
|
|
160
|
+
</View>
|
|
161
|
+
<Divider />
|
|
162
|
+
<View style={styles.memberSection}>
|
|
163
|
+
<Heading variant="h3">{pluralize(memberCount, 'member')} selected</Heading>
|
|
164
|
+
{hasChildren && <ChildNotice childMembers={childMembers} style={styles.banner} />}
|
|
165
|
+
{isMemberError && (
|
|
166
|
+
<Banner
|
|
167
|
+
appearance="error"
|
|
168
|
+
description="There was an issue loading team members, please refresh and try again."
|
|
169
|
+
style={styles.banner}
|
|
170
|
+
/>
|
|
171
|
+
)}
|
|
172
|
+
</View>
|
|
173
|
+
</View>
|
|
174
|
+
)
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const useStyles = () => {
|
|
178
|
+
const sectionPadding = 16
|
|
179
|
+
|
|
180
|
+
return StyleSheet.create({
|
|
181
|
+
formContainer: {
|
|
182
|
+
flex: 1,
|
|
183
|
+
},
|
|
184
|
+
formContent: {
|
|
185
|
+
paddingVertical: sectionPadding,
|
|
186
|
+
flex: 1,
|
|
187
|
+
},
|
|
188
|
+
toSection: {
|
|
189
|
+
padding: sectionPadding,
|
|
190
|
+
gap: 8,
|
|
191
|
+
},
|
|
192
|
+
toSectionRow: {
|
|
193
|
+
flexDirection: 'row',
|
|
194
|
+
gap: 8,
|
|
195
|
+
alignItems: 'baseline',
|
|
196
|
+
flexWrap: 'wrap',
|
|
197
|
+
},
|
|
198
|
+
badgeRow: {
|
|
199
|
+
flexDirection: 'row',
|
|
200
|
+
},
|
|
201
|
+
groupName: {
|
|
202
|
+
fontSize: 18,
|
|
203
|
+
},
|
|
204
|
+
filterByPlanSection: {
|
|
205
|
+
padding: sectionPadding,
|
|
206
|
+
gap: 8,
|
|
207
|
+
},
|
|
208
|
+
filterByPlanSectionLead: {
|
|
209
|
+
flexDirection: 'row',
|
|
210
|
+
gap: 8,
|
|
211
|
+
justifyContent: 'space-between',
|
|
212
|
+
alignItems: 'center',
|
|
213
|
+
},
|
|
214
|
+
filterByPlanSectionRow: {
|
|
215
|
+
flexDirection: 'row',
|
|
216
|
+
gap: 8,
|
|
217
|
+
},
|
|
218
|
+
titleInput: {
|
|
219
|
+
fontSize: 18,
|
|
220
|
+
},
|
|
221
|
+
memberSection: {
|
|
222
|
+
padding: sectionPadding,
|
|
223
|
+
paddingBottom: 0,
|
|
224
|
+
},
|
|
225
|
+
banner: {
|
|
226
|
+
marginTop: 16,
|
|
227
|
+
},
|
|
228
|
+
})
|
|
229
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { StaticScreenProps } from '@react-navigation/native'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { GroupsForm } from './components/groups_form'
|
|
4
|
-
import {
|
|
4
|
+
import { ServicesForm } from './components/services_form'
|
|
5
5
|
import { SourceAppErrorCard } from './components/source_app_error_card'
|
|
6
6
|
import { AppName } from '../../types/resources/app_name'
|
|
7
7
|
import { GraphId } from '../../types/resources/group_resource'
|
|
@@ -26,7 +26,7 @@ export const ConversationNewScreen = ({ route }: ConversationNewScreenProps) =>
|
|
|
26
26
|
<SourceAppErrorCard />
|
|
27
27
|
)
|
|
28
28
|
case 'Services':
|
|
29
|
-
return <
|
|
29
|
+
return <ServicesForm initialTeamIds={team_ids} initialPlanId={plan_id} />
|
|
30
30
|
default:
|
|
31
31
|
return <SourceAppErrorCard />
|
|
32
32
|
}
|
|
@@ -38,16 +38,16 @@ export interface PlansResource extends ServicesChatResource {
|
|
|
38
38
|
plans: PlansResponseItem[]
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
interface PlansResponseItem {
|
|
41
|
+
export interface PlansResponseItem {
|
|
42
42
|
value: number
|
|
43
43
|
name: string
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
export interface TeamPeopleResource extends ServicesChatResource {
|
|
47
|
-
people:
|
|
47
|
+
people: TeamPersonResponseItem[]
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
interface
|
|
50
|
+
export interface TeamPersonResponseItem {
|
|
51
51
|
id: number
|
|
52
52
|
name: string
|
|
53
53
|
avatar: string
|
|
@@ -58,3 +58,7 @@ interface PersonResponseItem {
|
|
|
58
58
|
export interface ServicesChatPayloadResource extends ServicesChatResource {
|
|
59
59
|
payload: string
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
export interface ServicesChatGroupIdentifiersResource extends ServicesChatResource {
|
|
63
|
+
groupIdentifiers: string[]
|
|
64
|
+
}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
type TeamFormProps = {
|
|
3
|
-
initialTeamIds?: number[];
|
|
4
|
-
initialPlanId?: number;
|
|
5
|
-
};
|
|
6
|
-
export declare const TeamsForm: ({ initialTeamIds, initialPlanId }: TeamFormProps) => React.JSX.Element;
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=team_form.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"team_form.d.ts","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/team_form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,KAAK,aAAa,GAAG;IACnB,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;IACzB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB,CAAA;AAED,eAAO,MAAM,SAAS,sCAAuC,aAAa,sBAQzE,CAAA"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { View } from 'react-native';
|
|
3
|
-
import { Text } from '../../../components';
|
|
4
|
-
export const TeamsForm = ({ initialTeamIds, initialPlanId }) => {
|
|
5
|
-
console.log('initialTeamIds', initialTeamIds);
|
|
6
|
-
console.log('initialPlanId', initialPlanId);
|
|
7
|
-
return (<View>
|
|
8
|
-
<Text>Services team form coming soon</Text>
|
|
9
|
-
</View>);
|
|
10
|
-
};
|
|
11
|
-
//# sourceMappingURL=team_form.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"team_form.js","sourceRoot":"","sources":["../../../../src/screens/conversation_new/components/team_form.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,qBAAqB,CAAA;AAO1C,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,EAAE,cAAc,EAAE,aAAa,EAAiB,EAAE,EAAE;IAC5E,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,cAAc,CAAC,CAAA;IAC7C,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,aAAa,CAAC,CAAA;IAC3C,OAAO,CACL,CAAC,IAAI,CACH;MAAA,CAAC,IAAI,CAAC,8BAA8B,EAAE,IAAI,CAC5C;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC,CAAA","sourcesContent":["import React from 'react'\nimport { View } from 'react-native'\nimport { Text } from '../../../components'\n\ntype TeamFormProps = {\n initialTeamIds?: number[]\n initialPlanId?: number\n}\n\nexport const TeamsForm = ({ initialTeamIds, initialPlanId }: TeamFormProps) => {\n console.log('initialTeamIds', initialTeamIds)\n console.log('initialPlanId', initialPlanId)\n return (\n <View>\n <Text>Services team form coming soon</Text>\n </View>\n )\n}\n"]}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import React from 'react'
|
|
2
|
-
import { View } from 'react-native'
|
|
3
|
-
import { Text } from '../../../components'
|
|
4
|
-
|
|
5
|
-
type TeamFormProps = {
|
|
6
|
-
initialTeamIds?: number[]
|
|
7
|
-
initialPlanId?: number
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const TeamsForm = ({ initialTeamIds, initialPlanId }: TeamFormProps) => {
|
|
11
|
-
console.log('initialTeamIds', initialTeamIds)
|
|
12
|
-
console.log('initialPlanId', initialPlanId)
|
|
13
|
-
return (
|
|
14
|
-
<View>
|
|
15
|
-
<Text>Services team form coming soon</Text>
|
|
16
|
-
</View>
|
|
17
|
-
)
|
|
18
|
-
}
|