@planningcenter/chat-react-native 3.38.1-rc.2 → 3.38.2-qa-778.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 (220) hide show
  1. package/build/components/conversation/messages_disabled_banners.d.ts +6 -1
  2. package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
  3. package/build/components/conversation/messages_disabled_banners.js +8 -2
  4. package/build/components/conversation/messages_disabled_banners.js.map +1 -1
  5. package/build/components/primitive/form_sheet.d.ts +1 -0
  6. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  7. package/build/components/primitive/form_sheet.js +17 -7
  8. package/build/components/primitive/form_sheet.js.map +1 -1
  9. package/build/contexts/api_provider.js +2 -1
  10. package/build/contexts/api_provider.js.map +1 -1
  11. package/build/contexts/conversations_context.d.ts.map +1 -1
  12. package/build/contexts/conversations_context.js +6 -2
  13. package/build/contexts/conversations_context.js.map +1 -1
  14. package/build/hooks/direct_messages/use_direct_message_affiliations.d.ts +5 -0
  15. package/build/hooks/direct_messages/use_direct_message_affiliations.d.ts.map +1 -0
  16. package/build/hooks/direct_messages/use_direct_message_affiliations.js +20 -0
  17. package/build/hooks/direct_messages/use_direct_message_affiliations.js.map +1 -0
  18. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts +4 -0
  19. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts.map +1 -0
  20. package/build/hooks/direct_messages/use_direct_message_candidates.js +28 -0
  21. package/build/hooks/direct_messages/use_direct_message_candidates.js.map +1 -0
  22. package/build/hooks/direct_messages/use_direct_message_conversation_validate.d.ts +11 -0
  23. package/build/hooks/direct_messages/use_direct_message_conversation_validate.d.ts.map +1 -0
  24. package/build/hooks/direct_messages/use_direct_message_conversation_validate.js +25 -0
  25. package/build/hooks/direct_messages/use_direct_message_conversation_validate.js.map +1 -0
  26. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.d.ts +13 -0
  27. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.d.ts.map +1 -0
  28. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.js +51 -0
  29. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.js.map +1 -0
  30. package/build/hooks/groups/use_group_chat_conversation_payload.d.ts.map +1 -1
  31. package/build/hooks/groups/use_group_chat_conversation_payload.js +2 -1
  32. package/build/hooks/groups/use_group_chat_conversation_payload.js.map +1 -1
  33. package/build/hooks/index.d.ts +2 -0
  34. package/build/hooks/index.d.ts.map +1 -1
  35. package/build/hooks/index.js +2 -0
  36. package/build/hooks/index.js.map +1 -1
  37. package/build/hooks/services/use_services_chat_conversation_payload.d.ts.map +1 -1
  38. package/build/hooks/services/use_services_chat_conversation_payload.js +2 -1
  39. package/build/hooks/services/use_services_chat_conversation_payload.js.map +1 -1
  40. package/build/hooks/use_api.d.ts +5 -1
  41. package/build/hooks/use_api.d.ts.map +1 -1
  42. package/build/hooks/use_api.js +2 -1
  43. package/build/hooks/use_api.js.map +1 -1
  44. package/build/hooks/use_chat_configuration.d.ts.map +1 -1
  45. package/build/hooks/use_chat_configuration.js +2 -1
  46. package/build/hooks/use_chat_configuration.js.map +1 -1
  47. package/build/hooks/use_chat_permissions.d.ts.map +1 -1
  48. package/build/hooks/use_chat_permissions.js +4 -1
  49. package/build/hooks/use_chat_permissions.js.map +1 -1
  50. package/build/hooks/use_conversation.d.ts.map +1 -1
  51. package/build/hooks/use_conversation.js +1 -0
  52. package/build/hooks/use_conversation.js.map +1 -1
  53. package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
  54. package/build/hooks/use_conversation_jolt_events.js +2 -2
  55. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  56. package/build/hooks/use_current_person.d.ts.map +1 -1
  57. package/build/hooks/use_current_person.js +5 -2
  58. package/build/hooks/use_current_person.js.map +1 -1
  59. package/build/hooks/use_direct_messages_enabled.d.ts +2 -0
  60. package/build/hooks/use_direct_messages_enabled.d.ts.map +1 -0
  61. package/build/hooks/use_direct_messages_enabled.js +16 -0
  62. package/build/hooks/use_direct_messages_enabled.js.map +1 -0
  63. package/build/hooks/use_features.d.ts +1 -0
  64. package/build/hooks/use_features.d.ts.map +1 -1
  65. package/build/hooks/use_features.js +3 -1
  66. package/build/hooks/use_features.js.map +1 -1
  67. package/build/hooks/use_groups.d.ts.map +1 -1
  68. package/build/hooks/use_groups.js +2 -1
  69. package/build/hooks/use_groups.js.map +1 -1
  70. package/build/hooks/use_groups_groups.d.ts.map +1 -1
  71. package/build/hooks/use_groups_groups.js +2 -1
  72. package/build/hooks/use_groups_groups.js.map +1 -1
  73. package/build/hooks/use_has_direct_messages.d.ts +2 -0
  74. package/build/hooks/use_has_direct_messages.d.ts.map +1 -0
  75. package/build/hooks/use_has_direct_messages.js +17 -0
  76. package/build/hooks/use_has_direct_messages.js.map +1 -0
  77. package/build/hooks/use_jolt.d.ts.map +1 -1
  78. package/build/hooks/use_jolt.js +2 -1
  79. package/build/hooks/use_jolt.js.map +1 -1
  80. package/build/hooks/use_organization.d.ts.map +1 -1
  81. package/build/hooks/use_organization.js +4 -1
  82. package/build/hooks/use_organization.js.map +1 -1
  83. package/build/hooks/use_person_settings.d.ts +6 -0
  84. package/build/hooks/use_person_settings.d.ts.map +1 -0
  85. package/build/hooks/use_person_settings.js +26 -0
  86. package/build/hooks/use_person_settings.js.map +1 -0
  87. package/build/navigation/index.d.ts +39 -0
  88. package/build/navigation/index.d.ts.map +1 -1
  89. package/build/navigation/index.js +19 -1
  90. package/build/navigation/index.js.map +1 -1
  91. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  92. package/build/screens/conversation_details_screen.js +2 -1
  93. package/build/screens/conversation_details_screen.js.map +1 -1
  94. package/build/screens/conversation_filters/components/conversation_filters.d.ts.map +1 -1
  95. package/build/screens/conversation_filters/components/conversation_filters.js +20 -5
  96. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  97. package/build/screens/conversation_filters/components/rows.d.ts +2 -1
  98. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  99. package/build/screens/conversation_filters/components/rows.js +2 -2
  100. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  101. package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -1
  102. package/build/screens/conversation_filters/context/conversation_filter_context.js +4 -0
  103. package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -1
  104. package/build/screens/conversation_filters/filter_types.d.ts +1 -0
  105. package/build/screens/conversation_filters/filter_types.d.ts.map +1 -1
  106. package/build/screens/conversation_filters/filter_types.js +1 -0
  107. package/build/screens/conversation_filters/filter_types.js.map +1 -1
  108. package/build/screens/conversation_filters/screen_props.d.ts +1 -0
  109. package/build/screens/conversation_filters/screen_props.d.ts.map +1 -1
  110. package/build/screens/conversation_filters/screen_props.js.map +1 -1
  111. package/build/screens/conversation_screen.d.ts.map +1 -1
  112. package/build/screens/conversation_screen.js +1 -1
  113. package/build/screens/conversation_screen.js.map +1 -1
  114. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts +3 -0
  115. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -0
  116. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +334 -0
  117. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -0
  118. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  119. package/build/screens/conversation_select_type_screen.js +11 -17
  120. package/build/screens/conversation_select_type_screen.js.map +1 -1
  121. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  122. package/build/screens/conversations/components/list_header_component.js +35 -17
  123. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  124. package/build/screens/conversations/conversations_screen.d.ts +1 -0
  125. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  126. package/build/screens/conversations/conversations_screen.js.map +1 -1
  127. package/build/screens/get_help_screen.d.ts.map +1 -1
  128. package/build/screens/get_help_screen.js +2 -18
  129. package/build/screens/get_help_screen.js.map +1 -1
  130. package/build/screens/index.d.ts +1 -0
  131. package/build/screens/index.d.ts.map +1 -1
  132. package/build/screens/index.js +1 -0
  133. package/build/screens/index.js.map +1 -1
  134. package/build/screens/settings_screen.d.ts +5 -0
  135. package/build/screens/settings_screen.d.ts.map +1 -0
  136. package/build/screens/settings_screen.js +56 -0
  137. package/build/screens/settings_screen.js.map +1 -0
  138. package/build/types/jolt_events/conversation_events.d.ts +2 -0
  139. package/build/types/jolt_events/conversation_events.d.ts.map +1 -1
  140. package/build/types/jolt_events/conversation_events.js.map +1 -1
  141. package/build/types/resources/conversation.d.ts +2 -0
  142. package/build/types/resources/conversation.d.ts.map +1 -1
  143. package/build/types/resources/conversation.js.map +1 -1
  144. package/build/types/resources/direct_message_affiliations.d.ts +8 -0
  145. package/build/types/resources/direct_message_affiliations.d.ts.map +1 -0
  146. package/build/types/resources/direct_message_affiliations.js +2 -0
  147. package/build/types/resources/direct_message_affiliations.js.map +1 -0
  148. package/build/types/resources/direct_message_candidate.d.ts +12 -0
  149. package/build/types/resources/direct_message_candidate.d.ts.map +1 -0
  150. package/build/types/resources/direct_message_candidate.js +2 -0
  151. package/build/types/resources/direct_message_candidate.js.map +1 -0
  152. package/build/types/resources/index.d.ts +2 -0
  153. package/build/types/resources/index.d.ts.map +1 -1
  154. package/build/types/resources/index.js +2 -0
  155. package/build/types/resources/index.js.map +1 -1
  156. package/build/types/resources/organization.d.ts +1 -0
  157. package/build/types/resources/organization.d.ts.map +1 -1
  158. package/build/types/resources/organization.js.map +1 -1
  159. package/build/types/resources/person.d.ts +2 -0
  160. package/build/types/resources/person.d.ts.map +1 -1
  161. package/build/types/resources/person.js.map +1 -1
  162. package/build/utils/request/conversation.d.ts +2 -1
  163. package/build/utils/request/conversation.d.ts.map +1 -1
  164. package/build/utils/request/conversation.js +15 -6
  165. package/build/utils/request/conversation.js.map +1 -1
  166. package/build/utils/time.d.ts +8 -0
  167. package/build/utils/time.d.ts.map +1 -0
  168. package/build/utils/time.js +15 -0
  169. package/build/utils/time.js.map +1 -0
  170. package/package.json +3 -3
  171. package/src/components/conversation/messages_disabled_banners.tsx +16 -2
  172. package/src/components/primitive/form_sheet.tsx +23 -6
  173. package/src/contexts/api_provider.tsx +4 -1
  174. package/src/contexts/conversations_context.tsx +6 -2
  175. package/src/hooks/direct_messages/use_direct_message_affiliations.ts +39 -0
  176. package/src/hooks/direct_messages/use_direct_message_candidates.ts +31 -0
  177. package/src/hooks/direct_messages/use_direct_message_conversation_validate.ts +35 -0
  178. package/src/hooks/direct_messages/use_find_or_create_direct_message_conversation.ts +66 -0
  179. package/src/hooks/groups/use_group_chat_conversation_payload.ts +2 -1
  180. package/src/hooks/index.ts +2 -0
  181. package/src/hooks/services/use_services_chat_conversation_payload.ts +2 -1
  182. package/src/hooks/use_api.ts +10 -1
  183. package/src/hooks/use_chat_configuration.ts +2 -1
  184. package/src/hooks/use_chat_permissions.ts +4 -1
  185. package/src/hooks/use_conversation.ts +1 -0
  186. package/src/hooks/use_conversation_jolt_events.ts +3 -2
  187. package/src/hooks/use_current_person.ts +5 -2
  188. package/src/hooks/use_direct_messages_enabled.ts +23 -0
  189. package/src/hooks/use_features.ts +3 -1
  190. package/src/hooks/use_groups.ts +16 -12
  191. package/src/hooks/use_groups_groups.ts +19 -15
  192. package/src/hooks/use_has_direct_messages.ts +21 -0
  193. package/src/hooks/use_jolt.ts +2 -1
  194. package/src/hooks/use_organization.ts +4 -1
  195. package/src/hooks/use_person_settings.ts +29 -0
  196. package/src/navigation/index.tsx +27 -1
  197. package/src/screens/conversation_details_screen.tsx +2 -1
  198. package/src/screens/conversation_filters/components/conversation_filters.tsx +25 -5
  199. package/src/screens/conversation_filters/components/rows.tsx +16 -3
  200. package/src/screens/conversation_filters/context/conversation_filter_context.tsx +4 -0
  201. package/src/screens/conversation_filters/filter_types.ts +1 -0
  202. package/src/screens/conversation_filters/screen_props.ts +1 -0
  203. package/src/screens/conversation_screen.tsx +2 -1
  204. package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +536 -0
  205. package/src/screens/conversation_select_type_screen.tsx +26 -17
  206. package/src/screens/conversations/components/list_header_component.tsx +84 -34
  207. package/src/screens/conversations/conversations_screen.tsx +1 -0
  208. package/src/screens/get_help_screen.tsx +2 -29
  209. package/src/screens/index.ts +1 -0
  210. package/src/screens/settings_screen.tsx +67 -0
  211. package/src/types/jolt_events/conversation_events.ts +2 -0
  212. package/src/types/resources/conversation.ts +3 -0
  213. package/src/types/resources/direct_message_affiliations.ts +8 -0
  214. package/src/types/resources/direct_message_candidate.ts +12 -0
  215. package/src/types/resources/index.ts +2 -0
  216. package/src/types/resources/organization.ts +1 -0
  217. package/src/types/resources/person.ts +2 -0
  218. package/src/utils/__tests__/conversation.test.ts +14 -0
  219. package/src/utils/request/conversation.ts +13 -5
  220. package/src/utils/time.ts +17 -0
@@ -29,6 +29,7 @@ export const getConversationRequestArgs = ({ conversation_id }: { conversation_i
29
29
  'custom_avatar_color',
30
30
  'custom_avatar_image_url',
31
31
  'disabled',
32
+ 'disabled_reason',
32
33
  'member_ability',
33
34
  'muted',
34
35
  'replies_disabled',
@@ -26,7 +26,8 @@ export function useConversationJoltEvents({ conversationId }: Props) {
26
26
 
27
27
  const handleUpdatedConversation = useCallback(
28
28
  (e: JoltConversationEvent) => {
29
- const { last_message_idempotent_key, last_message_author_id, disabled } = e.data.data
29
+ const { last_message_idempotent_key, last_message_author_id, disabled, disabled_reason } =
30
+ e.data.data
30
31
 
31
32
  if (last_message_idempotent_key && last_message_author_id === currentPersonId) {
32
33
  completeMessageCreationConversationTracking({
@@ -37,7 +38,7 @@ export function useConversationJoltEvents({ conversationId }: Props) {
37
38
 
38
39
  queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {
39
40
  if (!prev?.data) return prev
40
- return { ...prev, data: { ...prev.data, disabled } }
41
+ return { ...prev, data: { ...prev.data, disabled, disabledReason: disabled_reason } }
41
42
  })
42
43
 
43
44
  queryClient.invalidateQueries({ queryKey })
@@ -1,6 +1,7 @@
1
1
  import { useQueryClient } from '@tanstack/react-query'
2
2
  import { CurrentPersonResource } from '../types'
3
3
  import { ApiResource } from '../types/api_primitives'
4
+ import { FIVE_MINUTES, THIRTY_MINUTES } from '../utils/time'
4
5
  import { getRequestQueryKey, useSuspenseGet } from './use_suspense_api'
5
6
 
6
7
  export const currentPersonRequestArgs = {
@@ -15,6 +16,8 @@ export const currentPersonRequestArgs = {
15
16
  'unread_count',
16
17
  'pco_chat_enabled',
17
18
  'age_qualification_status',
19
+ 'direct_messages_disabled',
20
+ 'under_18',
18
21
  ],
19
22
  },
20
23
  },
@@ -24,8 +27,8 @@ export const currentPersonQueryKey = getRequestQueryKey(currentPersonRequestArgs
24
27
 
25
28
  export const useCurrentPerson = () => {
26
29
  const { data: person } = useSuspenseGet<CurrentPersonResource>(currentPersonRequestArgs, {
27
- staleTime: 5 * 60 * 1000, // 5 minutes - data stays fresh for 5 minutes
28
- gcTime: 30 * 60 * 1000, // 30 minutes - data stays in cache for 30 minutes when not in use
30
+ staleTime: FIVE_MINUTES,
31
+ gcTime: THIRTY_MINUTES,
29
32
  })
30
33
 
31
34
  return person
@@ -0,0 +1,23 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { ApiCollection } from '../types'
3
+ import type { FeatureResource } from '../types/resources/feature_resource'
4
+ import { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'
5
+ import { useApiClient } from './use_api_client'
6
+ import { availableFeatures } from './use_features'
7
+
8
+ export function useDirectMessagesEnabled(): boolean {
9
+ const apiClient = useApiClient()
10
+ const { data, isFetched } = useQuery<ApiCollection<FeatureResource>>({
11
+ queryKey: getFeaturesQueryKey(),
12
+ queryFn: () => apiClient.chat.get<ApiCollection<FeatureResource>>(getFeaturesRequestArgs()),
13
+ staleTime: 1000 * 60 * 5,
14
+ })
15
+
16
+ if (!isFetched) return false
17
+
18
+ return (
19
+ data?.data.some(
20
+ feature => feature.name === availableFeatures.direct_messages_eap && feature.enabled
21
+ ) ?? false
22
+ )
23
+ }
@@ -3,6 +3,7 @@ import { useCallback } from 'react'
3
3
  import { ApiCollection } from '../types'
4
4
  import type { FeatureResource } from '../types/resources/feature_resource'
5
5
  import { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'
6
+ import { FIVE_MINUTES } from '../utils/time'
6
7
  import { useApiClient } from './use_api_client'
7
8
 
8
9
  type FeatureName = (typeof availableFeatures)[keyof typeof availableFeatures]
@@ -18,7 +19,7 @@ export function useFeatures() {
18
19
  .get<ApiCollection<FeatureResource>>(requestArgs)
19
20
  .catch(() => stableEmptyFeatures)
20
21
  },
21
- staleTime: 1000 * 60 * 5, // 5 minutes
22
+ staleTime: FIVE_MINUTES,
22
23
  })
23
24
 
24
25
  const features = data.data
@@ -42,6 +43,7 @@ export const availableFeatures = {
42
43
  custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',
43
44
  conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
44
45
  video_moderation: 'ROLLOUT_MOBILE_video_moderation',
46
+ direct_messages_eap: 'ROLLOUT_direct_messages_eap',
45
47
  } as const satisfies Record<string, `ROLLOUT_${string}`>
46
48
 
47
49
  const stableEmptyFeatures: ApiCollection<FeatureResource> = {
@@ -1,5 +1,6 @@
1
1
  import { AppName } from '../types/resources/app_name'
2
2
  import { GroupResource, SourceType } from '../types/resources/group_resource'
3
+ import { FIVE_MINUTES } from '../utils/time'
3
4
  import { useApiPaginator } from './use_api'
4
5
 
5
6
  type UseGroupsProps = {
@@ -8,20 +9,23 @@ type UseGroupsProps = {
8
9
  }
9
10
 
10
11
  export const useGroups = ({ source_app_name, source_type }: UseGroupsProps) => {
11
- return useApiPaginator<GroupResource>({
12
- url: '/me/groups',
13
- data: {
14
- fields: {
15
- Group: [],
12
+ return useApiPaginator<GroupResource>(
13
+ {
14
+ url: '/me/groups',
15
+ data: {
16
+ fields: {
17
+ Group: [],
18
+ },
19
+ where: {
20
+ source_app_name,
21
+ source_type,
22
+ },
23
+ perPage: 100,
16
24
  },
17
- where: {
18
- source_app_name,
19
- source_type,
20
- },
21
- perPage: 100,
25
+ app: 'chat',
22
26
  },
23
- app: 'chat',
24
- })
27
+ { staleTime: FIVE_MINUTES }
28
+ )
25
29
  }
26
30
 
27
31
  export const useCanDisplayGroups = (props: UseGroupsProps) => {
@@ -1,24 +1,28 @@
1
1
  import { GroupsGroupResource } from '../types'
2
+ import { FIVE_MINUTES } from '../utils/time'
2
3
  import { useApiPaginator } from './use_api'
3
4
 
4
5
  export const useGroupsGroups = () => {
5
- return useApiPaginator<GroupsGroupResource>({
6
- url: '/me/groups',
7
- data: {
8
- perPage: 100,
9
- fields: {
10
- Group: [
11
- 'can_create_conversation',
12
- 'can_create_conversation_reason_code',
13
- 'name',
14
- 'header_image',
15
- 'memberships_count',
16
- ],
6
+ return useApiPaginator<GroupsGroupResource>(
7
+ {
8
+ url: '/me/groups',
9
+ data: {
10
+ perPage: 100,
11
+ fields: {
12
+ Group: [
13
+ 'can_create_conversation',
14
+ 'can_create_conversation_reason_code',
15
+ 'name',
16
+ 'header_image',
17
+ 'memberships_count',
18
+ ],
19
+ },
20
+ order: 'name',
17
21
  },
18
- order: 'name',
22
+ app: 'groups',
19
23
  },
20
- app: 'groups',
21
- })
24
+ { staleTime: FIVE_MINUTES }
25
+ )
22
26
  }
23
27
 
24
28
  export const useCanDisplayGroupsGroups = () => {
@@ -0,0 +1,21 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { ApiCollection, ConversationResource } from '../types'
3
+ import { useApiClient } from './use_api_client'
4
+
5
+ export function useHasDirectMessages(): boolean {
6
+ const apiClient = useApiClient()
7
+
8
+ const { data, isFetched } = useQuery<ApiCollection<ConversationResource>>({
9
+ queryKey: ['chat', '/me/conversations', 'direct_message', 'has_any'],
10
+ queryFn: () =>
11
+ apiClient.chat.get({
12
+ url: '/me/conversations',
13
+ data: { filter: 'direct_message', perPage: 1, fields: { Conversation: ['id'] } },
14
+ }),
15
+ staleTime: 1000 * 60 * 5,
16
+ })
17
+
18
+ if (!isFetched) return false
19
+
20
+ return (data?.data.length ?? 0) > 0
21
+ }
@@ -13,6 +13,7 @@ import { useChatContext } from '../contexts/chat_context'
13
13
  import { ApiResource } from '../types'
14
14
  import type { JoltSubscriptionPattern } from '../types/jolt_events'
15
15
  import { Client, Uri } from '../utils'
16
+ import { FIVE_SECONDS } from '../utils/time'
16
17
 
17
18
  interface JoltResponse {
18
19
  type: 'JoltToken'
@@ -49,7 +50,7 @@ export const useJoltClient = (): JoltClient | undefined => {
49
50
  },
50
51
  })
51
52
  },
52
- staleTime: 5000, // 5 seconds
53
+ staleTime: FIVE_SECONDS,
53
54
  })
54
55
  }
55
56
 
@@ -1,4 +1,5 @@
1
1
  import { OrganizationResource } from '../types'
2
+ import { ONE_HOUR } from '../utils/time'
2
3
  import { App } from './use_api_client'
3
4
  import { useSuspenseGet } from './use_suspense_api'
4
5
 
@@ -13,5 +14,7 @@ export const organizationRequestArgs = {
13
14
  }
14
15
 
15
16
  export function useOrganization() {
16
- return useSuspenseGet<OrganizationResource>(organizationRequestArgs)
17
+ return useSuspenseGet<OrganizationResource>(organizationRequestArgs, {
18
+ staleTime: ONE_HOUR,
19
+ })
17
20
  }
@@ -0,0 +1,29 @@
1
+ import { useMutation } from '@tanstack/react-query'
2
+ import { throwResponseError } from '../utils/response_error'
3
+ import { useApiClient } from './use_api_client'
4
+ import { useCurrentPerson, useCurrentPersonCache } from './use_current_person'
5
+
6
+ export function usePersonSettings() {
7
+ const apiClient = useApiClient()
8
+ const person = useCurrentPerson()
9
+ const { update, invalidate } = useCurrentPersonCache()
10
+
11
+ const directMessagesDisabled = person?.directMessagesDisabled ?? false
12
+
13
+ const { mutate: setDirectMessagesDisabled, isPending: isMutating } = useMutation({
14
+ mutationFn: (disabled: boolean) => {
15
+ const action = disabled ? 'disable_direct_messages' : 'enable_direct_messages'
16
+ return apiClient.chat
17
+ .post({ url: `/me/${action}`, data: { data: { type: 'Person', attributes: {} } } })
18
+ .catch(throwResponseError)
19
+ },
20
+ onMutate: disabled => {
21
+ update({ directMessagesDisabled: disabled })
22
+ },
23
+ onError: () => {
24
+ invalidate()
25
+ },
26
+ })
27
+
28
+ return { directMessagesDisabled, setDirectMessagesDisabled, isMutating }
29
+ }
@@ -12,7 +12,7 @@ import {
12
12
  HeaderDoneButton,
13
13
  HeaderTextButton,
14
14
  } from '../components/display/platform_modal_header_buttons'
15
- import { useQualifiedByAge } from '../hooks'
15
+ import { useDirectMessagesEnabled, useQualifiedByAge } from '../hooks'
16
16
  import {
17
17
  AttachmentActionsScreen,
18
18
  AttachmentActionsScreenOptions,
@@ -48,6 +48,7 @@ import {
48
48
  ConversationScreenTitle,
49
49
  } from '../screens/conversation_screen'
50
50
  import { ConversationNewEntryScreen } from '../screens/conversation_select_recipients/conversation_new_entry_screen'
51
+ import { ConversationSelectDirectMessageRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen'
51
52
  import { ConversationSelectGroupRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_group_recipients_screen'
52
53
  import { ConversationSelectTeamsILeadRecipientsScreen } from '../screens/conversation_select_recipients/conversation_select_teams_i_lead_recipients_screen'
53
54
  import { ConversationSelectRecipientsParams } from '../screens/conversation_select_recipients/types/screen_props'
@@ -76,6 +77,7 @@ import { NotificationSettingsScreen } from '../screens/notification_settings_scr
76
77
  import { PreferredAppSelectionScreen } from '../screens/preferred_app_selection_screen'
77
78
  import { ReactionsScreen, ReactionsScreenOptions } from '../screens/reactions_screen'
78
79
  import { SendGiphyScreen, SendGiphyScreenOptions } from '../screens/send_giphy_screen'
80
+ import { SettingsScreen } from '../screens/settings_screen'
79
81
  import {
80
82
  SystemMessagePeopleScreen,
81
83
  SystemMessagePeopleScreenOptions,
@@ -131,6 +133,20 @@ export const NewConversationStack = createNativeStackNavigator({
131
133
  ),
132
134
  }),
133
135
  },
136
+ ConversationSelectDirectMessageRecipients: {
137
+ screen: ConversationSelectDirectMessageRecipientsScreen,
138
+ if: useDirectMessagesEnabled,
139
+ options: ({ navigation, route }) => ({
140
+ title: 'New conversation',
141
+ headerRight: (props: NativeStackHeaderRightProps) => (
142
+ <HeaderTextButton
143
+ {...props}
144
+ onPress={() => navigation.popTo('Conversations', route.params)}
145
+ title="Cancel"
146
+ />
147
+ ),
148
+ }),
149
+ },
134
150
  ConversationFilterRecipients: {
135
151
  screen: ConversationFilterRecipientsScreen,
136
152
  options: ConversationFilterReceipientsScreenOptions,
@@ -265,6 +281,16 @@ export const ChatStack = createNativeStackNavigator({
265
281
  screen: AvatarPickerScreen,
266
282
  options: AvatarPickerScreenOptions,
267
283
  },
284
+ ChatSettings: {
285
+ screen: SettingsScreen,
286
+ options: ({ navigation }) => ({
287
+ title: 'Chat settings',
288
+ headerBackVisible: false,
289
+ headerRight: (props: NativeStackHeaderRightProps) => (
290
+ <HeaderTextButton {...props} onPress={navigation.goBack} title="Done" />
291
+ ),
292
+ }),
293
+ },
268
294
  NotificationSettings: {
269
295
  screen: NotificationSettingsScreen,
270
296
  options: ({ navigation }) => ({
@@ -122,6 +122,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
122
122
  const canDelete = conversation.memberAbility?.canDelete || false
123
123
  const isLeader = conversation.memberAbility?.leader || false
124
124
  const isDisabled = conversation.disabled ?? false
125
+ const showAdultRequirementNotice = isDisabled && conversation.disabledReason === 'safety_check'
125
126
 
126
127
  const {
127
128
  data: members,
@@ -350,7 +351,7 @@ export function ConversationDetailsScreen({ route }: ConversationDetailsScreenPr
350
351
  sectionInnerStyle: styles.sectionInnerGenderNotice,
351
352
  },
352
353
  {
353
- type: isDisabled ? SectionTypes.view : SectionTypes.hidden,
354
+ type: showAdultRequirementNotice ? SectionTypes.view : SectionTypes.hidden,
354
355
  data: {
355
356
  children: <AdultRequirementNotice />,
356
357
  },
@@ -2,7 +2,12 @@ import React, { useContext, useMemo } from 'react'
2
2
  import { StyleSheet, View, ViewStyle } from 'react-native'
3
3
  import { FlatList } from 'react-native-gesture-handler'
4
4
  import { Heading } from '../../../components'
5
- import { useAtFontScaleBreakpoint, useTheme } from '../../../hooks'
5
+ import {
6
+ useAtFontScaleBreakpoint,
7
+ useDirectMessagesEnabled,
8
+ useHasDirectMessages,
9
+ useTheme,
10
+ } from '../../../hooks'
6
11
  import { FilterContext, useFilterContext } from '../context/conversation_filter_context'
7
12
  import { FilterTypes } from '../filter_types'
8
13
  import { useGroupsToFilter, useTeamsToFilter } from '../hooks/filters'
@@ -52,7 +57,11 @@ interface DataItem<T, TName extends SectionTypes> {
52
57
  export const ConversationFilters = () => {
53
58
  const styles = useStyles()
54
59
  const { setScrollOffset, params } = useContext(FilterContext)
55
- const { chat_group_graph_id, group_source_app_name = '' } = params
60
+ const { chat_group_graph_id, group_source_app_name = '', show_direct_messages } = params
61
+
62
+ const directMessagesEnabled = useDirectMessagesEnabled()
63
+ const hasDirectMessages = useHasDirectMessages()
64
+ const canFilterByDMs = directMessagesEnabled && hasDirectMessages
56
65
 
57
66
  const activeFilter: FilterTypes = useMemo(() => {
58
67
  if (chat_group_graph_id) {
@@ -61,10 +70,12 @@ export const ConversationFilters = () => {
61
70
  return FilterTypes.Groups
62
71
  } else if (/services/i.test(group_source_app_name)) {
63
72
  return FilterTypes.Teams
73
+ } else if (show_direct_messages) {
74
+ return FilterTypes.DirectMessages
64
75
  }
65
76
 
66
77
  return FilterTypes.All
67
- }, [chat_group_graph_id, group_source_app_name])
78
+ }, [chat_group_graph_id, group_source_app_name, show_direct_messages])
68
79
 
69
80
  const { groups = [] } = useGroupsToFilter()
70
81
  const { teams = [] } = useTeamsToFilter()
@@ -91,14 +102,15 @@ export const ConversationFilters = () => {
91
102
  const teamItemData = selectActiveWithFirst(5)(teamItems)
92
103
 
93
104
  const hideAppFilters = groupItems.length < 1 || teamItems.length < 1
105
+ const showGeneralFilters = !hideAppFilters || canFilterByDMs
94
106
 
95
107
  const listData: SectionListData = [
96
108
  {
97
- type: hideAppFilters ? SectionTypes.hidden : SectionTypes.header,
109
+ type: showGeneralFilters ? SectionTypes.header : SectionTypes.hidden,
98
110
  data: { title: 'General Filters' },
99
111
  },
100
112
  {
101
- type: hideAppFilters ? SectionTypes.hidden : SectionTypes.filter,
113
+ type: showGeneralFilters ? SectionTypes.filter : SectionTypes.hidden,
102
114
  data: { filter: FilterTypes.All, isActive: activeFilter === FilterTypes.All },
103
115
  },
104
116
  {
@@ -117,6 +129,14 @@ export const ConversationFilters = () => {
117
129
  isActive: activeFilter === FilterTypes.Teams,
118
130
  },
119
131
  },
132
+ {
133
+ type: canFilterByDMs ? SectionTypes.filter : SectionTypes.hidden,
134
+ data: {
135
+ filter: FilterTypes.DirectMessages,
136
+ show_direct_messages: true,
137
+ isActive: activeFilter === FilterTypes.DirectMessages,
138
+ },
139
+ },
120
140
  {
121
141
  type: groupItems.length ? SectionTypes.header : SectionTypes.hidden,
122
142
  data: { title: 'Groups', style: styles.extraHeaderScalableSpace },
@@ -17,13 +17,26 @@ import { FilterTypes } from '../filter_types'
17
17
  import { FilteredGroup } from '../hooks/filters'
18
18
  import { ConversationFilterStackParamList } from '../screen_props'
19
19
 
20
- export type FilterProps = { group_source_app_name?: string; isActive: boolean; filter: FilterTypes }
20
+ export type FilterProps = {
21
+ group_source_app_name?: string
22
+ show_direct_messages?: boolean
23
+ isActive: boolean
24
+ filter: FilterTypes
25
+ }
21
26
 
22
- export const FilterRow = ({ group_source_app_name, isActive, filter }: FilterProps) => {
27
+ export const FilterRow = ({
28
+ group_source_app_name,
29
+ show_direct_messages,
30
+ isActive,
31
+ filter,
32
+ }: FilterProps) => {
23
33
  const { setAppFilter } = useContext(FilterContext)
24
34
 
25
35
  return (
26
- <PressableRow onPress={() => setAppFilter({ group_source_app_name })} isActive={isActive}>
36
+ <PressableRow
37
+ onPress={() => setAppFilter({ group_source_app_name, show_direct_messages })}
38
+ isActive={isActive}
39
+ >
27
40
  <Text>{filter}</Text>
28
41
  </PressableRow>
29
42
  )
@@ -21,6 +21,7 @@ export const FilterContext = createContext<{
21
21
  params: {
22
22
  chat_group_graph_id: undefined,
23
23
  group_source_app_name: undefined,
24
+ show_direct_messages: undefined,
24
25
  },
25
26
  scrollOffset: 0,
26
27
  setScrollOffset: () => {},
@@ -55,6 +56,7 @@ export const FilterProvider = ({ children }: PropsWithChildren) => {
55
56
  StackActions.popTo('Conversations', {
56
57
  chat_group_graph_id: undefined,
57
58
  group_source_app_name: undefined,
59
+ show_direct_messages: undefined,
58
60
  })
59
61
  )
60
62
  },
@@ -62,12 +64,14 @@ export const FilterProvider = ({ children }: PropsWithChildren) => {
62
64
  navigation.setParams({
63
65
  chat_group_graph_id: params.chat_group_graph_id,
64
66
  group_source_app_name: undefined,
67
+ show_direct_messages: undefined,
65
68
  })
66
69
  },
67
70
  setAppFilter: (params: Omit<ConversationFiltersParams, 'chat_group_graph_id'>) => {
68
71
  navigation.setParams({
69
72
  chat_group_graph_id: undefined,
70
73
  group_source_app_name: params.group_source_app_name,
74
+ show_direct_messages: params.show_direct_messages,
71
75
  })
72
76
  },
73
77
  applyFilters: (params: ConversationFiltersParams) => {
@@ -1,5 +1,6 @@
1
1
  export enum FilterTypes {
2
2
  All = 'All conversations',
3
+ DirectMessages = 'Direct messages',
3
4
  Groups = 'All my groups',
4
5
  Teams = 'All my teams and plans',
5
6
  More = 'More',
@@ -4,6 +4,7 @@ import { GraphId } from '../../types/resources/group_resource'
4
4
  export type ConversationFiltersParams = {
5
5
  chat_group_graph_id?: GraphId
6
6
  group_source_app_name?: string
7
+ show_direct_messages?: boolean
7
8
  }
8
9
 
9
10
  export type ConversationFiltersScreenProps = StaticScreenProps<ConversationFiltersParams>
@@ -239,7 +239,8 @@ function ConversationBottomBar({
239
239
  replyRootId,
240
240
  currentlyEditingMessage,
241
241
  }: ConversationBottomBarProps) {
242
- if (conversation.disabled) return <ConversationDisabledBanner />
242
+ if (conversation.disabled)
243
+ return <ConversationDisabledBanner disabledReason={conversation.disabledReason} />
243
244
  if (!canReply) return <MemberMessagesDisabledBanner />
244
245
  return (
245
246
  <MessageForm.Root