@planningcenter/chat-react-native 3.38.1 → 3.39.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 (65) hide show
  1. package/build/hooks/direct_messages/use_direct_message_affiliations.d.ts +5 -0
  2. package/build/hooks/direct_messages/use_direct_message_affiliations.d.ts.map +1 -0
  3. package/build/hooks/direct_messages/use_direct_message_affiliations.js +20 -0
  4. package/build/hooks/direct_messages/use_direct_message_affiliations.js.map +1 -0
  5. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts +4 -0
  6. package/build/hooks/direct_messages/use_direct_message_candidates.d.ts.map +1 -0
  7. package/build/hooks/direct_messages/use_direct_message_candidates.js +27 -0
  8. package/build/hooks/direct_messages/use_direct_message_candidates.js.map +1 -0
  9. package/build/hooks/direct_messages/use_direct_message_conversation_validate.d.ts +11 -0
  10. package/build/hooks/direct_messages/use_direct_message_conversation_validate.d.ts.map +1 -0
  11. package/build/hooks/direct_messages/use_direct_message_conversation_validate.js +25 -0
  12. package/build/hooks/direct_messages/use_direct_message_conversation_validate.js.map +1 -0
  13. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.d.ts +13 -0
  14. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.d.ts.map +1 -0
  15. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.js +51 -0
  16. package/build/hooks/direct_messages/use_find_or_create_direct_message_conversation.js.map +1 -0
  17. package/build/hooks/index.d.ts +1 -0
  18. package/build/hooks/index.d.ts.map +1 -1
  19. package/build/hooks/index.js +1 -0
  20. package/build/hooks/index.js.map +1 -1
  21. package/build/hooks/use_direct_messages_enabled.d.ts +2 -0
  22. package/build/hooks/use_direct_messages_enabled.d.ts.map +1 -0
  23. package/build/hooks/use_direct_messages_enabled.js +16 -0
  24. package/build/hooks/use_direct_messages_enabled.js.map +1 -0
  25. package/build/hooks/use_features.d.ts +1 -0
  26. package/build/hooks/use_features.d.ts.map +1 -1
  27. package/build/hooks/use_features.js +1 -0
  28. package/build/hooks/use_features.js.map +1 -1
  29. package/build/navigation/index.d.ts +26 -0
  30. package/build/navigation/index.d.ts.map +1 -1
  31. package/build/navigation/index.js +10 -1
  32. package/build/navigation/index.js.map +1 -1
  33. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts +4 -0
  34. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.d.ts.map +1 -0
  35. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +25 -0
  36. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -0
  37. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  38. package/build/screens/conversation_select_type_screen.js +9 -17
  39. package/build/screens/conversation_select_type_screen.js.map +1 -1
  40. package/build/types/resources/direct_message_affiliations.d.ts +8 -0
  41. package/build/types/resources/direct_message_affiliations.d.ts.map +1 -0
  42. package/build/types/resources/direct_message_affiliations.js +2 -0
  43. package/build/types/resources/direct_message_affiliations.js.map +1 -0
  44. package/build/types/resources/direct_message_candidate.d.ts +12 -0
  45. package/build/types/resources/direct_message_candidate.d.ts.map +1 -0
  46. package/build/types/resources/direct_message_candidate.js +2 -0
  47. package/build/types/resources/direct_message_candidate.js.map +1 -0
  48. package/build/types/resources/index.d.ts +2 -0
  49. package/build/types/resources/index.d.ts.map +1 -1
  50. package/build/types/resources/index.js +2 -0
  51. package/build/types/resources/index.js.map +1 -1
  52. package/package.json +2 -2
  53. package/src/hooks/direct_messages/use_direct_message_affiliations.ts +39 -0
  54. package/src/hooks/direct_messages/use_direct_message_candidates.ts +30 -0
  55. package/src/hooks/direct_messages/use_direct_message_conversation_validate.ts +35 -0
  56. package/src/hooks/direct_messages/use_find_or_create_direct_message_conversation.ts +66 -0
  57. package/src/hooks/index.ts +1 -0
  58. package/src/hooks/use_direct_messages_enabled.ts +23 -0
  59. package/src/hooks/use_features.ts +1 -0
  60. package/src/navigation/index.tsx +16 -1
  61. package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +33 -0
  62. package/src/screens/conversation_select_type_screen.tsx +22 -17
  63. package/src/types/resources/direct_message_affiliations.ts +8 -0
  64. package/src/types/resources/direct_message_candidate.ts +12 -0
  65. package/src/types/resources/index.ts +2 -0
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_type_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAG3D,eAAO,MAAM,mCAAmC,uEAE9C,CAAA;AAEF,MAAM,MAAM,iCAAiC,GAAG,iBAAiB,CAAC;IAChE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,yBAAyB,CAAC,EAAE,yBAAyB,CAAA;CACtD,CAAC,CAAA;AAEF,wBAAgB,4BAA4B,CAAC,EAAE,KAAK,EAAE,EAAE,iCAAiC,qBAwFxF"}
1
+ {"version":3,"file":"conversation_select_type_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAiB,MAAM,0BAA0B,CAAA;AAC3E,OAAO,KAAK,MAAM,OAAO,CAAA;AAIzB,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,2CAA2C,CAAA;AAC1F,OAAO,EAAE,OAAO,EAAE,MAAM,6BAA6B,CAAA;AACrD,OAAO,EAAE,OAAO,EAAE,MAAM,mCAAmC,CAAA;AAG3D,eAAO,MAAM,mCAAmC,uEAE9C,CAAA;AAEF,MAAM,MAAM,iCAAiC,GAAG,iBAAiB,CAAC;IAChE,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,OAAO,CAAA;IAC/B,yBAAyB,CAAC,EAAE,yBAAyB,CAAA;CACtD,CAAC,CAAA;AAOF,wBAAgB,4BAA4B,CAAC,EAAE,KAAK,EAAE,EAAE,iCAAiC,qBAuFxF"}
@@ -1,6 +1,7 @@
1
1
  import { useNavigation } from '@react-navigation/native';
2
2
  import React from 'react';
3
3
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet';
4
+ import { availableFeatures, useFeatures } from '../hooks/use_features';
4
5
  import { useNewConversationEntry } from '../hooks/use_new_conversation_entry';
5
6
  import { Haptic } from '../utils/native_adapters';
6
7
  export const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({
@@ -9,10 +10,12 @@ export const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({
9
10
  export function ConversationSelectTypeScreen({ route }) {
10
11
  const navigation = useNavigation();
11
12
  const entryMode = useNewConversationEntry();
13
+ const { featureEnabled } = useFeatures();
12
14
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } = route.params || {};
13
15
  const filterParams = { chat_group_graph_id, group_source_app_name };
14
16
  const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups';
15
17
  const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams';
18
+ const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap);
16
19
  const handleFilterPress = () => {
17
20
  if (!newConversationFromFilter)
18
21
  return;
@@ -41,26 +44,14 @@ export function ConversationSelectTypeScreen({ route }) {
41
44
  }
42
45
  });
43
46
  };
44
- const handleGroupPress = () => {
47
+ const navigateToNewConversationType = (screen) => {
45
48
  Haptic.impactLight();
46
49
  navigation.goBack();
47
- requestAnimationFrame(() => {
48
- navigation.navigate('New', {
49
- screen: 'ConversationSelectGroupRecipients',
50
- params: filterParams,
51
- });
52
- });
53
- };
54
- const handleTeamPress = () => {
55
- Haptic.impactLight();
56
- navigation.goBack();
57
- requestAnimationFrame(() => {
58
- navigation.navigate('New', {
59
- screen: 'ConversationSelectTeamsILeadRecipients',
60
- params: filterParams,
61
- });
62
- });
50
+ requestAnimationFrame(() => navigation.navigate('New', { screen, params: filterParams }));
63
51
  };
52
+ const handleGroupPress = () => navigateToNewConversationType('ConversationSelectGroupRecipients');
53
+ const handleTeamPress = () => navigateToNewConversationType('ConversationSelectTeamsILeadRecipients');
54
+ const handleDirectMessagePress = () => navigateToNewConversationType('ConversationSelectDirectMessageRecipients');
64
55
  return (<FormSheet.Root>
65
56
  <FormSheet.Header>
66
57
  <FormSheet.HeaderTitle>Start a conversation by</FormSheet.HeaderTitle>
@@ -68,6 +59,7 @@ export function ConversationSelectTypeScreen({ route }) {
68
59
  {newConversationFromFilter && (<FormSheet.Action title={`New conversation in ${newConversationFromFilter.name}`} onPress={handleFilterPress} accessibilityHint="Creates a conversation pre-scoped to the current filter"/>)}
69
60
  {canCreateGroups && (<FormSheet.Action title="Group" onPress={handleGroupPress} accessibilityHint="Opens group selection screen"/>)}
70
61
  {canCreateTeams && (<FormSheet.Action title="Team" onPress={handleTeamPress} accessibilityHint="Opens team selection screen"/>)}
62
+ {canCreateDMs && (<FormSheet.Action title="Direct message" onPress={handleDirectMessagePress} accessibilityHint="Opens direct message recipient selection screen"/>)}
71
63
  </FormSheet.Root>);
72
64
  }
73
65
  //# sourceMappingURL=conversation_select_type_screen.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_select_type_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'\nimport { useNewConversationEntry } from '../hooks/use_new_conversation_entry'\nimport type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'\nimport { AppName } from '../types/resources/app_name'\nimport { GraphId } from '../types/resources/group_resource'\nimport { Haptic } from '../utils/native_adapters'\n\nexport const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({\n headerTitle: 'New conversation',\n})\n\nexport type ConversationSelectTypeScreenProps = StaticScreenProps<{\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n newConversationFromFilter?: NewConversationFromFilter\n}>\n\nexport function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {\n const navigation = useNavigation()\n const entryMode = useNewConversationEntry()\n const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =\n route.params || {}\n\n const filterParams = { chat_group_graph_id, group_source_app_name }\n const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'\n const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'\n\n const handleFilterPress = () => {\n if (!newConversationFromFilter) return\n\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n if (newConversationFromFilter.sourceAppName === 'groups') {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Groups' as AppName,\n group_id: newConversationFromFilter.groupId,\n },\n })\n } else {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Services' as AppName,\n team_ids: newConversationFromFilter.teamIds,\n },\n })\n }\n })\n }\n\n const handleGroupPress = () => {\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n navigation.navigate('New', {\n screen: 'ConversationSelectGroupRecipients',\n params: filterParams,\n })\n })\n }\n\n const handleTeamPress = () => {\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n navigation.navigate('New', {\n screen: 'ConversationSelectTeamsILeadRecipients',\n params: filterParams,\n })\n })\n }\n\n return (\n <FormSheet.Root>\n <FormSheet.Header>\n <FormSheet.HeaderTitle>Start a conversation by</FormSheet.HeaderTitle>\n </FormSheet.Header>\n {newConversationFromFilter && (\n <FormSheet.Action\n title={`New conversation in ${newConversationFromFilter.name}`}\n onPress={handleFilterPress}\n accessibilityHint=\"Creates a conversation pre-scoped to the current filter\"\n />\n )}\n {canCreateGroups && (\n <FormSheet.Action\n title=\"Group\"\n onPress={handleGroupPress}\n accessibilityHint=\"Opens group selection screen\"\n />\n )}\n {canCreateTeams && (\n <FormSheet.Action\n title=\"Team\"\n onPress={handleTeamPress}\n accessibilityHint=\"Opens team selection screen\"\n />\n )}\n </FormSheet.Root>\n )\n}\n"]}
1
+ {"version":3,"file":"conversation_select_type_screen.js","sourceRoot":"","sources":["../../src/screens/conversation_select_type_screen.tsx"],"names":[],"mappings":"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","sourcesContent":["import { StaticScreenProps, useNavigation } from '@react-navigation/native'\nimport React from 'react'\nimport FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'\nimport { availableFeatures, useFeatures } from '../hooks/use_features'\nimport { useNewConversationEntry } from '../hooks/use_new_conversation_entry'\nimport type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'\nimport { AppName } from '../types/resources/app_name'\nimport { GraphId } from '../types/resources/group_resource'\nimport { Haptic } from '../utils/native_adapters'\n\nexport const ConversationSelectTypeScreenOptions = getFormSheetScreenOptions({\n headerTitle: 'New conversation',\n})\n\nexport type ConversationSelectTypeScreenProps = StaticScreenProps<{\n chat_group_graph_id?: GraphId\n group_source_app_name?: AppName\n newConversationFromFilter?: NewConversationFromFilter\n}>\n\ntype NewConversationTypeScreen =\n | 'ConversationSelectGroupRecipients'\n | 'ConversationSelectTeamsILeadRecipients'\n | 'ConversationSelectDirectMessageRecipients'\n\nexport function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {\n const navigation = useNavigation()\n const entryMode = useNewConversationEntry()\n const { featureEnabled } = useFeatures()\n const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =\n route.params || {}\n\n const filterParams = { chat_group_graph_id, group_source_app_name }\n const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'\n const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'\n const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap)\n\n const handleFilterPress = () => {\n if (!newConversationFromFilter) return\n\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => {\n if (newConversationFromFilter.sourceAppName === 'groups') {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Groups' as AppName,\n group_id: newConversationFromFilter.groupId,\n },\n })\n } else {\n navigation.navigate('New', {\n screen: 'ConversationNew',\n params: {\n ...filterParams,\n source_app_name: 'Services' as AppName,\n team_ids: newConversationFromFilter.teamIds,\n },\n })\n }\n })\n }\n\n const navigateToNewConversationType = (screen: NewConversationTypeScreen) => {\n Haptic.impactLight()\n navigation.goBack()\n requestAnimationFrame(() => navigation.navigate('New', { screen, params: filterParams }))\n }\n\n const handleGroupPress = () => navigateToNewConversationType('ConversationSelectGroupRecipients')\n const handleTeamPress = () =>\n navigateToNewConversationType('ConversationSelectTeamsILeadRecipients')\n const handleDirectMessagePress = () =>\n navigateToNewConversationType('ConversationSelectDirectMessageRecipients')\n\n return (\n <FormSheet.Root>\n <FormSheet.Header>\n <FormSheet.HeaderTitle>Start a conversation by</FormSheet.HeaderTitle>\n </FormSheet.Header>\n {newConversationFromFilter && (\n <FormSheet.Action\n title={`New conversation in ${newConversationFromFilter.name}`}\n onPress={handleFilterPress}\n accessibilityHint=\"Creates a conversation pre-scoped to the current filter\"\n />\n )}\n {canCreateGroups && (\n <FormSheet.Action\n title=\"Group\"\n onPress={handleGroupPress}\n accessibilityHint=\"Opens group selection screen\"\n />\n )}\n {canCreateTeams && (\n <FormSheet.Action\n title=\"Team\"\n onPress={handleTeamPress}\n accessibilityHint=\"Opens team selection screen\"\n />\n )}\n {canCreateDMs && (\n <FormSheet.Action\n title=\"Direct message\"\n onPress={handleDirectMessagePress}\n accessibilityHint=\"Opens direct message recipient selection screen\"\n />\n )}\n </FormSheet.Root>\n )\n}\n"]}
@@ -0,0 +1,8 @@
1
+ import { ResourceObject } from '../api_primitives';
2
+ export interface DirectMessageAffiliationsResource extends ResourceObject {
3
+ type: 'DirectMessageAffiliations';
4
+ id: string;
5
+ groups: Record<string, string>;
6
+ teams: Record<string, string>;
7
+ }
8
+ //# sourceMappingURL=direct_message_affiliations.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_message_affiliations.d.ts","sourceRoot":"","sources":["../../../src/types/resources/direct_message_affiliations.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,iCAAkC,SAAQ,cAAc;IACvE,IAAI,EAAE,2BAA2B,CAAA;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC9B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAC9B"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=direct_message_affiliations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_message_affiliations.js","sourceRoot":"","sources":["../../../src/types/resources/direct_message_affiliations.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface DirectMessageAffiliationsResource extends ResourceObject {\n type: 'DirectMessageAffiliations'\n id: string\n groups: Record<string, string>\n teams: Record<string, string>\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { ResourceObject } from '../api_primitives';
2
+ export interface DirectMessageCandidateResource extends ResourceObject {
3
+ type: 'DirectMessageCandidate';
4
+ id: string;
5
+ name: string;
6
+ avatar: string;
7
+ groups: number[];
8
+ teams: number[];
9
+ under_18: boolean;
10
+ directMessagesDisabled: boolean;
11
+ }
12
+ //# sourceMappingURL=direct_message_candidate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_message_candidate.d.ts","sourceRoot":"","sources":["../../../src/types/resources/direct_message_candidate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,MAAM,WAAW,8BAA+B,SAAQ,cAAc;IACpE,IAAI,EAAE,wBAAwB,CAAA;IAC9B,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,QAAQ,EAAE,OAAO,CAAA;IACjB,sBAAsB,EAAE,OAAO,CAAA;CAChC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=direct_message_candidate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct_message_candidate.js","sourceRoot":"","sources":["../../../src/types/resources/direct_message_candidate.ts"],"names":[],"mappings":"","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport interface DirectMessageCandidateResource extends ResourceObject {\n type: 'DirectMessageCandidate'\n id: string\n name: string\n avatar: string\n groups: number[]\n teams: number[]\n under_18: boolean\n directMessagesDisabled: boolean\n}\n"]}
@@ -1,4 +1,6 @@
1
1
  export * from './analytics_metadata';
2
+ export * from './direct_message_affiliations';
3
+ export * from './direct_message_candidate';
2
4
  export * from './conversation';
3
5
  export * from './conversation_membership';
4
6
  export * from './conversation_validate';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA"}
@@ -1,4 +1,6 @@
1
1
  export * from './analytics_metadata';
2
+ export * from './direct_message_affiliations';
3
+ export * from './direct_message_candidate';
2
4
  export * from './conversation';
3
5
  export * from './conversation_membership';
4
6
  export * from './conversation_validate';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA;AAC9B,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA","sourcesContent":["export * from './analytics_metadata'\nexport * from './conversation'\nexport * from './conversation_membership'\nexport * from './conversation_validate'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\nexport * from './organization'\nexport * from './group_membership'\nexport * from './group_resource'\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/types/resources/index.ts"],"names":[],"mappings":"AAAA,cAAc,sBAAsB,CAAA;AACpC,cAAc,+BAA+B,CAAA;AAC7C,cAAc,4BAA4B,CAAA;AAC1C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,2BAA2B,CAAA;AACzC,cAAc,yBAAyB,CAAA;AACvC,cAAc,UAAU,CAAA;AACxB,cAAc,WAAW,CAAA;AACzB,cAAc,eAAe,CAAA;AAC7B,cAAc,UAAU,CAAA;AACxB,cAAc,UAAU,CAAA;AACxB,cAAc,aAAa,CAAA;AAC3B,cAAc,YAAY,CAAA;AAC1B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,oBAAoB,CAAA;AAClC,cAAc,kBAAkB,CAAA","sourcesContent":["export * from './analytics_metadata'\nexport * from './direct_message_affiliations'\nexport * from './direct_message_candidate'\nexport * from './conversation'\nexport * from './conversation_membership'\nexport * from './conversation_validate'\nexport * from './member'\nexport * from './message'\nexport * from './oauth_token'\nexport * from './person'\nexport * from './groups'\nexport * from './app_grant'\nexport * from './services'\nexport * from './organization'\nexport * from './group_membership'\nexport * from './group_resource'\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.38.1",
3
+ "version": "3.39.0-rc.1",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "react-native": "./src/index.tsx",
@@ -72,5 +72,5 @@
72
72
  "react-native-url-polyfill": "^2.0.0",
73
73
  "typescript": "~5.9.2"
74
74
  },
75
- "gitHead": "6d265a33344c936db3e2bf45179d81debdd43792"
75
+ "gitHead": "03a375a045ff2ae572627318c41bfc6cdcf1bc74"
76
76
  }
@@ -0,0 +1,39 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { useMemo } from 'react'
3
+ import { ApiResource } from '../../types'
4
+ import { DirectMessageAffiliationsResource } from '../../types/resources/direct_message_affiliations'
5
+ import { useApiClient } from '../use_api_client'
6
+
7
+ export function useDirectMessageAffiliations() {
8
+ const apiClient = useApiClient()
9
+
10
+ const { data } = useQuery({
11
+ queryKey: ['chat', '/me/direct_message_affiliations'],
12
+ queryFn: () =>
13
+ apiClient.chat.get({
14
+ url: '/me/direct_message_affiliations',
15
+ data: {
16
+ fields: { DirectMessageAffiliations: ['groups', 'teams'] },
17
+ },
18
+ }) as Promise<ApiResource<DirectMessageAffiliationsResource>>,
19
+ staleTime: 5 * 60 * 1000,
20
+ })
21
+
22
+ const groups = useMemo(
23
+ () =>
24
+ new Map<number, string>(
25
+ Object.entries(data?.data?.groups ?? {}).map(([id, name]) => [+id, name])
26
+ ),
27
+ [data]
28
+ )
29
+
30
+ const teams = useMemo(
31
+ () =>
32
+ new Map<number, string>(
33
+ Object.entries(data?.data?.teams ?? {}).map(([id, name]) => [+id, name])
34
+ ),
35
+ [data]
36
+ )
37
+
38
+ return { groups, teams }
39
+ }
@@ -0,0 +1,30 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { ApiCollection } from '../../types'
3
+ import { DirectMessageCandidateResource } from '../../types/resources/direct_message_candidate'
4
+ import { useApiClient } from '../use_api_client'
5
+
6
+ export function useDirectMessageCandidates(term: string) {
7
+ const apiClient = useApiClient()
8
+ return useQuery({
9
+ queryKey: ['chat', '/me/direct_message_candidates', term],
10
+ queryFn: () =>
11
+ apiClient.chat.get({
12
+ url: '/me/direct_message_candidates',
13
+ data: {
14
+ q: term,
15
+ fields: {
16
+ DirectMessageCandidate: [
17
+ 'name',
18
+ 'avatar',
19
+ 'groups',
20
+ 'teams',
21
+ 'under_18',
22
+ 'direct_messages_disabled',
23
+ ],
24
+ },
25
+ },
26
+ }) as Promise<ApiCollection<DirectMessageCandidateResource>>,
27
+ enabled: term.length >= 1,
28
+ staleTime: 1000 * 60,
29
+ })
30
+ }
@@ -0,0 +1,35 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { ApiResource, ConversationValidateResource, ConversationWarning } from '../../types'
3
+ import { useApiClient } from '../use_api_client'
4
+
5
+ interface Props {
6
+ recipientIds: string[]
7
+ enabled?: boolean
8
+ }
9
+
10
+ export function useDirectMessageConversationValidate({ recipientIds, enabled = true }: Props) {
11
+ const apiClient = useApiClient()
12
+
13
+ const { data, isLoading } = useQuery({
14
+ queryKey: ['chat', '/me/conversation_validate', { recipient_ids: recipientIds }],
15
+ queryFn: () =>
16
+ apiClient.chat.post<ApiResource<ConversationValidateResource>>({
17
+ url: '/me/conversation_validate',
18
+ data: {
19
+ data: {
20
+ type: 'ConversationValidate',
21
+ attributes: { recipient_ids: recipientIds },
22
+ },
23
+ },
24
+ }),
25
+ enabled: enabled && recipientIds.length > 0,
26
+ retry: false,
27
+ })
28
+
29
+ const warnings: ConversationWarning[] = data?.data.warnings ?? []
30
+
31
+ return {
32
+ warnings,
33
+ validationPending: enabled && recipientIds.length > 0 && isLoading,
34
+ }
35
+ }
@@ -0,0 +1,66 @@
1
+ import { useQuery } from '@tanstack/react-query'
2
+ import { useState, useCallback } from 'react'
3
+ import { ApiCollection, ApiResource, ConversationResource } from '../../types'
4
+ import { ApiClient, useApiClient } from '../use_api_client'
5
+
6
+ const findDirectMessageConversation = (apiClient: ApiClient, participantIds: string[]) =>
7
+ apiClient.chat.get({
8
+ url: '/me/conversations',
9
+ data: {
10
+ fields: { Conversation: ['title'] },
11
+ filter: 'with_exact_direct_message_participants',
12
+ participant_ids: participantIds.join(','),
13
+ },
14
+ }) as Promise<ApiCollection<ConversationResource>>
15
+
16
+ const createDirectMessageConversation = (apiClient: ApiClient, ids: string[]) =>
17
+ apiClient.chat.post({
18
+ url: '/me/direct_messages',
19
+ data: {
20
+ data: {
21
+ type: 'DirectMessage',
22
+ attributes: { recipients: ids },
23
+ },
24
+ },
25
+ }) as Promise<ApiResource<ConversationResource>>
26
+
27
+ interface Props {
28
+ recipientIds: string[]
29
+ onSuccess: (conversationId: ConversationResource['id']) => void
30
+ }
31
+
32
+ export function useFindOrCreateDirectMessageConversation({ recipientIds, onSuccess }: Props) {
33
+ const apiClient = useApiClient()
34
+ const [isFinding, setIsFinding] = useState(false)
35
+ const [isError, setIsError] = useState(false)
36
+
37
+ const { data } = useQuery({
38
+ queryKey: ['chat', '/me/conversations', 'with_exact_direct_message_participants', recipientIds],
39
+ queryFn: () => findDirectMessageConversation(apiClient, recipientIds),
40
+ enabled: recipientIds.length > 0,
41
+ })
42
+
43
+ const directMessageExists = (data?.data.length ?? 0) > 0
44
+
45
+ const findOrCreateConversation = useCallback(
46
+ async (participantIds: string[]) => {
47
+ setIsFinding(true)
48
+ setIsError(false)
49
+ try {
50
+ const findResponse = await findDirectMessageConversation(apiClient, participantIds)
51
+ if (findResponse.data.length > 0) {
52
+ onSuccess(findResponse.data[0].id)
53
+ } else {
54
+ const createResponse = await createDirectMessageConversation(apiClient, participantIds)
55
+ onSuccess(createResponse.data.id)
56
+ }
57
+ } catch {
58
+ setIsError(true)
59
+ setIsFinding(false)
60
+ }
61
+ },
62
+ [apiClient, onSuccess]
63
+ )
64
+
65
+ return { findOrCreateConversation, directMessageExists, isFinding, isError }
66
+ }
@@ -8,6 +8,7 @@ export * from './use_chat_permissions'
8
8
  export * from './use_create_android_ripple_color'
9
9
  export * from './use_current_person'
10
10
  export * from './use_deleting_ids'
11
+ export * from './use_direct_messages_enabled'
11
12
  export * from './use_font_scale'
12
13
  export * from './use_groups_groups'
13
14
  export * from './use_groups'
@@ -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
+ }
@@ -42,6 +42,7 @@ export const availableFeatures = {
42
42
  custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',
43
43
  conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
44
44
  video_moderation: 'ROLLOUT_MOBILE_video_moderation',
45
+ direct_messages_eap: 'ROLLOUT_direct_messages_eap',
45
46
  } as const satisfies Record<string, `ROLLOUT_${string}`>
46
47
 
47
48
  const stableEmptyFeatures: ApiCollection<FeatureResource> = {
@@ -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'
@@ -131,6 +132,20 @@ export const NewConversationStack = createNativeStackNavigator({
131
132
  ),
132
133
  }),
133
134
  },
135
+ ConversationSelectDirectMessageRecipients: {
136
+ screen: ConversationSelectDirectMessageRecipientsScreen,
137
+ if: useDirectMessagesEnabled,
138
+ options: ({ navigation, route }) => ({
139
+ title: 'New conversation',
140
+ headerRight: (props: NativeStackHeaderRightProps) => (
141
+ <HeaderTextButton
142
+ {...props}
143
+ onPress={() => navigation.popTo('Conversations', route.params)}
144
+ title="Cancel"
145
+ />
146
+ ),
147
+ }),
148
+ },
134
149
  ConversationFilterRecipients: {
135
150
  screen: ConversationFilterRecipientsScreen,
136
151
  options: ConversationFilterReceipientsScreenOptions,
@@ -0,0 +1,33 @@
1
+ import React from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
4
+ import { Heading, Text } from '../../components'
5
+ import { ConversationSelectRecipientsScreenProps } from './types/screen_props'
6
+
7
+ export function ConversationSelectDirectMessageRecipientsScreen(
8
+ _props: ConversationSelectRecipientsScreenProps
9
+ ) {
10
+ const styles = useStyles()
11
+
12
+ return (
13
+ <View style={styles.container}>
14
+ <Heading variant="h2">New direct message</Heading>
15
+ <Text variant="secondary">Coming soon</Text>
16
+ </View>
17
+ )
18
+ }
19
+
20
+ const useStyles = () => {
21
+ const { bottom } = useSafeAreaInsets()
22
+
23
+ return StyleSheet.create({
24
+ container: {
25
+ flex: 1,
26
+ padding: 16,
27
+ paddingBottom: 16 + bottom,
28
+ alignItems: 'center',
29
+ justifyContent: 'center',
30
+ gap: 8,
31
+ },
32
+ })
33
+ }
@@ -1,6 +1,7 @@
1
1
  import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
2
  import React from 'react'
3
3
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
4
+ import { availableFeatures, useFeatures } from '../hooks/use_features'
4
5
  import { useNewConversationEntry } from '../hooks/use_new_conversation_entry'
5
6
  import type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
6
7
  import { AppName } from '../types/resources/app_name'
@@ -17,15 +18,22 @@ export type ConversationSelectTypeScreenProps = StaticScreenProps<{
17
18
  newConversationFromFilter?: NewConversationFromFilter
18
19
  }>
19
20
 
21
+ type NewConversationTypeScreen =
22
+ | 'ConversationSelectGroupRecipients'
23
+ | 'ConversationSelectTeamsILeadRecipients'
24
+ | 'ConversationSelectDirectMessageRecipients'
25
+
20
26
  export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeScreenProps) {
21
27
  const navigation = useNavigation()
22
28
  const entryMode = useNewConversationEntry()
29
+ const { featureEnabled } = useFeatures()
23
30
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
24
31
  route.params || {}
25
32
 
26
33
  const filterParams = { chat_group_graph_id, group_source_app_name }
27
34
  const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'
28
35
  const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'
36
+ const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap)
29
37
 
30
38
  const handleFilterPress = () => {
31
39
  if (!newConversationFromFilter) return
@@ -55,27 +63,17 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
55
63
  })
56
64
  }
57
65
 
58
- const handleGroupPress = () => {
66
+ const navigateToNewConversationType = (screen: NewConversationTypeScreen) => {
59
67
  Haptic.impactLight()
60
68
  navigation.goBack()
61
- requestAnimationFrame(() => {
62
- navigation.navigate('New', {
63
- screen: 'ConversationSelectGroupRecipients',
64
- params: filterParams,
65
- })
66
- })
69
+ requestAnimationFrame(() => navigation.navigate('New', { screen, params: filterParams }))
67
70
  }
68
71
 
69
- const handleTeamPress = () => {
70
- Haptic.impactLight()
71
- navigation.goBack()
72
- requestAnimationFrame(() => {
73
- navigation.navigate('New', {
74
- screen: 'ConversationSelectTeamsILeadRecipients',
75
- params: filterParams,
76
- })
77
- })
78
- }
72
+ const handleGroupPress = () => navigateToNewConversationType('ConversationSelectGroupRecipients')
73
+ const handleTeamPress = () =>
74
+ navigateToNewConversationType('ConversationSelectTeamsILeadRecipients')
75
+ const handleDirectMessagePress = () =>
76
+ navigateToNewConversationType('ConversationSelectDirectMessageRecipients')
79
77
 
80
78
  return (
81
79
  <FormSheet.Root>
@@ -103,6 +101,13 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
103
101
  accessibilityHint="Opens team selection screen"
104
102
  />
105
103
  )}
104
+ {canCreateDMs && (
105
+ <FormSheet.Action
106
+ title="Direct message"
107
+ onPress={handleDirectMessagePress}
108
+ accessibilityHint="Opens direct message recipient selection screen"
109
+ />
110
+ )}
106
111
  </FormSheet.Root>
107
112
  )
108
113
  }
@@ -0,0 +1,8 @@
1
+ import { ResourceObject } from '../api_primitives'
2
+
3
+ export interface DirectMessageAffiliationsResource extends ResourceObject {
4
+ type: 'DirectMessageAffiliations'
5
+ id: string
6
+ groups: Record<string, string>
7
+ teams: Record<string, string>
8
+ }
@@ -0,0 +1,12 @@
1
+ import { ResourceObject } from '../api_primitives'
2
+
3
+ export interface DirectMessageCandidateResource extends ResourceObject {
4
+ type: 'DirectMessageCandidate'
5
+ id: string
6
+ name: string
7
+ avatar: string
8
+ groups: number[]
9
+ teams: number[]
10
+ under_18: boolean
11
+ directMessagesDisabled: boolean
12
+ }
@@ -1,4 +1,6 @@
1
1
  export * from './analytics_metadata'
2
+ export * from './direct_message_affiliations'
3
+ export * from './direct_message_candidate'
2
4
  export * from './conversation'
3
5
  export * from './conversation_membership'
4
6
  export * from './conversation_validate'