@planningcenter/chat-react-native 3.39.0-rc.9 → 3.39.1-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.
Files changed (59) hide show
  1. package/build/components/conversation/conversation_start_banner.d.ts +10 -0
  2. package/build/components/conversation/conversation_start_banner.d.ts.map +1 -0
  3. package/build/components/conversation/conversation_start_banner.js +68 -0
  4. package/build/components/conversation/conversation_start_banner.js.map +1 -0
  5. package/build/components/conversation/messages_disabled_banners.d.ts +6 -1
  6. package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
  7. package/build/components/conversation/messages_disabled_banners.js +8 -2
  8. package/build/components/conversation/messages_disabled_banners.js.map +1 -1
  9. package/build/components/primitive/form_sheet.d.ts +1 -0
  10. package/build/components/primitive/form_sheet.d.ts.map +1 -1
  11. package/build/components/primitive/form_sheet.js +17 -7
  12. package/build/components/primitive/form_sheet.js.map +1 -1
  13. package/build/hooks/use_conversation.d.ts.map +1 -1
  14. package/build/hooks/use_conversation.js +2 -0
  15. package/build/hooks/use_conversation.js.map +1 -1
  16. package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
  17. package/build/hooks/use_conversation_jolt_events.js +2 -2
  18. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  19. package/build/hooks/use_current_person.d.ts.map +1 -1
  20. package/build/hooks/use_current_person.js +1 -0
  21. package/build/hooks/use_current_person.js.map +1 -1
  22. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  23. package/build/screens/conversation_details_screen.js +2 -1
  24. package/build/screens/conversation_details_screen.js.map +1 -1
  25. package/build/screens/conversation_screen.d.ts.map +1 -1
  26. package/build/screens/conversation_screen.js +9 -3
  27. package/build/screens/conversation_screen.js.map +1 -1
  28. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js +1 -1
  29. package/build/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.js.map +1 -1
  30. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  31. package/build/screens/conversation_select_type_screen.js +4 -2
  32. package/build/screens/conversation_select_type_screen.js.map +1 -1
  33. package/build/types/jolt_events/conversation_events.d.ts +2 -0
  34. package/build/types/jolt_events/conversation_events.d.ts.map +1 -1
  35. package/build/types/jolt_events/conversation_events.js.map +1 -1
  36. package/build/types/resources/conversation.d.ts +3 -0
  37. package/build/types/resources/conversation.d.ts.map +1 -1
  38. package/build/types/resources/conversation.js.map +1 -1
  39. package/build/types/resources/person.d.ts +1 -0
  40. package/build/types/resources/person.d.ts.map +1 -1
  41. package/build/types/resources/person.js.map +1 -1
  42. package/build/utils/request/conversation.d.ts.map +1 -1
  43. package/build/utils/request/conversation.js +1 -0
  44. package/build/utils/request/conversation.js.map +1 -1
  45. package/package.json +2 -2
  46. package/src/components/conversation/conversation_start_banner.tsx +102 -0
  47. package/src/components/conversation/messages_disabled_banners.tsx +16 -2
  48. package/src/components/primitive/form_sheet.tsx +23 -6
  49. package/src/hooks/use_conversation.ts +2 -0
  50. package/src/hooks/use_conversation_jolt_events.ts +3 -2
  51. package/src/hooks/use_current_person.ts +1 -0
  52. package/src/screens/conversation_details_screen.tsx +2 -1
  53. package/src/screens/conversation_screen.tsx +13 -3
  54. package/src/screens/conversation_select_recipients/conversation_select_direct_message_recipients_screen.tsx +1 -0
  55. package/src/screens/conversation_select_type_screen.tsx +6 -2
  56. package/src/types/jolt_events/conversation_events.ts +2 -0
  57. package/src/types/resources/conversation.ts +4 -0
  58. package/src/types/resources/person.ts +1 -0
  59. package/src/utils/request/conversation.ts +1 -0
@@ -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 { useCurrentPerson } from '../hooks/use_current_person';
4
5
  import { availableFeatures, useFeatures } from '../hooks/use_features';
5
6
  import { useNewConversationEntry } from '../hooks/use_new_conversation_entry';
6
7
  import { Haptic } from '../utils/native_adapters';
@@ -11,11 +12,12 @@ export function ConversationSelectTypeScreen({ route }) {
11
12
  const navigation = useNavigation();
12
13
  const entryMode = useNewConversationEntry();
13
14
  const { featureEnabled } = useFeatures();
15
+ const { directMessagesDisabled, under_18 } = useCurrentPerson();
14
16
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } = route.params || {};
15
17
  const filterParams = { chat_group_graph_id, group_source_app_name };
16
18
  const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups';
17
19
  const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams';
18
- const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap);
20
+ const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap);
19
21
  const handleFilterPress = () => {
20
22
  if (!newConversationFromFilter)
21
23
  return;
@@ -59,7 +61,7 @@ export function ConversationSelectTypeScreen({ route }) {
59
61
  {newConversationFromFilter && (<FormSheet.Action title={`New conversation in ${newConversationFromFilter.name}`} onPress={handleFilterPress} accessibilityHint="Creates a conversation pre-scoped to the current filter"/>)}
60
62
  {canCreateGroups && (<FormSheet.Action title="Group" onPress={handleGroupPress} accessibilityHint="Opens group selection screen"/>)}
61
63
  {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"/>)}
64
+ {dmFeatureEnabled && !under_18 && (<FormSheet.Action title="Direct message" onPress={handleDirectMessagePress} disabled={directMessagesDisabled} disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined} accessibilityHint="Opens direct message recipient selection screen"/>)}
63
65
  </FormSheet.Root>);
64
66
  }
65
67
  //# 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 { 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"]}
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 { useCurrentPerson } from '../hooks/use_current_person'\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 { directMessagesDisabled, under_18 } = useCurrentPerson()\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 dmFeatureEnabled = 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 {dmFeatureEnabled && !under_18 && (\n <FormSheet.Action\n title=\"Direct message\"\n onPress={handleDirectMessagePress}\n disabled={directMessagesDisabled}\n disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined}\n accessibilityHint=\"Opens direct message recipient selection screen\"\n />\n )}\n </FormSheet.Root>\n )\n}\n"]}
@@ -1,4 +1,5 @@
1
1
  import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection';
2
+ import type { ConversationDisabledReason } from '../resources/conversation';
2
3
  type DateString = string;
3
4
  interface BaseConversationEventData extends Record<string, unknown> {
4
5
  data: {
@@ -14,6 +15,7 @@ interface BaseConversationEventData extends Record<string, unknown> {
14
15
  latest_read_message_sort_key?: string;
15
16
  organization_id: number;
16
17
  disabled: boolean;
18
+ disabled_reason?: ConversationDisabledReason;
17
19
  replies_disabled: boolean;
18
20
  subtitle?: string;
19
21
  title: string;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_events.d.ts","sourceRoot":"","sources":["../../../src/types/jolt_events/conversation_events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAA;AAE1F,KAAK,UAAU,GAAG,MAAM,CAAA;AACxB,UAAU,yBAA0B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,WAAW,EAAE,UAAU,CAAA;QACvB,UAAU,EAAE,UAAU,CAAA;QACtB,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,uBAAuB,CAAC,EAAE,UAAU,CAAA;QACpC,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3C,yBAAyB,CAAC,EAAE,MAAM,CAAA;QAClC,4BAA4B,CAAC,EAAE,MAAM,CAAA;QACrC,eAAe,EAAE,MAAM,CAAA;QACvB,QAAQ,EAAE,OAAO,CAAA;QACjB,gBAAgB,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,UAAU,CAAA;KACvB,CAAA;CACF;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,wBAAwB,CAAA;IAC/B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,KAAK,EAAE,mBAAmB,CAAA;IAC1B,IAAI,EAAE,yBAAyB,CAAA;CAChC"}
1
+ {"version":3,"file":"conversation_events.d.ts","sourceRoot":"","sources":["../../../src/types/jolt_events/conversation_events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uDAAuD,CAAA;AAC1F,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,2BAA2B,CAAA;AAE3E,KAAK,UAAU,GAAG,MAAM,CAAA;AACxB,UAAU,yBAA0B,SAAQ,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACjE,IAAI,EAAE;QACJ,EAAE,EAAE,MAAM,CAAA;QACV,WAAW,EAAE,UAAU,CAAA;QACvB,UAAU,EAAE,UAAU,CAAA;QACtB,sBAAsB,CAAC,EAAE,MAAM,CAAA;QAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;QACjC,uBAAuB,CAAC,EAAE,UAAU,CAAA;QACpC,qBAAqB,CAAC,EAAE,MAAM,CAAA;QAC9B,2BAA2B,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC3C,yBAAyB,CAAC,EAAE,MAAM,CAAA;QAClC,4BAA4B,CAAC,EAAE,MAAM,CAAA;QACrC,eAAe,EAAE,MAAM,CAAA;QACvB,QAAQ,EAAE,OAAO,CAAA;QACjB,eAAe,CAAC,EAAE,0BAA0B,CAAA;QAC5C,gBAAgB,EAAE,OAAO,CAAA;QACzB,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,UAAU,CAAA;KACvB,CAAA;CACF;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,sBAAsB,CAAA;IAC7B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,wBAAyB,SAAQ,aAAa;IAC7D,KAAK,EAAE,wBAAwB,CAAA;IAC/B,IAAI,EAAE,yBAAyB,CAAA;CAChC;AAED,MAAM,WAAW,qBAAsB,SAAQ,aAAa;IAC1D,KAAK,EAAE,mBAAmB,CAAA;IAC1B,IAAI,EAAE,yBAAyB,CAAA;CAChC"}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_events.js","sourceRoot":"","sources":["../../../src/types/jolt_events/conversation_events.ts"],"names":[],"mappings":"","sourcesContent":["import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'\n\ntype DateString = string\ninterface BaseConversationEventData extends Record<string, unknown> {\n data: {\n id: number\n archived_at: DateString\n created_at: DateString\n last_message_author_id?: number\n last_message_author_name?: string\n last_message_created_at?: DateString\n last_message_sort_key?: string\n last_message_idempotent_key?: string | null\n last_message_text_preview?: string\n latest_read_message_sort_key?: string\n organization_id: number\n disabled: boolean\n replies_disabled: boolean\n subtitle?: string\n title: string\n updated_at: DateString\n }\n}\n\nexport interface ConversationCreatedEvent extends CustomMessage {\n event: 'conversation.created'\n data: BaseConversationEventData\n}\n\nexport interface ConversationUpdatedEvent extends CustomMessage {\n event: 'conversation.updated'\n data: BaseConversationEventData\n}\n\nexport interface ConversationDeletedEvent extends CustomMessage {\n event: 'conversation.destroyed'\n data: BaseConversationEventData\n}\n\nexport interface ConversationReadEvent extends CustomMessage {\n event: 'conversation.read'\n data: BaseConversationEventData\n}\n"]}
1
+ {"version":3,"file":"conversation_events.js","sourceRoot":"","sources":["../../../src/types/jolt_events/conversation_events.ts"],"names":[],"mappings":"","sourcesContent":["import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'\nimport type { ConversationDisabledReason } from '../resources/conversation'\n\ntype DateString = string\ninterface BaseConversationEventData extends Record<string, unknown> {\n data: {\n id: number\n archived_at: DateString\n created_at: DateString\n last_message_author_id?: number\n last_message_author_name?: string\n last_message_created_at?: DateString\n last_message_sort_key?: string\n last_message_idempotent_key?: string | null\n last_message_text_preview?: string\n latest_read_message_sort_key?: string\n organization_id: number\n disabled: boolean\n disabled_reason?: ConversationDisabledReason\n replies_disabled: boolean\n subtitle?: string\n title: string\n updated_at: DateString\n }\n}\n\nexport interface ConversationCreatedEvent extends CustomMessage {\n event: 'conversation.created'\n data: BaseConversationEventData\n}\n\nexport interface ConversationUpdatedEvent extends CustomMessage {\n event: 'conversation.updated'\n data: BaseConversationEventData\n}\n\nexport interface ConversationDeletedEvent extends CustomMessage {\n event: 'conversation.destroyed'\n data: BaseConversationEventData\n}\n\nexport interface ConversationReadEvent extends CustomMessage {\n event: 'conversation.read'\n data: BaseConversationEventData\n}\n"]}
@@ -3,6 +3,7 @@ import { ConversationBadgeResource } from './conversation_badge';
3
3
  import { ConversationMembershipResource } from './conversation_membership';
4
4
  import { GroupResource } from './group_resource';
5
5
  import { MemberAbilityResource } from './member_ability';
6
+ export type ConversationDisabledReason = 'safety_check' | 'direct_messages_disabled';
6
7
  export interface ConversationResource {
7
8
  type: 'Conversation';
8
9
  id: number;
@@ -11,7 +12,9 @@ export interface ConversationResource {
11
12
  conversationMembership?: Partial<ConversationMembershipResource>;
12
13
  createdAt: string;
13
14
  deleted?: boolean;
15
+ directMessage?: boolean;
14
16
  disabled?: boolean;
17
+ disabledReason?: ConversationDisabledReason;
15
18
  genderOption?: string | null;
16
19
  groups?: GroupResource[];
17
20
  previewAvatarUrls?: string[];
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,yBAAyB,EAAE,CAAA;IACpC,iBAAiB,CAAC,EAAE,yBAAyB,CAAA;IAC7C,sBAAsB,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAA;IAChE,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;IACpD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAClB"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AACrE,OAAO,EAAE,yBAAyB,EAAE,MAAM,sBAAsB,CAAA;AAChE,OAAO,EAAE,8BAA8B,EAAE,MAAM,2BAA2B,CAAA;AAC1E,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAChD,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAExD,MAAM,MAAM,0BAA0B,GAAG,cAAc,GAAG,0BAA0B,CAAA;AAEpF,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,cAAc,CAAA;IACpB,EAAE,EAAE,MAAM,CAAA;IACV,MAAM,CAAC,EAAE,yBAAyB,EAAE,CAAA;IACpC,iBAAiB,CAAC,EAAE,yBAAyB,CAAA;IAC7C,sBAAsB,CAAC,EAAE,OAAO,CAAC,8BAA8B,CAAC,CAAA;IAChE,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,cAAc,CAAC,EAAE,0BAA0B,CAAA;IAC3C,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC5B,MAAM,CAAC,EAAE,aAAa,EAAE,CAAA;IACxB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5B,gBAAgB,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAA;IACpD,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,oBAAoB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,wBAAwB,CAAC,EAAE,MAAM,CAAA;IACjC,aAAa,CAAC,EAAE,qBAAqB,CAAA;IACrC,KAAK,EAAE,OAAO,CAAA;IACd,eAAe,EAAE,OAAO,CAAA;IACxB,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,EAAE,MAAM,CAAA;CAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnalyticsMetadataResource } from './analytics_metadata'\nimport { ConversationBadgeResource } from './conversation_badge'\nimport { ConversationMembershipResource } from './conversation_membership'\nimport { GroupResource } from './group_resource'\nimport { MemberAbilityResource } from './member_ability'\n\nexport interface ConversationResource {\n type: 'Conversation'\n id: number\n badges?: ConversationBadgeResource[]\n analyticsMetadata?: AnalyticsMetadataResource\n conversationMembership?: Partial<ConversationMembershipResource>\n createdAt: string\n deleted?: boolean\n disabled?: boolean\n genderOption?: string | null\n groups?: GroupResource[]\n previewAvatarUrls?: string[]\n customAvatarType?: 'image' | 'icon' | 'emoji' | null\n customAvatarKey?: string | null\n customAvatarColor?: string | null\n customAvatarImageUrl?: string | null\n lastMessageAuthorId?: string\n lastMessageAuthorName?: string\n lastMessageCreatedAt?: string\n lastMessageTextPreview?: string\n latestReadMessageSortKey?: string\n memberAbility?: MemberAbilityResource\n muted: boolean\n repliesDisabled: boolean\n title: string\n unreadCount: number\n unreadReactionCount?: number // Derived from Jolt events\n updatedAt: string\n}\n"]}
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/types/resources/conversation.ts"],"names":[],"mappings":"","sourcesContent":["import type { AnalyticsMetadataResource } from './analytics_metadata'\nimport { ConversationBadgeResource } from './conversation_badge'\nimport { ConversationMembershipResource } from './conversation_membership'\nimport { GroupResource } from './group_resource'\nimport { MemberAbilityResource } from './member_ability'\n\nexport type ConversationDisabledReason = 'safety_check' | 'direct_messages_disabled'\n\nexport interface ConversationResource {\n type: 'Conversation'\n id: number\n badges?: ConversationBadgeResource[]\n analyticsMetadata?: AnalyticsMetadataResource\n conversationMembership?: Partial<ConversationMembershipResource>\n createdAt: string\n deleted?: boolean\n directMessage?: boolean\n disabled?: boolean\n disabledReason?: ConversationDisabledReason\n genderOption?: string | null\n groups?: GroupResource[]\n previewAvatarUrls?: string[]\n customAvatarType?: 'image' | 'icon' | 'emoji' | null\n customAvatarKey?: string | null\n customAvatarColor?: string | null\n customAvatarImageUrl?: string | null\n lastMessageAuthorId?: string\n lastMessageAuthorName?: string\n lastMessageCreatedAt?: string\n lastMessageTextPreview?: string\n latestReadMessageSortKey?: string\n memberAbility?: MemberAbilityResource\n muted: boolean\n repliesDisabled: boolean\n title: string\n unreadCount: number\n unreadReactionCount?: number // Derived from Jolt events\n updatedAt: string\n}\n"]}
@@ -17,5 +17,6 @@ export interface CurrentPersonResource extends PersonResource {
17
17
  pcoChatEnabled: boolean;
18
18
  ageQualificationStatus?: AgeQualificationStatus;
19
19
  directMessagesDisabled: boolean;
20
+ under_18: boolean;
20
21
  }
21
22
  //# sourceMappingURL=person.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAA;AAEV,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAA;AAEtE,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;IACvB,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C,sBAAsB,EAAE,OAAO,CAAA;CAChC"}
1
+ {"version":3,"file":"person.d.ts","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAA;AAElD,eAAO,MAAM,sBAAsB;;;;CAIzB,CAAA;AAEV,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,OAAO,sBAAsB,CAAC,CAAA;AAEtE,MAAM,WAAW,cAAe,SAAQ,cAAc;IACpD,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,QAAQ,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,qBAAsB,SAAQ,cAAc;IAC3D,OAAO,EAAE,OAAO,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,OAAO,CAAA;IACvB,sBAAsB,CAAC,EAAE,sBAAsB,CAAA;IAC/C,sBAAsB,EAAE,OAAO,CAAA;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB"}
@@ -1 +1 @@
1
- {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;CACV,CAAA","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport const AgeQualificationStatus = {\n QUALIFIED: 'qualified',\n DISQUALIFIED: 'disqualified',\n UNKNOWN: 'unknown',\n} as const\n\nexport type AgeQualificationStatus =\n (typeof AgeQualificationStatus)[keyof typeof AgeQualificationStatus]\n\nexport interface PersonResource extends ResourceObject {\n id: number\n type: 'Person'\n name: string\n avatar: string\n}\n\nexport interface CurrentPersonResource extends PersonResource {\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n ageQualificationStatus?: AgeQualificationStatus\n directMessagesDisabled: boolean\n}\n"]}
1
+ {"version":3,"file":"person.js","sourceRoot":"","sources":["../../../src/types/resources/person.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,sBAAsB,GAAG;IACpC,SAAS,EAAE,WAAW;IACtB,YAAY,EAAE,cAAc;IAC5B,OAAO,EAAE,SAAS;CACV,CAAA","sourcesContent":["import { ResourceObject } from '../api_primitives'\n\nexport const AgeQualificationStatus = {\n QUALIFIED: 'qualified',\n DISQUALIFIED: 'disqualified',\n UNKNOWN: 'unknown',\n} as const\n\nexport type AgeQualificationStatus =\n (typeof AgeQualificationStatus)[keyof typeof AgeQualificationStatus]\n\nexport interface PersonResource extends ResourceObject {\n id: number\n type: 'Person'\n name: string\n avatar: string\n}\n\nexport interface CurrentPersonResource extends PersonResource {\n canChat: boolean\n unreadCount: number\n pcoChatEnabled: boolean\n ageQualificationStatus?: AgeQualificationStatus\n directMessagesDisabled: boolean\n under_18: boolean\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,2BAA2B,GAAI,8EAKzC,OAAO,CAAC,uBAAuB,CAAM,KAAG,UAiD1C,CAAA"}
1
+ {"version":3,"file":"conversation.d.ts","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAA;AAC9D,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAE5C,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAC/B;AAED,eAAO,MAAM,2BAA2B,GAAI,8EAKzC,OAAO,CAAC,uBAAuB,CAAM,KAAG,UAkD1C,CAAA"}
@@ -26,6 +26,7 @@ export const getConversationsRequestArgs = ({ gids, chat_group_graph_id, group_s
26
26
  'created_at',
27
27
  'badges',
28
28
  'disabled',
29
+ 'disabled_reason',
29
30
  'groups',
30
31
  'last_message_author_id',
31
32
  'last_message_author_name',
@@ -1 +1 @@
1
- {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,EAC1C,IAAI,EACJ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,MACgB,EAAE,EAAc,EAAE;IACtD,IAAI,MAAc,CAAA;IAClB,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,GAAG,OAAO,CAAA;IAClB,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,uBAAuB,CAAA;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,mBAAmB,CAAA;IAC9B,CAAC;IAED,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE;YACJ,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,eAAe;YACtB,MAAM;YACN,IAAI;YACJ,KAAK,EAAE,mBAAmB;YAC1B,qBAAqB;YACrB,MAAM,EAAE;gBACN,YAAY,EAAE;oBACZ,YAAY;oBACZ,QAAQ;oBACR,UAAU;oBACV,QAAQ;oBACR,wBAAwB;oBACxB,0BAA0B;oBAC1B,yBAAyB;oBACzB,2BAA2B;oBAC3B,qBAAqB;oBACrB,oBAAoB;oBACpB,mBAAmB;oBACnB,qBAAqB;oBACrB,yBAAyB;oBACzB,gBAAgB;oBAChB,OAAO;oBACP,kBAAkB;oBAClB,OAAO;oBACP,cAAc;oBACd,YAAY;iBACb;gBACD,iBAAiB,EAAE,CAAC,UAAU,CAAC;gBAC/B,iBAAiB,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC;aAC7D;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,oBAAoB,CAAC;SAC1C;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'disabled',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\n },\n }\n}\n"]}
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/utils/request/conversation.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,2BAA2B,GAAG,CAAC,EAC1C,IAAI,EACJ,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,MACgB,EAAE,EAAc,EAAE;IACtD,IAAI,MAAc,CAAA;IAClB,IAAI,mBAAmB,EAAE,CAAC;QACxB,MAAM,GAAG,OAAO,CAAA;IAClB,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,uBAAuB,CAAA;IAClC,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,mBAAmB,CAAA;IAC9B,CAAC;IAED,OAAO;QACL,GAAG,EAAE,mBAAmB;QACxB,IAAI,EAAE;YACJ,OAAO,EAAE,EAAE;YACX,KAAK,EAAE,eAAe;YACtB,MAAM;YACN,IAAI;YACJ,KAAK,EAAE,mBAAmB;YAC1B,qBAAqB;YACrB,MAAM,EAAE;gBACN,YAAY,EAAE;oBACZ,YAAY;oBACZ,QAAQ;oBACR,UAAU;oBACV,iBAAiB;oBACjB,QAAQ;oBACR,wBAAwB;oBACxB,0BAA0B;oBAC1B,yBAAyB;oBACzB,2BAA2B;oBAC3B,qBAAqB;oBACrB,oBAAoB;oBACpB,mBAAmB;oBACnB,qBAAqB;oBACrB,yBAAyB;oBACzB,gBAAgB;oBAChB,OAAO;oBACP,kBAAkB;oBAClB,OAAO;oBACP,cAAc;oBACd,YAAY;iBACb;gBACD,iBAAiB,EAAE,CAAC,UAAU,CAAC;gBAC/B,iBAAiB,EAAE,CAAC,UAAU,EAAE,mBAAmB,EAAE,MAAM,CAAC;aAC7D;YACD,OAAO,EAAE,CAAC,QAAQ,EAAE,oBAAoB,CAAC;SAC1C;KACF,CAAA;AACH,CAAC,CAAA","sourcesContent":["import { GraphId } from '../../types/resources/group_resource'\nimport { GetRequest } from '../client/types'\n\nexport interface ConversationRequestArgs {\n gids: string\n chat_group_graph_id?: GraphId\n group_source_app_name?: string\n show_direct_messages?: boolean\n}\n\nexport const getConversationsRequestArgs = ({\n gids,\n chat_group_graph_id,\n group_source_app_name,\n show_direct_messages,\n}: Partial<ConversationRequestArgs> = {}): GetRequest => {\n let filter: string\n if (chat_group_graph_id) {\n filter = 'group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'group_source_app_name'\n } else {\n filter = 'mine_or_not_empty'\n }\n\n return {\n url: '/me/conversations',\n data: {\n perPage: 20,\n order: '-last_message',\n filter,\n gids,\n group: chat_group_graph_id,\n group_source_app_name,\n fields: {\n Conversation: [\n 'created_at',\n 'badges',\n 'disabled',\n 'disabled_reason',\n 'groups',\n 'last_message_author_id',\n 'last_message_author_name',\n 'last_message_created_at',\n 'last_message_text_preview',\n 'preview_avatar_urls',\n 'custom_avatar_type',\n 'custom_avatar_key',\n 'custom_avatar_color',\n 'custom_avatar_image_url',\n 'member_ability',\n 'muted',\n 'replies_disabled',\n 'title',\n 'unread_count',\n 'updated_at',\n ],\n AnalyticsMetadata: ['metadata'],\n ConversationBadge: ['app_name', 'pco_resource_type', 'text'],\n },\n include: ['badges', 'analytics_metadata'],\n },\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@planningcenter/chat-react-native",
3
- "version": "3.39.0-rc.9",
3
+ "version": "3.39.1-rc.0",
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": "efc42ba18a6b517142779c36df3eb96ce6606d1f"
75
+ "gitHead": "b7e10e39ea3e6d0ba3af001d7a0f62b8ce7e4178"
76
76
  }
@@ -0,0 +1,102 @@
1
+ import React from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import { useTheme } from '../../hooks'
4
+ import type { ConversationResource } from '../../types'
5
+ import { tokens } from '../../vendor/tapestry/tokens'
6
+ import { ConversationAvatar } from '../display/conversation_avatar'
7
+ import { Heading } from '../display/heading'
8
+ import { Icon } from '../display/icon'
9
+ import { Text } from '../display/text'
10
+
11
+ type ConversationStartBannerData = Pick<
12
+ ConversationResource,
13
+ | 'title'
14
+ | 'customAvatarType'
15
+ | 'customAvatarKey'
16
+ | 'customAvatarColor'
17
+ | 'customAvatarImageUrl'
18
+ | 'previewAvatarUrls'
19
+ | 'directMessage'
20
+ >
21
+
22
+ interface ConversationStartBannerProps {
23
+ conversation: ConversationStartBannerData
24
+ hasMessages: boolean
25
+ }
26
+
27
+ export function ConversationStartBanner({
28
+ conversation,
29
+ hasMessages,
30
+ }: ConversationStartBannerProps) {
31
+ const styles = useStyles()
32
+ const { colors } = useTheme()
33
+ const introText = hasMessages
34
+ ? 'This is the beginning of your conversation.'
35
+ : 'This conversation is hidden from everyone until you send a message.'
36
+
37
+ return (
38
+ <View style={styles.container}>
39
+ <ConversationAvatar conversation={conversation} size="2xl" />
40
+ <Heading variant="h3" style={styles.title}>
41
+ {conversation.title}
42
+ </Heading>
43
+ <Text style={styles.subtitle}>{introText}</Text>
44
+ {conversation.directMessage && (
45
+ <View style={styles.safetyNotice}>
46
+ <Icon
47
+ name="general.shieldExclamation"
48
+ size={16}
49
+ color={colors.statusWarningComposedIcon}
50
+ style={styles.safetyIcon}
51
+ />
52
+ <Text style={styles.safetyText}>
53
+ {
54
+ "This is your church's communication platform. Be kind, stay safe, and report anything concerning."
55
+ }
56
+ </Text>
57
+ </View>
58
+ )}
59
+ </View>
60
+ )
61
+ }
62
+
63
+ const useStyles = () => {
64
+ const { colors } = useTheme()
65
+
66
+ return StyleSheet.create({
67
+ container: {
68
+ alignItems: 'center',
69
+ paddingHorizontal: 16,
70
+ paddingVertical: 24,
71
+ gap: 8,
72
+ },
73
+ title: {
74
+ textAlign: 'center',
75
+ },
76
+ subtitle: {
77
+ textAlign: 'center',
78
+ color: colors.textColorDefaultSecondary,
79
+ fontSize: tokens.fontSizeSm,
80
+ },
81
+ safetyNotice: {
82
+ flexDirection: 'row',
83
+ alignItems: 'flex-start',
84
+ gap: 8,
85
+ marginTop: 4,
86
+ padding: 12,
87
+ backgroundColor: colors.statusWarningComposedBackground,
88
+ borderColor: colors.statusWarningBorder,
89
+ borderWidth: 1,
90
+ borderRadius: 8,
91
+ width: '100%',
92
+ },
93
+ safetyIcon: {
94
+ marginTop: 1,
95
+ },
96
+ safetyText: {
97
+ flex: 1,
98
+ color: colors.statusWarningComposedText,
99
+ fontSize: tokens.fontSizeSm,
100
+ },
101
+ })
102
+ }
@@ -1,6 +1,7 @@
1
1
  import { StyleSheet, View, type ViewStyle } from 'react-native'
2
2
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
3
3
  import { useTheme } from '../../hooks'
4
+ import type { ConversationDisabledReason } from '../../types'
4
5
  import { ADULT_REQUIREMENT_BODY } from '../../utils'
5
6
  import { Text } from '../display'
6
7
 
@@ -21,10 +22,23 @@ export const MemberMessagesDisabledBanner = () => {
21
22
  )
22
23
  }
23
24
 
24
- export const ConversationDisabledBanner = () => {
25
+ const DISABLED_REASON_TEXT: Record<ConversationDisabledReason, string> = {
26
+ safety_check: ADULT_REQUIREMENT_BODY,
27
+ direct_messages_disabled: 'Direct messages have been turned off by someone in this conversation.',
28
+ }
29
+
30
+ const DEFAULT_DISABLED_TEXT = 'This conversation has been disabled.'
31
+
32
+ interface ConversationDisabledBannerProps {
33
+ disabledReason?: ConversationDisabledReason
34
+ }
35
+
36
+ export const ConversationDisabledBanner = ({ disabledReason }: ConversationDisabledBannerProps) => {
25
37
  const styles = useStyles()
38
+ const description =
39
+ (disabledReason && DISABLED_REASON_TEXT[disabledReason]) ?? DEFAULT_DISABLED_TEXT
26
40
 
27
- return <MessagesDisabledBanner description={ADULT_REQUIREMENT_BODY} style={styles.memberBanner} />
41
+ return <MessagesDisabledBanner description={description} style={styles.memberBanner} />
28
42
  }
29
43
 
30
44
  interface MessagesDisabledBannerProps {
@@ -242,6 +242,7 @@ interface FormSheetActionProps {
242
242
  accessibilityRole?: AccessibilityRole
243
243
  appearance?: FormSheetActionAppearanceUnion
244
244
  disabled?: boolean
245
+ disabledReason?: string
245
246
  }
246
247
 
247
248
  function FormSheetAction({
@@ -253,14 +254,17 @@ function FormSheetAction({
253
254
  accessibilityRole = 'button',
254
255
  appearance = 'neutral',
255
256
  disabled = false,
257
+ disabledReason,
256
258
  }: FormSheetActionProps) {
257
- const styles = useStyles({ appearance })
259
+ const styles = useStyles({ appearance, disabled })
258
260
 
259
261
  return (
260
262
  <PlatformPressable
261
263
  onPress={onPress}
262
264
  accessibilityLabel={accessibilityLabel}
263
- accessibilityHint={accessibilityHint}
265
+ accessibilityHint={
266
+ accessibilityHint ?? (disabled && disabledReason ? disabledReason : undefined)
267
+ }
264
268
  accessibilityRole={accessibilityRole}
265
269
  style={styles.actionPressable}
266
270
  disabled={disabled}
@@ -268,7 +272,12 @@ function FormSheetAction({
268
272
  {iconName && (
269
273
  <Icon name={iconName} size={16} accessibilityElementsHidden style={styles.actionIcon} />
270
274
  )}
271
- <Text style={styles.actionTitle}>{title}</Text>
275
+ <View style={styles.actionTextBlock}>
276
+ <Text style={styles.actionTitle}>{title}</Text>
277
+ {disabled && disabledReason && (
278
+ <Text style={styles.actionDisabledReason}>{disabledReason}</Text>
279
+ )}
280
+ </View>
272
281
  </PlatformPressable>
273
282
  )
274
283
  }
@@ -281,9 +290,10 @@ FormSheetAction.displayName = 'FormSheet.Action'
281
290
 
282
291
  interface Styles {
283
292
  appearance?: FormSheetActionAppearanceUnion
293
+ disabled?: boolean
284
294
  }
285
295
 
286
- const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
296
+ const useStyles = ({ appearance = 'neutral', disabled = false }: Styles = {}) => {
287
297
  const { colors } = useTheme()
288
298
  const { height } = useWindowDimensions()
289
299
  const { bottom, top } = useSafeAreaInsets()
@@ -368,10 +378,17 @@ const useStyles = ({ appearance = 'neutral' }: Styles = {}) => {
368
378
  gap: 8,
369
379
  },
370
380
  actionIcon: {
371
- color: appearanceColorsMap[appearance].iconColor,
381
+ color: disabled ? colors.textColorDefaultDisabled : appearanceColorsMap[appearance].iconColor,
382
+ },
383
+ actionTextBlock: {
384
+ flex: 1,
372
385
  },
373
386
  actionTitle: {
374
- color: appearanceColorsMap[appearance].textColor,
387
+ color: disabled ? colors.textColorDefaultDisabled : appearanceColorsMap[appearance].textColor,
388
+ },
389
+ actionDisabledReason: {
390
+ color: colors.textColorDefaultDisabled,
391
+ fontSize: 12,
375
392
  },
376
393
  })
377
394
  }
@@ -28,7 +28,9 @@ export const getConversationRequestArgs = ({ conversation_id }: { conversation_i
28
28
  'custom_avatar_key',
29
29
  'custom_avatar_color',
30
30
  'custom_avatar_image_url',
31
+ 'direct_message',
31
32
  'disabled',
33
+ 'disabled_reason',
32
34
  'member_ability',
33
35
  'muted',
34
36
  '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 })
@@ -17,6 +17,7 @@ export const currentPersonRequestArgs = {
17
17
  'pco_chat_enabled',
18
18
  'age_qualification_status',
19
19
  'direct_messages_disabled',
20
+ 'under_18',
20
21
  ],
21
22
  },
22
23
  },
@@ -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
  },
@@ -12,7 +12,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'
12
12
  import { FlatList, Platform, StyleSheet, View } from 'react-native'
13
13
  import { useSafeAreaInsets } from 'react-native-safe-area-context'
14
14
  import { Badge, Icon, Text } from '../components'
15
- import { EmptyConversationBlankState } from '../components/conversation/empty_conversation_blank_state'
15
+ import { ConversationStartBanner } from '../components/conversation/conversation_start_banner'
16
16
  import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button'
17
17
  import { Message } from '../components/conversation/message'
18
18
  import { MessageForm } from '../components/conversation/message_form'
@@ -166,7 +166,9 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
166
166
  <View style={styles.container}>
167
167
  <KeyboardView>
168
168
  {noMessages ? (
169
- <EmptyConversationBlankState />
169
+ <View style={styles.emptyState}>
170
+ <ConversationStartBanner conversation={conversation} hasMessages={false} />
171
+ </View>
170
172
  ) : (
171
173
  <FlatList
172
174
  inverted
@@ -176,6 +178,9 @@ function ConversationScreenContent({ route }: ConversationScreenProps) {
176
178
  keyExtractor={item => item.id}
177
179
  onScroll={trackScroll}
178
180
  scrollEventThrottle={10}
181
+ ListFooterComponent={
182
+ <ConversationStartBanner conversation={conversation} hasMessages={true} />
183
+ }
179
184
  renderItem={({ item }) => {
180
185
  if (item.type === 'DateSeparator') {
181
186
  return <InlineDateSeparator {...item} />
@@ -239,7 +244,8 @@ function ConversationBottomBar({
239
244
  replyRootId,
240
245
  currentlyEditingMessage,
241
246
  }: ConversationBottomBarProps) {
242
- if (conversation.disabled) return <ConversationDisabledBanner />
247
+ if (conversation.disabled)
248
+ return <ConversationDisabledBanner disabledReason={conversation.disabledReason} />
243
249
  if (!canReply) return <MemberMessagesDisabledBanner />
244
250
  return (
245
251
  <MessageForm.Root
@@ -386,6 +392,10 @@ const useStyles = () => {
386
392
  backgroundColor: navigationTheme.colors.card,
387
393
  paddingBottom: bottom,
388
394
  },
395
+ emptyState: {
396
+ flex: 1,
397
+ justifyContent: 'center',
398
+ },
389
399
  listContainer: {
390
400
  paddingVertical: 12,
391
401
  },
@@ -301,6 +301,7 @@ function CandidateList({
301
301
  return (
302
302
  <FlatList<DirectMessageCandidateResource>
303
303
  data={available}
304
+ keyboardShouldPersistTaps="handled"
304
305
  keyExtractor={item => item.id}
305
306
  renderItem={({ item }) => (
306
307
  <CandidateItem
@@ -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 { useCurrentPerson } from '../hooks/use_current_person'
4
5
  import { availableFeatures, useFeatures } from '../hooks/use_features'
5
6
  import { useNewConversationEntry } from '../hooks/use_new_conversation_entry'
6
7
  import type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
@@ -27,13 +28,14 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
27
28
  const navigation = useNavigation()
28
29
  const entryMode = useNewConversationEntry()
29
30
  const { featureEnabled } = useFeatures()
31
+ const { directMessagesDisabled, under_18 } = useCurrentPerson()
30
32
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
31
33
  route.params || {}
32
34
 
33
35
  const filterParams = { chat_group_graph_id, group_source_app_name }
34
36
  const canCreateGroups = entryMode === 'select_type' || entryMode === 'groups'
35
37
  const canCreateTeams = entryMode === 'select_type' || entryMode === 'teams'
36
- const canCreateDMs = featureEnabled(availableFeatures.direct_messages_eap)
38
+ const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)
37
39
 
38
40
  const handleFilterPress = () => {
39
41
  if (!newConversationFromFilter) return
@@ -101,10 +103,12 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
101
103
  accessibilityHint="Opens team selection screen"
102
104
  />
103
105
  )}
104
- {canCreateDMs && (
106
+ {dmFeatureEnabled && !under_18 && (
105
107
  <FormSheet.Action
106
108
  title="Direct message"
107
109
  onPress={handleDirectMessagePress}
110
+ disabled={directMessagesDisabled}
111
+ disabledReason={directMessagesDisabled ? 'Disabled in chat settings' : undefined}
108
112
  accessibilityHint="Opens direct message recipient selection screen"
109
113
  />
110
114
  )}
@@ -1,4 +1,5 @@
1
1
  import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'
2
+ import type { ConversationDisabledReason } from '../resources/conversation'
2
3
 
3
4
  type DateString = string
4
5
  interface BaseConversationEventData extends Record<string, unknown> {
@@ -15,6 +16,7 @@ interface BaseConversationEventData extends Record<string, unknown> {
15
16
  latest_read_message_sort_key?: string
16
17
  organization_id: number
17
18
  disabled: boolean
19
+ disabled_reason?: ConversationDisabledReason
18
20
  replies_disabled: boolean
19
21
  subtitle?: string
20
22
  title: string
@@ -4,6 +4,8 @@ import { ConversationMembershipResource } from './conversation_membership'
4
4
  import { GroupResource } from './group_resource'
5
5
  import { MemberAbilityResource } from './member_ability'
6
6
 
7
+ export type ConversationDisabledReason = 'safety_check' | 'direct_messages_disabled'
8
+
7
9
  export interface ConversationResource {
8
10
  type: 'Conversation'
9
11
  id: number
@@ -12,7 +14,9 @@ export interface ConversationResource {
12
14
  conversationMembership?: Partial<ConversationMembershipResource>
13
15
  createdAt: string
14
16
  deleted?: boolean
17
+ directMessage?: boolean
15
18
  disabled?: boolean
19
+ disabledReason?: ConversationDisabledReason
16
20
  genderOption?: string | null
17
21
  groups?: GroupResource[]
18
22
  previewAvatarUrls?: string[]
@@ -22,4 +22,5 @@ export interface CurrentPersonResource extends PersonResource {
22
22
  pcoChatEnabled: boolean
23
23
  ageQualificationStatus?: AgeQualificationStatus
24
24
  directMessagesDisabled: boolean
25
+ under_18: boolean
25
26
  }
@@ -39,6 +39,7 @@ export const getConversationsRequestArgs = ({
39
39
  'created_at',
40
40
  'badges',
41
41
  'disabled',
42
+ 'disabled_reason',
42
43
  'groups',
43
44
  'last_message_author_id',
44
45
  'last_message_author_name',