@planningcenter/chat-react-native 3.36.2-rc.3 → 3.37.0-rc.1

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 (75) hide show
  1. package/build/components/display/action_button.d.ts +3 -1
  2. package/build/components/display/action_button.d.ts.map +1 -1
  3. package/build/components/display/action_button.js +8 -1
  4. package/build/components/display/action_button.js.map +1 -1
  5. package/build/hooks/groups/use_group_chat_conversation_payload.d.ts +168 -0
  6. package/build/hooks/groups/use_group_chat_conversation_payload.d.ts.map +1 -0
  7. package/build/hooks/groups/use_group_chat_conversation_payload.js +23 -0
  8. package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -0
  9. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts +0 -4
  10. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts.map +1 -1
  11. package/build/hooks/groups/use_group_members_for_new_conversation.js +6 -18
  12. package/build/hooks/groups/use_group_members_for_new_conversation.js.map +1 -1
  13. package/build/hooks/groups/use_groups_conversation_create.js +1 -1
  14. package/build/hooks/groups/use_groups_conversation_create.js.map +1 -1
  15. package/build/hooks/services/use_find_or_create_services_conversation.d.ts +11 -3
  16. package/build/hooks/services/use_find_or_create_services_conversation.d.ts.map +1 -1
  17. package/build/hooks/services/use_find_or_create_services_conversation.js +10 -14
  18. package/build/hooks/services/use_find_or_create_services_conversation.js.map +1 -1
  19. package/build/hooks/services/use_services_chat_conversation_payload.d.ts +164 -0
  20. package/build/hooks/services/use_services_chat_conversation_payload.d.ts.map +1 -0
  21. package/build/hooks/services/use_services_chat_conversation_payload.js +16 -0
  22. package/build/hooks/services/use_services_chat_conversation_payload.js.map +1 -0
  23. package/build/hooks/services/use_team_members_for_new_conversation.d.ts.map +1 -1
  24. package/build/hooks/services/use_team_members_for_new_conversation.js +11 -4
  25. package/build/hooks/services/use_team_members_for_new_conversation.js.map +1 -1
  26. package/build/hooks/use_conversation_validate.d.ts +12 -0
  27. package/build/hooks/use_conversation_validate.d.ts.map +1 -0
  28. package/build/hooks/use_conversation_validate.js +28 -0
  29. package/build/hooks/use_conversation_validate.js.map +1 -0
  30. package/build/hooks/use_enrich_people.d.ts +13 -0
  31. package/build/hooks/use_enrich_people.d.ts.map +1 -0
  32. package/build/hooks/use_enrich_people.js +25 -0
  33. package/build/hooks/use_enrich_people.js.map +1 -0
  34. package/build/hooks/use_features.d.ts +1 -0
  35. package/build/hooks/use_features.d.ts.map +1 -1
  36. package/build/hooks/use_features.js +1 -0
  37. package/build/hooks/use_features.js.map +1 -1
  38. package/build/screens/conversation_details_screen.js +1 -1
  39. package/build/screens/conversation_details_screen.js.map +1 -1
  40. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  41. package/build/screens/conversation_new/components/groups_form.js +14 -1
  42. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  43. package/build/screens/conversation_new/components/services_form.d.ts.map +1 -1
  44. package/build/screens/conversation_new/components/services_form.js +20 -2
  45. package/build/screens/conversation_new/components/services_form.js.map +1 -1
  46. package/build/screens/team_conversation_screen.d.ts.map +1 -1
  47. package/build/screens/team_conversation_screen.js +6 -3
  48. package/build/screens/team_conversation_screen.js.map +1 -1
  49. package/build/types/resources/conversation_validate.d.ts +10 -0
  50. package/build/types/resources/conversation_validate.d.ts.map +1 -0
  51. package/build/types/resources/conversation_validate.js +2 -0
  52. package/build/types/resources/conversation_validate.js.map +1 -0
  53. package/build/types/resources/index.d.ts +1 -0
  54. package/build/types/resources/index.d.ts.map +1 -1
  55. package/build/types/resources/index.js +1 -0
  56. package/build/types/resources/index.js.map +1 -1
  57. package/package.json +2 -2
  58. package/src/__tests__/hooks/use_conversation_validate.test.tsx +117 -0
  59. package/src/__tests__/hooks/use_enrich_people.test.tsx +95 -0
  60. package/src/components/display/action_button.tsx +18 -0
  61. package/src/hooks/groups/use_group_chat_conversation_payload.ts +38 -0
  62. package/src/hooks/groups/use_group_members_for_new_conversation.ts +9 -23
  63. package/src/hooks/groups/use_groups_conversation_create.ts +1 -1
  64. package/src/hooks/services/use_find_or_create_services_conversation.ts +27 -24
  65. package/src/hooks/services/use_services_chat_conversation_payload.ts +26 -0
  66. package/src/hooks/services/use_team_members_for_new_conversation.ts +18 -7
  67. package/src/hooks/use_conversation_validate.ts +45 -0
  68. package/src/hooks/use_enrich_people.ts +35 -0
  69. package/src/hooks/use_features.ts +1 -0
  70. package/src/screens/conversation_details_screen.tsx +1 -1
  71. package/src/screens/conversation_new/components/groups_form.tsx +17 -1
  72. package/src/screens/conversation_new/components/services_form.tsx +26 -2
  73. package/src/screens/team_conversation_screen.tsx +6 -6
  74. package/src/types/resources/conversation_validate.ts +11 -0
  75. package/src/types/resources/index.ts +1 -0
@@ -41,6 +41,7 @@ export const availableFeatures = {
41
41
  granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',
42
42
  custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',
43
43
  jump_to_unread: 'ROLLOUT_jump_to_unread',
44
+ conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
44
45
  } as const satisfies Record<string, `ROLLOUT_${string}`>
45
46
 
46
47
  const stableEmptyFeatures: ApiCollection<FeatureResource> = {
@@ -148,7 +148,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
148
148
  const memberSectionStyle = memberSectionStyleMap[memberPosition]
149
149
 
150
150
  return {
151
- type: data.child ? SectionTypes.hidden : SectionTypes.members,
151
+ type: SectionTypes.members,
152
152
  data,
153
153
  sectionInnerStyle: memberSectionStyle,
154
154
  }
@@ -5,6 +5,7 @@ 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
7
  import { useApiClient, useCurrentPerson, useSuspenseGet, useTheme } from '../../../hooks'
8
+ import { useGroupChatConversationPayload } from '../../../hooks/groups/use_group_chat_conversation_payload'
8
9
  import {
9
10
  GroupMembersForNewConversationResult,
10
11
  useGroupMembersForNewConversation,
@@ -14,6 +15,7 @@ import {
14
15
  type AvatarUpdatePayload,
15
16
  patchConversationAvatar,
16
17
  } from '../../../hooks/use_conversation_avatar_update'
18
+ import { useConversationValidate } from '../../../hooks/use_conversation_validate'
17
19
  import { availableFeatures, useFeatures } from '../../../hooks/use_features'
18
20
  import { useMyGender } from '../../../hooks/use_my_gender'
19
21
  import { useUploadClient } from '../../../hooks/use_upload_client'
@@ -40,6 +42,7 @@ export const GroupsForm = ({ groupId, chat_group_graph_id, avatarSelection }: Gr
40
42
  const [genderFilterEnabled, setGenderFilterEnabled] = useState(false)
41
43
  const { featureEnabled } = useFeatures()
42
44
  const customAvatarsEnabled = featureEnabled(availableFeatures.custom_conversation_avatars)
45
+ const safetyLockEnabled = featureEnabled(availableFeatures.conversation_safety_lock)
43
46
  const {
44
47
  isFeatureEnabled: genderFilterAvailable,
45
48
  genderId,
@@ -59,6 +62,18 @@ export const GroupsForm = ({ groupId, chat_group_graph_id, avatarSelection }: Gr
59
62
  const activeGenderId = genderFilterEnabled ? genderId : null
60
63
  const activeGenderValue = genderFilterEnabled ? genderValue : null
61
64
 
65
+ const { payload, isLoading: isLoadingPayload } = useGroupChatConversationPayload({
66
+ groupId,
67
+ enabled: safetyLockEnabled,
68
+ })
69
+
70
+ const { warnings, validationPending } = useConversationValidate({
71
+ payload,
72
+ isLoadingPayload,
73
+ genderId: activeGenderId,
74
+ enabled: safetyLockEnabled,
75
+ })
76
+
62
77
  const groupMemberships = useGroupMembersForNewConversation({
63
78
  id: groupId,
64
79
  gender: activeGenderValue,
@@ -127,10 +142,11 @@ export const GroupsForm = ({ groupId, chat_group_graph_id, avatarSelection }: Gr
127
142
  }
128
143
  />
129
144
  <ActionButton
130
- disabled={!title || isPending}
145
+ disabled={!title || isPending || validationPending || warnings.length > 0}
131
146
  title="Start Conversation"
132
147
  onPress={() => handleSave()}
133
148
  infoText="Conversation will be automatically updated if any members are added or removed from this group."
149
+ warnings={warnings}
134
150
  />
135
151
  </KeyboardView>
136
152
  )
@@ -6,12 +6,14 @@ import { Badge, Banner, ChildNotice, Heading, Switch, TextButton } from '../../.
6
6
  import { ActionButton } from '../../../components/display/action_button'
7
7
  import { useApiClient } from '../../../hooks'
8
8
  import { useFindOrCreateServicesConversation } from '../../../hooks/services/use_find_or_create_services_conversation'
9
+ import { useServicesChatConversationPayload } from '../../../hooks/services/use_services_chat_conversation_payload'
9
10
  import { useServicesTeams } from '../../../hooks/services/use_services_team'
10
11
  import { useTeamMembersForNewConversation } from '../../../hooks/services/use_team_members_for_new_conversation'
11
12
  import {
12
13
  type AvatarUpdatePayload,
13
14
  patchConversationAvatar,
14
15
  } from '../../../hooks/use_conversation_avatar_update'
16
+ import { useConversationValidate } from '../../../hooks/use_conversation_validate'
15
17
  import { availableFeatures, useFeatures } from '../../../hooks/use_features'
16
18
  import { useUploadClient } from '../../../hooks/use_upload_client'
17
19
  import { MemberResource } from '../../../types'
@@ -41,6 +43,7 @@ export const ServicesForm = ({
41
43
  const uploadClient = useUploadClient()
42
44
  const { featureEnabled } = useFeatures()
43
45
  const customAvatarsEnabled = featureEnabled(availableFeatures.custom_conversation_avatars)
46
+ const safetyLockEnabled = featureEnabled(availableFeatures.conversation_safety_lock)
44
47
  const [selectedPlanId, setSelectedPlanId] = useState<number | undefined>(initialPlanId)
45
48
  const initialState = useMemo(() => uniq(initialTeamIds) || [], [initialTeamIds]) // Uniq here because services can send duplicates in the teams_i_lead response.
46
49
  const [selectedTeamIds, setSelectedTeamIds] = useState<number[]>(initialState)
@@ -60,6 +63,20 @@ export const ServicesForm = ({
60
63
 
61
64
  const [filerByPlan, setFilterByPlan] = useState(false)
62
65
 
66
+ const activePlanId = filerByPlan ? selectedPlanId : undefined
67
+
68
+ const { payload, isLoading: isLoadingPayload } = useServicesChatConversationPayload({
69
+ teamIds: selectedTeamIds,
70
+ planId: activePlanId,
71
+ enabled: safetyLockEnabled,
72
+ })
73
+
74
+ const { warnings, validationPending } = useConversationValidate({
75
+ payload,
76
+ isLoadingPayload,
77
+ enabled: safetyLockEnabled,
78
+ })
79
+
63
80
  const { members, isError: isMemberError } = useTeamMembersForNewConversation({
64
81
  teamIds: selectedTeamIds,
65
82
  planId: selectedPlanId,
@@ -74,7 +91,7 @@ export const ServicesForm = ({
74
91
  isLoadingConversationCheck,
75
92
  } = useFindOrCreateServicesConversation({
76
93
  teamIds: selectedTeamIds,
77
- planId: filerByPlan ? selectedPlanId : undefined,
94
+ planId: activePlanId,
78
95
  onSuccess: (conversation, { created }) => {
79
96
  navigation.getParent()?.goBack()
80
97
  navigation.dispatch(
@@ -113,11 +130,18 @@ export const ServicesForm = ({
113
130
  }
114
131
  />
115
132
  <ActionButton
116
- disabled={!selectedTeamIds.length || isPending || isLoadingConversationCheck}
133
+ disabled={
134
+ !selectedTeamIds.length ||
135
+ isPending ||
136
+ isLoadingConversationCheck ||
137
+ validationPending ||
138
+ warnings.length > 0
139
+ }
117
140
  title={selectionHasConversation ? 'Open conversation' : 'Start conversation'}
118
141
  onPress={createConversation}
119
142
  infoText="Conversation will be automatically updated if any members are added or removed from included teams."
120
143
  loading={isLoadingConversationCheck}
144
+ warnings={warnings}
121
145
  />
122
146
  </View>
123
147
  )
@@ -3,10 +3,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query'
3
3
  import { useEffect } from 'react'
4
4
  import { DefaultLoading } from '../components/page/loading'
5
5
  import { useApiClient } from '../hooks'
6
- import {
7
- buildTeamAndPlanParams,
8
- findOrCreateServicesConversation,
9
- } from '../hooks/services/use_find_or_create_services_conversation'
6
+ import { findOrCreateServicesConversation } from '../hooks/services/use_find_or_create_services_conversation'
10
7
 
11
8
  export type TeamConversationRouteProps = {
12
9
  plan_id?: number
@@ -19,11 +16,14 @@ export const TeamConversationScreen = ({ route }: TeamConversationScreenProps) =
19
16
  const apiClient = useApiClient()
20
17
  const queryClient = useQueryClient()
21
18
  const navigation = useNavigation()
22
- const teamAndPlanParams = buildTeamAndPlanParams(route.params.team_ids, route.params.plan_id)
23
19
  const { data: conversation } = useQuery({
24
20
  queryKey: ['team-conversation', route.params.team_ids, route.params.plan_id],
25
21
  queryFn: () =>
26
- findOrCreateServicesConversation(apiClient, teamAndPlanParams).then(r => r.conversation),
22
+ findOrCreateServicesConversation({
23
+ apiClient,
24
+ teamIds: route.params.team_ids ?? [],
25
+ planId: route.params.plan_id,
26
+ }).then(r => r.conversation),
27
27
  })
28
28
 
29
29
  useEffect(() => {
@@ -0,0 +1,11 @@
1
+ import { ResourceObject } from '../api_primitives'
2
+
3
+ export interface ConversationWarning {
4
+ attribute: string
5
+ fullMessage: string
6
+ }
7
+
8
+ export interface ConversationValidateResource extends ResourceObject {
9
+ type: 'ConversationValidate'
10
+ warnings: ConversationWarning[]
11
+ }
@@ -1,6 +1,7 @@
1
1
  export * from './analytics_metadata'
2
2
  export * from './conversation'
3
3
  export * from './conversation_membership'
4
+ export * from './conversation_validate'
4
5
  export * from './member'
5
6
  export * from './message'
6
7
  export * from './oauth_token'