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

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 (84) hide show
  1. package/build/components/conversation/messages_disabled_banners.d.ts +2 -3
  2. package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
  3. package/build/components/conversation/messages_disabled_banners.js +2 -7
  4. package/build/components/conversation/messages_disabled_banners.js.map +1 -1
  5. package/build/components/display/adult_requirement_notice.js +1 -1
  6. package/build/components/display/adult_requirement_notice.js.map +1 -1
  7. package/build/hooks/index.d.ts +1 -1
  8. package/build/hooks/index.d.ts.map +1 -1
  9. package/build/hooks/index.js +1 -1
  10. package/build/hooks/index.js.map +1 -1
  11. package/build/hooks/use_conversation.d.ts.map +1 -1
  12. package/build/hooks/use_conversation.js +1 -0
  13. package/build/hooks/use_conversation.js.map +1 -1
  14. package/build/hooks/use_conversation_jolt_events.d.ts.map +1 -1
  15. package/build/hooks/use_conversation_jolt_events.js +10 -2
  16. package/build/hooks/use_conversation_jolt_events.js.map +1 -1
  17. package/build/hooks/use_current_person.d.ts.map +1 -1
  18. package/build/hooks/use_current_person.js +1 -0
  19. package/build/hooks/use_current_person.js.map +1 -1
  20. package/build/hooks/use_direct_messages_eligible.d.ts +2 -0
  21. package/build/hooks/use_direct_messages_eligible.d.ts.map +1 -0
  22. package/build/hooks/use_direct_messages_eligible.js +12 -0
  23. package/build/hooks/use_direct_messages_eligible.js.map +1 -0
  24. package/build/hooks/use_features.d.ts +0 -1
  25. package/build/hooks/use_features.d.ts.map +1 -1
  26. package/build/hooks/use_features.js +0 -1
  27. package/build/hooks/use_features.js.map +1 -1
  28. package/build/navigation/index.d.ts +2 -3
  29. package/build/navigation/index.d.ts.map +1 -1
  30. package/build/navigation/index.js +2 -2
  31. package/build/navigation/index.js.map +1 -1
  32. package/build/screens/conversation_filters/components/conversation_filters.js +3 -3
  33. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  34. package/build/screens/conversation_screen.js +1 -1
  35. package/build/screens/conversation_screen.js.map +1 -1
  36. package/build/screens/conversation_select_type_screen.d.ts.map +1 -1
  37. package/build/screens/conversation_select_type_screen.js +4 -7
  38. package/build/screens/conversation_select_type_screen.js.map +1 -1
  39. package/build/screens/conversations/components/list_header_component.js +3 -3
  40. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  41. package/build/screens/settings_screen.js +3 -3
  42. package/build/screens/settings_screen.js.map +1 -1
  43. package/build/types/jolt_events/conversation_events.d.ts +2 -2
  44. package/build/types/jolt_events/conversation_events.d.ts.map +1 -1
  45. package/build/types/jolt_events/conversation_events.js.map +1 -1
  46. package/build/types/resources/conversation.d.ts +2 -2
  47. package/build/types/resources/conversation.d.ts.map +1 -1
  48. package/build/types/resources/conversation.js.map +1 -1
  49. package/build/types/resources/person.d.ts +1 -0
  50. package/build/types/resources/person.d.ts.map +1 -1
  51. package/build/types/resources/person.js.map +1 -1
  52. package/build/utils/conversation_safety_constants.d.ts +1 -1
  53. package/build/utils/conversation_safety_constants.d.ts.map +1 -1
  54. package/build/utils/conversation_safety_constants.js +1 -1
  55. package/build/utils/conversation_safety_constants.js.map +1 -1
  56. package/build/utils/request/conversation.d.ts.map +1 -1
  57. package/build/utils/request/conversation.js +1 -0
  58. package/build/utils/request/conversation.js.map +1 -1
  59. package/package.json +3 -3
  60. package/src/__tests__/hooks/use_direct_messages_eligible.test.tsx +76 -0
  61. package/src/components/conversation/messages_disabled_banners.tsx +3 -11
  62. package/src/components/display/adult_requirement_notice.tsx +1 -1
  63. package/src/hooks/index.ts +1 -1
  64. package/src/hooks/use_conversation.ts +1 -0
  65. package/src/hooks/use_conversation_jolt_events.ts +16 -3
  66. package/src/hooks/use_current_person.ts +1 -0
  67. package/src/hooks/use_direct_messages_eligible.ts +14 -0
  68. package/src/hooks/use_features.ts +0 -1
  69. package/src/navigation/index.tsx +2 -2
  70. package/src/screens/conversation_filters/components/conversation_filters.tsx +3 -3
  71. package/src/screens/conversation_screen.tsx +1 -1
  72. package/src/screens/conversation_select_type_screen.tsx +4 -7
  73. package/src/screens/conversations/components/list_header_component.tsx +3 -3
  74. package/src/screens/settings_screen.tsx +3 -3
  75. package/src/types/jolt_events/conversation_events.ts +2 -2
  76. package/src/types/resources/conversation.ts +2 -3
  77. package/src/types/resources/person.ts +1 -0
  78. package/src/utils/conversation_safety_constants.ts +1 -1
  79. package/src/utils/request/conversation.ts +1 -0
  80. package/build/hooks/use_direct_messages_enabled.d.ts +0 -2
  81. package/build/hooks/use_direct_messages_enabled.d.ts.map +0 -1
  82. package/build/hooks/use_direct_messages_enabled.js +0 -16
  83. package/build/hooks/use_direct_messages_enabled.js.map +0 -1
  84. package/src/hooks/use_direct_messages_enabled.ts +0 -23
@@ -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;IAC/B,QAAQ,EAAE,OAAO,CAAA;CAClB"}
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,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 under_18: 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 directMessagesEligible: boolean\n under_18: boolean\n}\n"]}
@@ -1,2 +1,2 @@
1
- export declare const ADULT_REQUIREMENT_BODY = "Conversations with teens require at least 2 adults. This chat is paused until another adult is added.";
1
+ export declare const ADULT_REQUIREMENT_BODY = "Conversations with minors require at least two adults. This chat is paused until more adults are added.";
2
2
  //# sourceMappingURL=conversation_safety_constants.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_safety_constants.d.ts","sourceRoot":"","sources":["../../src/utils/conversation_safety_constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,0GACsE,CAAA"}
1
+ {"version":3,"file":"conversation_safety_constants.d.ts","sourceRoot":"","sources":["../../src/utils/conversation_safety_constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,4GACwE,CAAA"}
@@ -1,2 +1,2 @@
1
- export const ADULT_REQUIREMENT_BODY = 'Conversations with teens require at least 2 adults. This chat is paused until another adult is added.';
1
+ export const ADULT_REQUIREMENT_BODY = 'Conversations with minors require at least two adults. This chat is paused until more adults are added.';
2
2
  //# sourceMappingURL=conversation_safety_constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_safety_constants.js","sourceRoot":"","sources":["../../src/utils/conversation_safety_constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GACjC,uGAAuG,CAAA","sourcesContent":["export const ADULT_REQUIREMENT_BODY =\n 'Conversations with teens require at least 2 adults. This chat is paused until another adult is added.'\n"]}
1
+ {"version":3,"file":"conversation_safety_constants.js","sourceRoot":"","sources":["../../src/utils/conversation_safety_constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,sBAAsB,GACjC,yGAAyG,CAAA","sourcesContent":["export const ADULT_REQUIREMENT_BODY =\n 'Conversations with minors require at least two adults. This chat is paused until more adults are added.'\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,UAoD1C,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,UAqD1C,CAAA"}
@@ -28,6 +28,7 @@ export const getConversationsRequestArgs = ({ gids, chat_group_graph_id, group_s
28
28
  'conversation_preview',
29
29
  'disabled',
30
30
  'disabled_reason',
31
+ 'disabled_message',
31
32
  'groups',
32
33
  'last_message_author_id',
33
34
  '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,yBAAyB,CAAA;IACpC,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,yCAAyC,CAAA;IACpD,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,sBAAsB;oBACtB,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,iBAAiB;oBACjB,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 = 'mine_or_not_empty,group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'mine_or_not_empty,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 'conversation_preview',\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 'unread_reaction',\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,yBAAyB,CAAA;IACpC,CAAC;SAAM,IAAI,oBAAoB,EAAE,CAAC;QAChC,MAAM,GAAG,kCAAkC,CAAA;IAC7C,CAAC;SAAM,IAAI,qBAAqB,EAAE,CAAC;QACjC,MAAM,GAAG,yCAAyC,CAAA;IACpD,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,sBAAsB;oBACtB,UAAU;oBACV,iBAAiB;oBACjB,kBAAkB;oBAClB,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,iBAAiB;oBACjB,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 = 'mine_or_not_empty,group'\n } else if (show_direct_messages) {\n filter = 'mine_or_not_empty,direct_message'\n } else if (group_source_app_name) {\n filter = 'mine_or_not_empty,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 'conversation_preview',\n 'disabled',\n 'disabled_reason',\n 'disabled_message',\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 'unread_reaction',\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.43.0-rc.1",
3
+ "version": "3.43.0-rc.3",
4
4
  "description": "",
5
5
  "main": "build/index.js",
6
6
  "react-native": "./src/index.tsx",
@@ -26,7 +26,7 @@
26
26
  "dependencies": {
27
27
  "@fortawesome/fontawesome-svg-core": "^7.2.0",
28
28
  "@fortawesome/react-native-fontawesome": "^0.3.2",
29
- "@planningcenter/emoji-keyboard": "3.43.0-rc.1",
29
+ "@planningcenter/emoji-keyboard": "3.43.0-rc.3",
30
30
  "lodash-inflection": "^1.5.0",
31
31
  "react-compiler-runtime": "^1.0.0"
32
32
  },
@@ -72,5 +72,5 @@
72
72
  "react-native-url-polyfill": "^2.0.0",
73
73
  "typescript": "~6.0.3"
74
74
  },
75
- "gitHead": "6b139e3805ab55e4f33cd77f997b536e26c63841"
75
+ "gitHead": "91f1e0975da6c34342b4e54491e986b569b5d475"
76
76
  }
@@ -0,0 +1,76 @@
1
+ import { QueryClientProvider } from '@tanstack/react-query'
2
+ import { act, renderHook, waitFor } from '@testing-library/react-native'
3
+ import React from 'react'
4
+ import { buildTestQueryClient } from '../../__utils__/query_client'
5
+ import { ChatContext, ChatContextValue } from '../../contexts/chat_context'
6
+ import { ApiClient, useApiClient } from '../../hooks/use_api_client'
7
+ import { currentPersonQueryKey } from '../../hooks/use_current_person'
8
+ import { useDirectMessagesEligible } from '../../hooks/use_direct_messages_eligible'
9
+ import { Session } from '../../utils'
10
+
11
+ jest.mock('../../hooks/use_api_client')
12
+
13
+ const mockedUseApiClient = useApiClient as jest.MockedFunction<typeof useApiClient>
14
+
15
+ let get: jest.Mock
16
+
17
+ const session = new Session({ token: { access_token: 'a-real-token' } })
18
+
19
+ const renderUseDirectMessagesEligible = (queryClient = buildTestQueryClient()) => {
20
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
21
+ <QueryClientProvider client={queryClient}>
22
+ <ChatContext.Provider value={{ session } as unknown as ChatContextValue}>
23
+ {children}
24
+ </ChatContext.Provider>
25
+ </QueryClientProvider>
26
+ )
27
+
28
+ return { ...renderHook(() => useDirectMessagesEligible(), { wrapper }), queryClient }
29
+ }
30
+
31
+ beforeEach(() => {
32
+ get = jest.fn().mockResolvedValue({ data: { id: 1, directMessagesEligible: true } })
33
+ mockedUseApiClient.mockReturnValue({ chat: { get } } as unknown as ApiClient)
34
+ })
35
+
36
+ afterEach(() => {
37
+ jest.clearAllMocks()
38
+ })
39
+
40
+ describe('useDirectMessagesEligible', () => {
41
+ it('returns true once the person is fetched as eligible', async () => {
42
+ get.mockResolvedValue({
43
+ data: { id: 1, directMessagesEligible: true, directMessagesDisabled: true },
44
+ })
45
+
46
+ const { result } = renderUseDirectMessagesEligible()
47
+
48
+ await waitFor(() => expect(result.current).toBe(true))
49
+ })
50
+
51
+ it('returns false when the attribute is absent from the response', async () => {
52
+ get.mockResolvedValue({ data: { id: 1 } })
53
+
54
+ const { result } = renderUseDirectMessagesEligible()
55
+
56
+ await waitFor(() => expect(get).toHaveBeenCalled())
57
+ // false is also the hook's return value before the fetch resolves, so a plain check here
58
+ // could pass by coincidence against that early state. react-query schedules its update via
59
+ // a real setTimeout, so this waits for that timer to actually fire before asserting the
60
+ // settled value.
61
+ await act(() => new Promise(resolve => setTimeout(resolve, 0)))
62
+
63
+ expect(result.current).toBe(false)
64
+ })
65
+
66
+ it('reads the same /me cache entry as useCurrentPerson', () => {
67
+ const queryClient = buildTestQueryClient()
68
+ queryClient.setQueryData(currentPersonQueryKey, {
69
+ data: { id: 1, directMessagesEligible: true },
70
+ })
71
+
72
+ const { result } = renderUseDirectMessagesEligible(queryClient)
73
+
74
+ expect(result.current).toBe(true)
75
+ })
76
+ })
@@ -1,8 +1,6 @@
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'
5
- import { ADULT_REQUIREMENT_BODY } from '../../utils'
6
4
  import { Button, Text } from '../display'
7
5
 
8
6
  export const LeaderMessagesDisabledBanner = () => {
@@ -22,25 +20,19 @@ export const MemberMessagesDisabledBanner = () => {
22
20
  )
23
21
  }
24
22
 
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
23
  const DEFAULT_DISABLED_TEXT = 'This conversation has been disabled.'
31
24
 
32
25
  interface ConversationDisabledBannerProps {
33
- disabledReason?: ConversationDisabledReason
26
+ message: string | null
34
27
  messageLink?: { label: string; onPress: () => void }
35
28
  }
36
29
 
37
30
  export const ConversationDisabledBanner = ({
38
- disabledReason,
31
+ message,
39
32
  messageLink,
40
33
  }: ConversationDisabledBannerProps) => {
41
34
  const styles = useStyles()
42
- const description =
43
- (disabledReason && DISABLED_REASON_TEXT[disabledReason]) ?? DEFAULT_DISABLED_TEXT
35
+ const description = message ?? DEFAULT_DISABLED_TEXT
44
36
 
45
37
  return (
46
38
  <MessagesDisabledBanner
@@ -13,7 +13,7 @@ export function AdultRequirementNotice({ style }: AdultRequirementNoticeProps) {
13
13
  <BannerCollapsible
14
14
  appearance="warning"
15
15
  iconName="general.shieldExclamation"
16
- heading="2 adults required to chat"
16
+ heading="Two adults required to chat"
17
17
  style={style}
18
18
  >
19
19
  <BannerPrimitive.Text>{ADULT_REQUIREMENT_BODY}</BannerPrimitive.Text>
@@ -8,7 +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
+ export * from './use_direct_messages_eligible'
12
12
  export * from './use_font_scale'
13
13
  export * from './use_has_direct_messages'
14
14
  export * from './use_groups_groups'
@@ -32,6 +32,7 @@ export const getConversationRequestArgs = ({ conversation_id }: { conversation_i
32
32
  'direct_message',
33
33
  'disabled',
34
34
  'disabled_reason',
35
+ 'disabled_message',
35
36
  'member_ability',
36
37
  'muted',
37
38
  'replies_disabled',
@@ -26,8 +26,13 @@ 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, disabled_reason } =
30
- e.data.data
29
+ const {
30
+ last_message_idempotent_key,
31
+ last_message_author_id,
32
+ disabled,
33
+ disabled_reason,
34
+ disabled_message,
35
+ } = e.data.data
31
36
 
32
37
  if (last_message_idempotent_key && last_message_author_id === currentPersonId) {
33
38
  completeMessageCreationConversationTracking({
@@ -38,7 +43,15 @@ export function useConversationJoltEvents({ conversationId }: Props) {
38
43
 
39
44
  queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {
40
45
  if (!prev?.data) return prev
41
- return { ...prev, data: { ...prev.data, disabled, disabledReason: disabled_reason } }
46
+ return {
47
+ ...prev,
48
+ data: {
49
+ ...prev.data,
50
+ disabled,
51
+ disabledReason: disabled_reason,
52
+ disabledMessage: disabled_message,
53
+ },
54
+ }
42
55
  })
43
56
 
44
57
  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
+ 'direct_messages_eligible',
20
21
  'under_18',
21
22
  ],
22
23
  },
@@ -0,0 +1,14 @@
1
+ import { CurrentPersonResource } from '../types'
2
+ import { useApiGet } from './use_api'
3
+ import { currentPersonRequestArgs } from './use_current_person'
4
+
5
+ export const useDirectMessagesEligible = (): boolean => {
6
+ const { data: person, isFetched } = useApiGet<CurrentPersonResource>(currentPersonRequestArgs)
7
+
8
+ // This hook is used as a React Navigation `if:` predicate, which can't suspend, so this has
9
+ // to return a real boolean synchronously. Until the /me fetch resolves, that means failing
10
+ // closed to false rather than blocking so the route is briefly absent instead of the app hanging.
11
+ if (!isFetched) return false
12
+
13
+ return person?.directMessagesEligible ?? false
14
+ }
@@ -43,7 +43,6 @@ export const availableFeatures = {
43
43
  custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',
44
44
  conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',
45
45
  video_moderation: 'ROLLOUT_MOBILE_video_moderation',
46
- direct_messages_eap: 'ROLLOUT_direct_messages_eap',
47
46
  dm_search_clear_fix: 'ROLLOUT_MOBILE_dm_search_clear_fix',
48
47
  } as const satisfies Record<string, `ROLLOUT_${string}`>
49
48
 
@@ -14,7 +14,7 @@ import {
14
14
  HeaderDoneButton,
15
15
  HeaderTextButton,
16
16
  } from '../components/display/platform_modal_header_buttons'
17
- import { useDirectMessagesEnabled, useQualifiedByAge } from '../hooks'
17
+ import { useDirectMessagesEligible, useQualifiedByAge } from '../hooks'
18
18
  import {
19
19
  AttachmentActionsScreen,
20
20
  AttachmentActionsScreenOptions,
@@ -128,7 +128,7 @@ export const NewConversationStack = createNativeStackNavigator({
128
128
  },
129
129
  ConversationSelectDirectMessageRecipients: {
130
130
  screen: ConversationSelectDirectMessageRecipientsScreen,
131
- if: useDirectMessagesEnabled,
131
+ if: useDirectMessagesEligible,
132
132
  options: ({ navigation, route }) => ({
133
133
  title: 'New conversation',
134
134
  headerRight: (props: NativeStackHeaderRightProps) => (
@@ -4,7 +4,7 @@ import { FlatList } from 'react-native-gesture-handler'
4
4
  import { Heading } from '../../../components'
5
5
  import {
6
6
  useAtFontScaleBreakpoint,
7
- useDirectMessagesEnabled,
7
+ useDirectMessagesEligible,
8
8
  useHasDirectMessages,
9
9
  useTheme,
10
10
  } from '../../../hooks'
@@ -59,9 +59,9 @@ export const ConversationFilters = () => {
59
59
  const { setScrollOffset, params } = useContext(FilterContext)
60
60
  const { chat_group_graph_id, group_source_app_name = '', show_direct_messages } = params
61
61
 
62
- const directMessagesEnabled = useDirectMessagesEnabled()
62
+ const directMessagesEligible = useDirectMessagesEligible()
63
63
  const hasDirectMessages = useHasDirectMessages()
64
- const canFilterByDMs = directMessagesEnabled && hasDirectMessages
64
+ const canFilterByDMs = directMessagesEligible && hasDirectMessages
65
65
 
66
66
  const activeFilter: FilterTypes = useMemo(() => {
67
67
  if (chat_group_graph_id) {
@@ -257,7 +257,7 @@ function ConversationBottomBar({
257
257
  if (conversation.disabled)
258
258
  return (
259
259
  <ConversationDisabledBanner
260
- disabledReason={conversation.disabledReason}
260
+ message={conversation.disabledMessage ?? null}
261
261
  messageLink={messageLink}
262
262
  />
263
263
  )
@@ -2,7 +2,6 @@ import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
2
  import React, { useLayoutEffect } from 'react'
3
3
  import FormSheet, { getFormSheetScreenOptions } from '../components/primitive/form_sheet'
4
4
  import { useCurrentPerson } from '../hooks/use_current_person'
5
- import { availableFeatures, useFeatures } from '../hooks/use_features'
6
5
  import { useConversationTypeAccess } from '../hooks/use_new_conversation_entry'
7
6
  import type { NewConversationFromFilter } from '../hooks/use_new_conversation_from_filter'
8
7
  import { AppName } from '../types/resources/app_name'
@@ -28,17 +27,15 @@ export function ConversationSelectTypeScreen({ route }: ConversationSelectTypeSc
28
27
  const navigation = useNavigation()
29
28
  const { canCreateGroupsConversations, canCreateServicesConversations } =
30
29
  useConversationTypeAccess()
31
- const { featureEnabled } = useFeatures()
32
- const { directMessagesDisabled, under_18 } = useCurrentPerson()
30
+ const { directMessagesDisabled, directMessagesEligible } = useCurrentPerson()
33
31
  const { newConversationFromFilter, chat_group_graph_id, group_source_app_name } =
34
32
  route.params || {}
35
33
 
36
34
  const filterParams = { chat_group_graph_id, group_source_app_name }
37
- const dmFeatureEnabled = featureEnabled(availableFeatures.direct_messages_eap)
38
- const showDirectMessageOption = dmFeatureEnabled && !under_18
35
+ const showDirectMessageOption = directMessagesEligible
39
36
 
40
- // sheetAllowedDetents depends on the DM feature flag, which isn't known until render, so it's
41
- // set here instead of in the static ConversationSelectTypeScreenOptions. useLayoutEffect applies
37
+ // sheetAllowedDetents depends on DM eligibility, which isn't known until render, so it's set
38
+ // here instead of in the static ConversationSelectTypeScreenOptions. useLayoutEffect applies
42
39
  // it before paint so the sheet never visibly resizes after opening.
43
40
  useLayoutEffect(() => {
44
41
  navigation.setOptions({ sheetAllowedDetents: showDirectMessageOption ? [0.3] : [0.25] })
@@ -6,7 +6,7 @@ import {
6
6
  useAtFontScaleBreakpoint,
7
7
  useCanCreateConversations,
8
8
  useCurrentPersonCache,
9
- useDirectMessagesEnabled,
9
+ useDirectMessagesEligible,
10
10
  useHasDirectMessages,
11
11
  useNewConversationEntry,
12
12
  useTheme,
@@ -35,9 +35,9 @@ export const ListHeaderComponent = () => {
35
35
  const navigation = useNavigation()
36
36
  const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' })
37
37
  const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' })
38
- const directMessagesEnabled = useDirectMessagesEnabled()
38
+ const directMessagesEligible = useDirectMessagesEligible()
39
39
  const hasDirectMessages = useHasDirectMessages()
40
- const canFilterByDMs = directMessagesEnabled && hasDirectMessages
40
+ const canFilterByDMs = directMessagesEligible && hasDirectMessages
41
41
  const route = useRoute<RouteProp<ConversationsScreenProps['route']>>()
42
42
  const {
43
43
  chat_group_graph_id,
@@ -4,7 +4,7 @@ import React, { useCallback } from 'react'
4
4
  import { Platform, StyleSheet, View } from 'react-native'
5
5
  import { Heading, Icon, Text } from '../components'
6
6
  import { Switch } from '../components/display/switch'
7
- import { useDirectMessagesEnabled, useTheme } from '../hooks'
7
+ import { useDirectMessagesEligible, useTheme } from '../hooks'
8
8
  import { useAppName } from '../hooks/use_app_name'
9
9
  import { usePersonSettings } from '../hooks/use_person_settings'
10
10
 
@@ -13,7 +13,7 @@ export type SettingsScreenProps = StaticScreenProps<{}>
13
13
  export function SettingsScreen({}: SettingsScreenProps) {
14
14
  const styles = useStyles()
15
15
  const { directMessagesDisabled, setDirectMessagesDisabled, isMutating } = usePersonSettings()
16
- const directMessagesEnabled = useDirectMessagesEnabled()
16
+ const directMessagesEligible = useDirectMessagesEligible()
17
17
  const appName = useAppName()
18
18
  const navigation = useNavigation()
19
19
 
@@ -31,7 +31,7 @@ export function SettingsScreen({}: SettingsScreenProps) {
31
31
  <View style={styles.sectionHeader}>
32
32
  <Heading variant="h2">Messages</Heading>
33
33
  </View>
34
- {directMessagesEnabled && (
34
+ {directMessagesEligible && (
35
35
  <View style={styles.settingRow}>
36
36
  <View style={styles.settingRowText}>
37
37
  <Text>Allow direct messages</Text>
@@ -1,5 +1,4 @@
1
1
  import type { CustomMessage } from '@planningcenter/jolt-client/dist/types/JoltConnection'
2
- import type { ConversationDisabledReason } from '../resources/conversation'
3
2
 
4
3
  type DateString = string
5
4
  interface BaseConversationEventData extends Record<string, unknown> {
@@ -16,7 +15,8 @@ interface BaseConversationEventData extends Record<string, unknown> {
16
15
  latest_read_message_sort_key?: string
17
16
  organization_id: number
18
17
  disabled: boolean
19
- disabled_reason?: ConversationDisabledReason
18
+ disabled_reason: string | null
19
+ disabled_message: string | null
20
20
  replies_disabled: boolean
21
21
  subtitle?: string
22
22
  title: string
@@ -5,8 +5,6 @@ import { GroupResource } from './group_resource'
5
5
  import { MemberAbilityResource } from './member_ability'
6
6
  import { ReactionCountResource } from './reaction'
7
7
 
8
- export type ConversationDisabledReason = 'safety_check' | 'direct_messages_disabled'
9
-
10
8
  export interface ConversationPreviewData {
11
9
  kind: 'reaction' | 'message'
12
10
  authorName: string
@@ -26,7 +24,8 @@ export interface ConversationResource {
26
24
  deleted?: boolean
27
25
  directMessage?: boolean
28
26
  disabled?: boolean
29
- disabledReason?: ConversationDisabledReason
27
+ disabledReason?: string | null
28
+ disabledMessage?: string | null
30
29
  genderOption?: string | null
31
30
  groups?: GroupResource[]
32
31
  previewAvatarUrls?: string[]
@@ -22,5 +22,6 @@ export interface CurrentPersonResource extends PersonResource {
22
22
  pcoChatEnabled: boolean
23
23
  ageQualificationStatus?: AgeQualificationStatus
24
24
  directMessagesDisabled: boolean
25
+ directMessagesEligible: boolean
25
26
  under_18: boolean
26
27
  }
@@ -1,2 +1,2 @@
1
1
  export const ADULT_REQUIREMENT_BODY =
2
- 'Conversations with teens require at least 2 adults. This chat is paused until another adult is added.'
2
+ 'Conversations with minors require at least two adults. This chat is paused until more adults are added.'
@@ -41,6 +41,7 @@ export const getConversationsRequestArgs = ({
41
41
  'conversation_preview',
42
42
  'disabled',
43
43
  'disabled_reason',
44
+ 'disabled_message',
44
45
  'groups',
45
46
  'last_message_author_id',
46
47
  'last_message_author_name',
@@ -1,2 +0,0 @@
1
- export declare function useDirectMessagesEnabled(): boolean;
2
- //# sourceMappingURL=use_direct_messages_enabled.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_direct_messages_enabled.d.ts","sourceRoot":"","sources":["../../src/hooks/use_direct_messages_enabled.ts"],"names":[],"mappings":"AAOA,wBAAgB,wBAAwB,IAAI,OAAO,CAelD"}
@@ -1,16 +0,0 @@
1
- import { useQuery } from '@tanstack/react-query';
2
- import { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features';
3
- import { useApiClient } from './use_api_client';
4
- import { availableFeatures } from './use_features';
5
- export function useDirectMessagesEnabled() {
6
- const apiClient = useApiClient();
7
- const { data, isFetched } = useQuery({
8
- queryKey: getFeaturesQueryKey(),
9
- queryFn: () => apiClient.chat.get(getFeaturesRequestArgs()),
10
- staleTime: 1000 * 60 * 5,
11
- });
12
- if (!isFetched)
13
- return false;
14
- return (data?.data.some(feature => feature.name === availableFeatures.direct_messages_eap && feature.enabled) ?? false);
15
- }
16
- //# sourceMappingURL=use_direct_messages_enabled.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use_direct_messages_enabled.js","sourceRoot":"","sources":["../../src/hooks/use_direct_messages_enabled.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAA;AAGhD,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,MAAM,UAAU,wBAAwB;IACtC,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,QAAQ,CAAiC;QACnE,QAAQ,EAAE,mBAAmB,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAiC,sBAAsB,EAAE,CAAC;QAC3F,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC;KACzB,CAAC,CAAA;IAEF,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAA;IAE5B,OAAO,CACL,IAAI,EAAE,IAAI,CAAC,IAAI,CACb,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,iBAAiB,CAAC,mBAAmB,IAAI,OAAO,CAAC,OAAO,CACrF,IAAI,KAAK,CACX,CAAA;AACH,CAAC","sourcesContent":["import { useQuery } from '@tanstack/react-query'\nimport { ApiCollection } from '../types'\nimport type { FeatureResource } from '../types/resources/feature_resource'\nimport { getFeaturesRequestArgs, getFeaturesQueryKey } from '../utils/request/get_features'\nimport { useApiClient } from './use_api_client'\nimport { availableFeatures } from './use_features'\n\nexport function useDirectMessagesEnabled(): boolean {\n const apiClient = useApiClient()\n const { data, isFetched } = useQuery<ApiCollection<FeatureResource>>({\n queryKey: getFeaturesQueryKey(),\n queryFn: () => apiClient.chat.get<ApiCollection<FeatureResource>>(getFeaturesRequestArgs()),\n staleTime: 1000 * 60 * 5,\n })\n\n if (!isFetched) return false\n\n return (\n data?.data.some(\n feature => feature.name === availableFeatures.direct_messages_eap && feature.enabled\n ) ?? false\n )\n}\n"]}
@@ -1,23 +0,0 @@
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
- }