@planningcenter/chat-react-native 3.37.1-qa-736.0 → 3.37.1-qa-747.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 (171) hide show
  1. package/build/components/conversation/jump_to_bottom_button.d.ts +1 -2
  2. package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
  3. package/build/components/conversation/jump_to_bottom_button.js +7 -39
  4. package/build/components/conversation/jump_to_bottom_button.js.map +1 -1
  5. package/build/components/conversation/message_form.d.ts.map +1 -1
  6. package/build/components/conversation/message_form.js +7 -19
  7. package/build/components/conversation/message_form.js.map +1 -1
  8. package/build/components/conversation/reply_shadow_message.d.ts +2 -1
  9. package/build/components/conversation/reply_shadow_message.d.ts.map +1 -1
  10. package/build/components/conversation/reply_shadow_message.js.map +1 -1
  11. package/build/components/conversations/conversations.d.ts.map +1 -1
  12. package/build/components/conversations/conversations.js +16 -6
  13. package/build/components/conversations/conversations.js.map +1 -1
  14. package/build/contexts/conversation_context.d.ts +1 -8
  15. package/build/contexts/conversation_context.d.ts.map +1 -1
  16. package/build/contexts/conversation_context.js +3 -21
  17. package/build/contexts/conversation_context.js.map +1 -1
  18. package/build/hooks/use_attachment_uploader.d.ts.map +1 -1
  19. package/build/hooks/use_attachment_uploader.js +0 -9
  20. package/build/hooks/use_attachment_uploader.js.map +1 -1
  21. package/build/hooks/use_conversation_messages.d.ts +6 -15
  22. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  23. package/build/hooks/use_conversation_messages.js +9 -62
  24. package/build/hooks/use_conversation_messages.js.map +1 -1
  25. package/build/hooks/use_conversation_messages_jolt_events.d.ts.map +1 -1
  26. package/build/hooks/use_conversation_messages_jolt_events.js +4 -4
  27. package/build/hooks/use_conversation_messages_jolt_events.js.map +1 -1
  28. package/build/hooks/use_conversations_actions.d.ts +0 -5
  29. package/build/hooks/use_conversations_actions.d.ts.map +1 -1
  30. package/build/hooks/use_conversations_actions.js +0 -12
  31. package/build/hooks/use_conversations_actions.js.map +1 -1
  32. package/build/hooks/use_features.d.ts +0 -2
  33. package/build/hooks/use_features.d.ts.map +1 -1
  34. package/build/hooks/use_features.js +0 -2
  35. package/build/hooks/use_features.js.map +1 -1
  36. package/build/hooks/use_mark_latest_message_read.d.ts +1 -1
  37. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  38. package/build/hooks/use_mark_latest_message_read.js +1 -17
  39. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  40. package/build/hooks/use_suspense_api.d.ts +0 -1
  41. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  42. package/build/hooks/use_suspense_api.js +1 -1
  43. package/build/hooks/use_suspense_api.js.map +1 -1
  44. package/build/hooks/use_upload_client.d.ts +0 -4
  45. package/build/hooks/use_upload_client.d.ts.map +1 -1
  46. package/build/hooks/use_upload_client.js +1 -13
  47. package/build/hooks/use_upload_client.js.map +1 -1
  48. package/build/jest.js +1 -1
  49. package/build/jest.js.map +1 -1
  50. package/build/screens/age_check/age_check_underage_screen.js +1 -1
  51. package/build/screens/age_check/age_check_underage_screen.js.map +1 -1
  52. package/build/screens/avatar_picker/emoji_tab.d.ts.map +1 -1
  53. package/build/screens/avatar_picker/emoji_tab.js +6 -2
  54. package/build/screens/avatar_picker/emoji_tab.js.map +1 -1
  55. package/build/screens/conversation_screen.d.ts +0 -1
  56. package/build/screens/conversation_screen.d.ts.map +1 -1
  57. package/build/screens/conversation_screen.js +48 -95
  58. package/build/screens/conversation_screen.js.map +1 -1
  59. package/build/types/jolt_events/index.d.ts +1 -3
  60. package/build/types/jolt_events/index.d.ts.map +1 -1
  61. package/build/types/jolt_events/index.js.map +1 -1
  62. package/build/utils/cache/messages_cache.d.ts +0 -1
  63. package/build/utils/cache/messages_cache.d.ts.map +1 -1
  64. package/build/utils/cache/messages_cache.js +0 -4
  65. package/build/utils/cache/messages_cache.js.map +1 -1
  66. package/build/utils/group_messages.d.ts +2 -9
  67. package/build/utils/group_messages.d.ts.map +1 -1
  68. package/build/utils/group_messages.js +1 -20
  69. package/build/utils/group_messages.js.map +1 -1
  70. package/package.json +4 -4
  71. package/src/__tests__/hooks/use_attachment_uploader.test.tsx +0 -36
  72. package/src/__tests__/jest.ts +1 -1
  73. package/src/components/conversation/jump_to_bottom_button.tsx +8 -57
  74. package/src/components/conversation/message_form.tsx +7 -21
  75. package/src/components/conversation/reply_shadow_message.tsx +1 -1
  76. package/src/components/conversations/conversations.tsx +16 -9
  77. package/src/contexts/conversation_context.tsx +2 -30
  78. package/src/hooks/use_attachment_uploader.ts +1 -14
  79. package/src/hooks/use_conversation_messages.ts +20 -120
  80. package/src/hooks/use_conversation_messages_jolt_events.ts +3 -4
  81. package/src/hooks/use_conversations_actions.ts +0 -15
  82. package/src/hooks/use_features.ts +0 -2
  83. package/src/hooks/use_mark_latest_message_read.ts +2 -16
  84. package/src/hooks/use_suspense_api.ts +1 -1
  85. package/src/hooks/use_upload_client.ts +1 -19
  86. package/src/jest.ts +1 -1
  87. package/src/screens/age_check/age_check_underage_screen.tsx +1 -1
  88. package/src/screens/avatar_picker/emoji_tab.tsx +6 -2
  89. package/src/screens/conversation_screen.tsx +76 -184
  90. package/src/types/jolt_events/index.ts +0 -3
  91. package/src/utils/__tests__/group_messages.test.ts +0 -71
  92. package/src/utils/cache/messages_cache.ts +0 -5
  93. package/src/utils/group_messages.ts +2 -42
  94. package/build/components/conversation/message_list.d.ts +0 -10
  95. package/build/components/conversation/message_list.d.ts.map +0 -1
  96. package/build/components/conversation/message_list.js +0 -13
  97. package/build/components/conversation/message_list.js.map +0 -1
  98. package/build/components/conversation/unread_divider.d.ts +0 -6
  99. package/build/components/conversation/unread_divider.d.ts.map +0 -1
  100. package/build/components/conversation/unread_divider.js +0 -59
  101. package/build/components/conversation/unread_divider.js.map +0 -1
  102. package/build/components/conversations/conversations_blank_state.d.ts +0 -8
  103. package/build/components/conversations/conversations_blank_state.d.ts.map +0 -1
  104. package/build/components/conversations/conversations_blank_state.js +0 -25
  105. package/build/components/conversations/conversations_blank_state.js.map +0 -1
  106. package/build/hooks/use_flat_list_viewability.d.ts +0 -20
  107. package/build/hooks/use_flat_list_viewability.d.ts.map +0 -1
  108. package/build/hooks/use_flat_list_viewability.js +0 -30
  109. package/build/hooks/use_flat_list_viewability.js.map +0 -1
  110. package/build/hooks/use_jump_to_bottom_action.d.ts +0 -9
  111. package/build/hooks/use_jump_to_bottom_action.d.ts.map +0 -1
  112. package/build/hooks/use_jump_to_bottom_action.js +0 -62
  113. package/build/hooks/use_jump_to_bottom_action.js.map +0 -1
  114. package/build/hooks/use_jump_to_unread_anchor.d.ts +0 -20
  115. package/build/hooks/use_jump_to_unread_anchor.d.ts.map +0 -1
  116. package/build/hooks/use_jump_to_unread_anchor.js +0 -53
  117. package/build/hooks/use_jump_to_unread_anchor.js.map +0 -1
  118. package/build/hooks/use_jump_to_unread_gates.d.ts +0 -5
  119. package/build/hooks/use_jump_to_unread_gates.d.ts.map +0 -1
  120. package/build/hooks/use_jump_to_unread_gates.js +0 -10
  121. package/build/hooks/use_jump_to_unread_gates.js.map +0 -1
  122. package/build/hooks/use_scroll_tracking.d.ts +0 -13
  123. package/build/hooks/use_scroll_tracking.d.ts.map +0 -1
  124. package/build/hooks/use_scroll_tracking.js +0 -45
  125. package/build/hooks/use_scroll_tracking.js.map +0 -1
  126. package/build/hooks/use_track_highest_seen_message.d.ts +0 -4
  127. package/build/hooks/use_track_highest_seen_message.d.ts.map +0 -1
  128. package/build/hooks/use_track_highest_seen_message.js +0 -35
  129. package/build/hooks/use_track_highest_seen_message.js.map +0 -1
  130. package/build/types/jolt_events/attachment_events.d.ts +0 -14
  131. package/build/types/jolt_events/attachment_events.d.ts.map +0 -1
  132. package/build/types/jolt_events/attachment_events.js +0 -2
  133. package/build/types/jolt_events/attachment_events.js.map +0 -1
  134. package/build/utils/conversation_messages.d.ts +0 -10
  135. package/build/utils/conversation_messages.d.ts.map +0 -1
  136. package/build/utils/conversation_messages.js +0 -22
  137. package/build/utils/conversation_messages.js.map +0 -1
  138. package/build/utils/highest_seen_tracker.d.ts +0 -12
  139. package/build/utils/highest_seen_tracker.d.ts.map +0 -1
  140. package/build/utils/highest_seen_tracker.js +0 -37
  141. package/build/utils/highest_seen_tracker.js.map +0 -1
  142. package/build/utils/message_viewability.d.ts +0 -24
  143. package/build/utils/message_viewability.d.ts.map +0 -1
  144. package/build/utils/message_viewability.js +0 -29
  145. package/build/utils/message_viewability.js.map +0 -1
  146. package/build/utils/unread_divider_helpers.d.ts +0 -18
  147. package/build/utils/unread_divider_helpers.d.ts.map +0 -1
  148. package/build/utils/unread_divider_helpers.js +0 -13
  149. package/build/utils/unread_divider_helpers.js.map +0 -1
  150. package/src/__tests__/hooks/use_conversation_messages.test.tsx +0 -109
  151. package/src/__tests__/hooks/use_mark_latest_message_read.test.tsx +0 -154
  152. package/src/__tests__/utils/cache/messages_cache.test.ts +0 -54
  153. package/src/components/conversation/__tests__/message_list.test.tsx +0 -14
  154. package/src/components/conversation/message_list.tsx +0 -42
  155. package/src/components/conversation/unread_divider.tsx +0 -90
  156. package/src/components/conversations/conversations_blank_state.tsx +0 -42
  157. package/src/hooks/use_flat_list_viewability.ts +0 -50
  158. package/src/hooks/use_jump_to_bottom_action.ts +0 -75
  159. package/src/hooks/use_jump_to_unread_anchor.ts +0 -68
  160. package/src/hooks/use_jump_to_unread_gates.ts +0 -10
  161. package/src/hooks/use_scroll_tracking.ts +0 -64
  162. package/src/hooks/use_track_highest_seen_message.ts +0 -43
  163. package/src/types/jolt_events/attachment_events.ts +0 -14
  164. package/src/utils/__tests__/conversation_messages.test.ts +0 -105
  165. package/src/utils/__tests__/highest_seen_tracker.test.ts +0 -82
  166. package/src/utils/__tests__/message_viewability.test.ts +0 -168
  167. package/src/utils/__tests__/unread_divider_helpers.test.ts +0 -85
  168. package/src/utils/conversation_messages.ts +0 -37
  169. package/src/utils/highest_seen_tracker.ts +0 -42
  170. package/src/utils/message_viewability.ts +0 -49
  171. package/src/utils/unread_divider_helpers.ts +0 -25
@@ -1 +1 @@
1
- {"version":3,"file":"use_features.js","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnC,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI/C,MAAM,UAAU,WAAW;IACzB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAA;IAE5C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC;QAChC,QAAQ,EAAE,mBAAmB,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,SAAS,CAAC,IAAI;iBAClB,GAAG,CAAiC,WAAW,CAAC;iBAChD,KAAK,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAA;QACrC,CAAC;QACD,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;KACvC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;IAE1B,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,WAAwB,EAAE,EAAE,CAC3B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,EAC3E,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO;QACL,QAAQ;QACR,cAAc;KACf,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,6BAA6B,EAAE,uCAAuC;IACtE,iBAAiB,EAAE,kCAAkC;IACrD,yBAAyB,EAAE,8CAA8C;IACzE,2BAA2B,EAAE,qCAAqC;IAClE,cAAc,EAAE,wBAAwB;IACxC,wBAAwB,EAAE,kCAAkC;IAC5D,gBAAgB,EAAE,iCAAiC;CACG,CAAA;AAExD,MAAM,mBAAmB,GAAmC;IAC1D,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,CAAC;QACR,UAAU,EAAE,CAAC;KACd;CACF,CAAA","sourcesContent":["import { useSuspenseQuery } from '@tanstack/react-query'\nimport { useCallback } from 'react'\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'\n\ntype FeatureName = (typeof availableFeatures)[keyof typeof availableFeatures]\n\nexport function useFeatures() {\n const apiClient = useApiClient()\n const requestArgs = getFeaturesRequestArgs()\n\n const { data } = useSuspenseQuery({\n queryKey: getFeaturesQueryKey(),\n queryFn: () => {\n return apiClient.chat\n .get<ApiCollection<FeatureResource>>(requestArgs)\n .catch(() => stableEmptyFeatures)\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n\n const features = data.data\n\n const featureEnabled = useCallback(\n (featureName: FeatureName) =>\n features.some(feature => feature.name === featureName && feature.enabled),\n [features]\n )\n\n return {\n features,\n featureEnabled,\n }\n}\n\nexport const availableFeatures = {\n gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',\n message_reporting: 'ROLLOUT_MOBILE_message_reporting',\n granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',\n custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',\n jump_to_unread: 'ROLLOUT_jump_to_unread',\n conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',\n video_moderation: 'ROLLOUT_MOBILE_video_moderation',\n} as const satisfies Record<string, `ROLLOUT_${string}`>\n\nconst stableEmptyFeatures: ApiCollection<FeatureResource> = {\n data: [],\n links: {},\n meta: {\n count: 0,\n totalCount: 0,\n },\n}\n"]}
1
+ {"version":3,"file":"use_features.js","sourceRoot":"","sources":["../../src/hooks/use_features.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAA;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAGnC,OAAO,EAAE,sBAAsB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAA;AAC3F,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAA;AAI/C,MAAM,UAAU,WAAW;IACzB,MAAM,SAAS,GAAG,YAAY,EAAE,CAAA;IAChC,MAAM,WAAW,GAAG,sBAAsB,EAAE,CAAA;IAE5C,MAAM,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC;QAChC,QAAQ,EAAE,mBAAmB,EAAE;QAC/B,OAAO,EAAE,GAAG,EAAE;YACZ,OAAO,SAAS,CAAC,IAAI;iBAClB,GAAG,CAAiC,WAAW,CAAC;iBAChD,KAAK,CAAC,GAAG,EAAE,CAAC,mBAAmB,CAAC,CAAA;QACrC,CAAC;QACD,SAAS,EAAE,IAAI,GAAG,EAAE,GAAG,CAAC,EAAE,YAAY;KACvC,CAAC,CAAA;IAEF,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAA;IAE1B,MAAM,cAAc,GAAG,WAAW,CAChC,CAAC,WAAwB,EAAE,EAAE,CAC3B,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,EAC3E,CAAC,QAAQ,CAAC,CACX,CAAA;IAED,OAAO;QACL,QAAQ;QACR,cAAc;KACf,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,6BAA6B,EAAE,uCAAuC;IACtE,iBAAiB,EAAE,kCAAkC;IACrD,yBAAyB,EAAE,8CAA8C;IACzE,2BAA2B,EAAE,qCAAqC;IAClE,wBAAwB,EAAE,kCAAkC;CACN,CAAA;AAExD,MAAM,mBAAmB,GAAmC;IAC1D,IAAI,EAAE,EAAE;IACR,KAAK,EAAE,EAAE;IACT,IAAI,EAAE;QACJ,KAAK,EAAE,CAAC;QACR,UAAU,EAAE,CAAC;KACd;CACF,CAAA","sourcesContent":["import { useSuspenseQuery } from '@tanstack/react-query'\nimport { useCallback } from 'react'\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'\n\ntype FeatureName = (typeof availableFeatures)[keyof typeof availableFeatures]\n\nexport function useFeatures() {\n const apiClient = useApiClient()\n const requestArgs = getFeaturesRequestArgs()\n\n const { data } = useSuspenseQuery({\n queryKey: getFeaturesQueryKey(),\n queryFn: () => {\n return apiClient.chat\n .get<ApiCollection<FeatureResource>>(requestArgs)\n .catch(() => stableEmptyFeatures)\n },\n staleTime: 1000 * 60 * 5, // 5 minutes\n })\n\n const features = data.data\n\n const featureEnabled = useCallback(\n (featureName: FeatureName) =>\n features.some(feature => feature.name === featureName && feature.enabled),\n [features]\n )\n\n return {\n features,\n featureEnabled,\n }\n}\n\nexport const availableFeatures = {\n gender_specific_conversations: 'ROLLOUT_gender_specific_conversations',\n message_reporting: 'ROLLOUT_MOBILE_message_reporting',\n granular_notifications_ui: 'ROLLOUT_granular_notification_preferences_ui',\n custom_conversation_avatars: 'ROLLOUT_custom_conversation_avatars',\n conversation_safety_lock: 'ROLLOUT_conversation_safety_lock',\n} as const satisfies Record<string, `ROLLOUT_${string}`>\n\nconst stableEmptyFeatures: ApiCollection<FeatureResource> = {\n data: [],\n links: {},\n meta: {\n count: 0,\n totalCount: 0,\n },\n}\n"]}
@@ -1,7 +1,7 @@
1
1
  import { ConversationResource, MessageResource } from '../types';
2
2
  interface Props {
3
3
  conversation: ConversationResource;
4
- messages?: MessageResource[];
4
+ messages: MessageResource[];
5
5
  }
6
6
  export declare function useMarkLatestMessageRead({ conversation }: Props): void;
7
7
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"use_mark_latest_message_read.d.ts","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAKhE,UAAU,KAAK;IACb,YAAY,EAAE,oBAAoB,CAAA;IAClC,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAA;CAC7B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,QAkC/D"}
1
+ {"version":3,"file":"use_mark_latest_message_read.d.ts","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,UAAU,CAAA;AAIhE,UAAU,KAAK;IACb,YAAY,EAAE,oBAAoB,CAAA;IAClC,QAAQ,EAAE,eAAe,EAAE,CAAA;CAC5B;AAED,wBAAgB,wBAAwB,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,QAsB/D"}
@@ -1,12 +1,8 @@
1
1
  import { debounce } from 'lodash';
2
2
  import { useEffect, useMemo, useRef } from 'react';
3
- import { useConversationContext } from '../contexts/conversation_context';
4
3
  import { useAppState } from './use_app_state';
5
4
  import { useConversationsMarkRead } from './use_conversations_actions';
6
- import { useJumpToUnreadGates } from './use_jump_to_unread_gates';
7
5
  export function useMarkLatestMessageRead({ conversation }) {
8
- const { jumpToUnreadActive } = useJumpToUnreadGates();
9
- const { currentPageReplyRootId, atEndOfMessageHistory } = useConversationContext();
10
6
  const firedOnce = useRef(false);
11
7
  const { markRead } = useConversationsMarkRead({ conversation });
12
8
  const debouncedMarkRead = useMemo(() => debounce(markRead, 1000, { leading: true, trailing: true }), [markRead]);
@@ -18,21 +14,9 @@ export function useMarkLatestMessageRead({ conversation }) {
18
14
  useEffect(() => {
19
15
  if (!isActive || !shouldMarkRead)
20
16
  return;
21
- if (currentPageReplyRootId)
22
- return;
23
- if (jumpToUnreadActive && !atEndOfMessageHistory)
24
- return;
25
17
  firedOnce.current = true;
26
18
  debouncedMarkRead(true);
27
19
  // keeping unreadReactionCount in the dependency array to watch for changes
28
- }, [
29
- debouncedMarkRead,
30
- isActive,
31
- shouldMarkRead,
32
- unreadReactionCount,
33
- currentPageReplyRootId,
34
- jumpToUnreadActive,
35
- atEndOfMessageHistory,
36
- ]);
20
+ }, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount]);
37
21
  }
38
22
  //# sourceMappingURL=use_mark_latest_message_read.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"use_mark_latest_message_read.js","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAClD,OAAO,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAA;AAEzE,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAA;AAOjE,MAAM,UAAU,wBAAwB,CAAC,EAAE,YAAY,EAAS;IAC9D,MAAM,EAAE,kBAAkB,EAAE,GAAG,oBAAoB,EAAE,CAAA;IACrD,MAAM,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,GAAG,sBAAsB,EAAE,CAAA;IAClF,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,GAAG,wBAAwB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/D,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EACjE,CAAC,QAAQ,CAAC,CACX,CAAA;IACD,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,CAAA;IAC5C,MAAM,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,IAAI,CAAC,CAAA;IAEjE,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACjG,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,QAAQ,GAAG,QAAQ,KAAK,QAAQ,CAAA;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,CAAC,cAAc;YAAE,OAAM;QACxC,IAAI,sBAAsB;YAAE,OAAM;QAClC,IAAI,kBAAkB,IAAI,CAAC,qBAAqB;YAAE,OAAM;QAExD,SAAS,CAAC,OAAO,GAAG,IAAI,CAAA;QAExB,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACvB,2EAA2E;IAC7E,CAAC,EAAE;QACD,iBAAiB;QACjB,QAAQ;QACR,cAAc;QACd,mBAAmB;QACnB,sBAAsB;QACtB,kBAAkB;QAClB,qBAAqB;KACtB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import { debounce } from 'lodash'\nimport { useEffect, useMemo, useRef } from 'react'\nimport { useConversationContext } from '../contexts/conversation_context'\nimport { ConversationResource, MessageResource } from '../types'\nimport { useAppState } from './use_app_state'\nimport { useConversationsMarkRead } from './use_conversations_actions'\nimport { useJumpToUnreadGates } from './use_jump_to_unread_gates'\n\ninterface Props {\n conversation: ConversationResource\n messages?: MessageResource[]\n}\n\nexport function useMarkLatestMessageRead({ conversation }: Props) {\n const { jumpToUnreadActive } = useJumpToUnreadGates()\n const { currentPageReplyRootId, atEndOfMessageHistory } = useConversationContext()\n const firedOnce = useRef<boolean>(false)\n const { markRead } = useConversationsMarkRead({ conversation })\n const debouncedMarkRead = useMemo(\n () => debounce(markRead, 1000, { leading: true, trailing: true }),\n [markRead]\n )\n const unreadCount = conversation.unreadCount\n const unreadReactionCount = conversation.unreadReactionCount || 0\n\n const shouldMarkRead = Boolean(unreadCount >= 1 || unreadReactionCount > 0 || !firedOnce.current)\n const appState = useAppState()\n const isActive = appState === 'active'\n\n useEffect(() => {\n if (!isActive || !shouldMarkRead) return\n if (currentPageReplyRootId) return\n if (jumpToUnreadActive && !atEndOfMessageHistory) return\n\n firedOnce.current = true\n\n debouncedMarkRead(true)\n // keeping unreadReactionCount in the dependency array to watch for changes\n }, [\n debouncedMarkRead,\n isActive,\n shouldMarkRead,\n unreadReactionCount,\n currentPageReplyRootId,\n jumpToUnreadActive,\n atEndOfMessageHistory,\n ])\n}\n"]}
1
+ {"version":3,"file":"use_mark_latest_message_read.js","sourceRoot":"","sources":["../../src/hooks/use_mark_latest_message_read.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAElD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,6BAA6B,CAAA;AAOtE,MAAM,UAAU,wBAAwB,CAAC,EAAE,YAAY,EAAS;IAC9D,MAAM,SAAS,GAAG,MAAM,CAAU,KAAK,CAAC,CAAA;IACxC,MAAM,EAAE,QAAQ,EAAE,GAAG,wBAAwB,CAAC,EAAE,YAAY,EAAE,CAAC,CAAA;IAC/D,MAAM,iBAAiB,GAAG,OAAO,CAC/B,GAAG,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EACjE,CAAC,QAAQ,CAAC,CACX,CAAA;IACD,MAAM,WAAW,GAAG,YAAY,CAAC,WAAW,CAAA;IAC5C,MAAM,mBAAmB,GAAG,YAAY,CAAC,mBAAmB,IAAI,CAAC,CAAA;IAEjE,MAAM,cAAc,GAAG,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,mBAAmB,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACjG,MAAM,QAAQ,GAAG,WAAW,EAAE,CAAA;IAC9B,MAAM,QAAQ,GAAG,QAAQ,KAAK,QAAQ,CAAA;IAEtC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,QAAQ,IAAI,CAAC,cAAc;YAAE,OAAM;QAExC,SAAS,CAAC,OAAO,GAAG,IAAI,CAAA;QAExB,iBAAiB,CAAC,IAAI,CAAC,CAAA;QACvB,2EAA2E;IAC7E,CAAC,EAAE,CAAC,iBAAiB,EAAE,QAAQ,EAAE,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAA;AACxE,CAAC","sourcesContent":["import { debounce } from 'lodash'\nimport { useEffect, useMemo, useRef } from 'react'\nimport { ConversationResource, MessageResource } from '../types'\nimport { useAppState } from './use_app_state'\nimport { useConversationsMarkRead } from './use_conversations_actions'\n\ninterface Props {\n conversation: ConversationResource\n messages: MessageResource[]\n}\n\nexport function useMarkLatestMessageRead({ conversation }: Props) {\n const firedOnce = useRef<boolean>(false)\n const { markRead } = useConversationsMarkRead({ conversation })\n const debouncedMarkRead = useMemo(\n () => debounce(markRead, 1000, { leading: true, trailing: true }),\n [markRead]\n )\n const unreadCount = conversation.unreadCount\n const unreadReactionCount = conversation.unreadReactionCount || 0\n\n const shouldMarkRead = Boolean(unreadCount >= 1 || unreadReactionCount > 0 || !firedOnce.current)\n const appState = useAppState()\n const isActive = appState === 'active'\n\n useEffect(() => {\n if (!isActive || !shouldMarkRead) return\n\n firedOnce.current = true\n\n debouncedMarkRead(true)\n // keeping unreadReactionCount in the dependency array to watch for changes\n }, [debouncedMarkRead, isActive, shouldMarkRead, unreadReactionCount])\n}\n"]}
@@ -70,7 +70,6 @@ export declare const useSuspensePaginator: <T extends ResourceObject>(args: Susp
70
70
  isFetchPreviousPageError: boolean;
71
71
  isFetchingPreviousPage: boolean;
72
72
  };
73
- export declare const throwResponseError: (error: unknown) => Promise<never>;
74
73
  export type RequestQueryKey = [
75
74
  SuspenseGetOptions['url'],
76
75
  SuspenseGetOptions['data'],
@@ -1 +1 @@
1
- {"version":3,"file":"use_suspense_api.d.ts","sourceRoot":"","sources":["../../src/hooks/use_suspense_api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,EAClC,YAAY,EAGZ,uBAAuB,EACxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAA;AAGzD,OAAO,EAAE,GAAG,EAAgB,MAAM,kBAAkB,CAAA;AAEpD,UAAU,kBAAmB,SAAQ,UAAU;IAC7C,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EAAE,IAAI,IAAI,CACrF,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,EACvD,UAAU,GAAG,SAAS,CACvB,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,cAAc,GAAG,cAAc,EAAE,EACxE,MAAM,kBAAkB,EACxB,UAAU,uBAAuB,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CAiBrC,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,kCAAkC,EAClC,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,GAAG,UAAU,CACjE,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,cAAc,EAC3D,MAAM,kBAAkB,EACxB,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqChC,CAAA;AAED,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,mBAMhD,CAAA;AAED,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,CAAC,KAAK,CAAC;IACzB,kBAAkB,CAAC,MAAM,CAAC;IAC1B,kBAAkB,CAAC,SAAS,CAAC;IAC7B,kBAAkB,CAAC,KAAK,CAAC;IACzB,kBAAkB,CAAC,eAAe,CAAC;CACpC,CAAA;AACD,eAAO,MAAM,kBAAkB,GAAI,MAAM,kBAAkB,KAAG,eAM7D,CAAA"}
1
+ {"version":3,"file":"use_suspense_api.d.ts","sourceRoot":"","sources":["../../src/hooks/use_suspense_api.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,kCAAkC,EAClC,YAAY,EAGZ,uBAAuB,EACxB,MAAM,uBAAuB,CAAA;AAC9B,OAAO,EAAE,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AACrE,OAAO,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAA;AAExD,OAAO,EAAE,UAAU,EAAe,MAAM,iBAAiB,CAAA;AAGzD,OAAO,EAAE,GAAG,EAAgB,MAAM,kBAAkB,CAAA;AAEpD,UAAU,kBAAmB,SAAQ,UAAU;IAC7C,GAAG,CAAC,EAAE,GAAG,CAAA;IACT,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAC9B;AAED,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,EAAE,IAAI,IAAI,CACrF,uBAAuB,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,cAAc,CAAC,EACvD,UAAU,GAAG,SAAS,CACvB,CAAA;AAED,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,cAAc,GAAG,cAAc,EAAE,EACxE,MAAM,kBAAkB,EACxB,UAAU,uBAAuB,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;CAiBrC,CAAA;AAED,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,kCAAkC,EAClC,kBAAkB,GAAG,kBAAkB,GAAG,SAAS,GAAG,UAAU,CACjE,CAAA;AAED,eAAO,MAAM,oBAAoB,GAAI,CAAC,SAAS,cAAc,EAC3D,MAAM,kBAAkB,EACxB,OAAO,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqChC,CAAA;AAUD,MAAM,MAAM,eAAe,GAAG;IAC5B,kBAAkB,CAAC,KAAK,CAAC;IACzB,kBAAkB,CAAC,MAAM,CAAC;IAC1B,kBAAkB,CAAC,SAAS,CAAC;IAC7B,kBAAkB,CAAC,KAAK,CAAC;IACzB,kBAAkB,CAAC,eAAe,CAAC;CACpC,CAAA;AACD,eAAO,MAAM,kBAAkB,GAAI,MAAM,kBAAkB,KAAG,eAM7D,CAAA"}
@@ -44,7 +44,7 @@ export const useSuspensePaginator = (args, opts) => {
44
44
  const totalCount = query.data?.pages[0]?.meta?.totalCount || data.length;
45
45
  return { ...query, data, totalCount };
46
46
  };
47
- export const throwResponseError = (error) => {
47
+ const throwResponseError = (error) => {
48
48
  if (error instanceof Response) {
49
49
  throw new ResponseError(error);
50
50
  }
@@ -1 +1 @@
1
- {"version":3,"file":"use_suspense_api.js","sourceRoot":"","sources":["../../src/hooks/use_suspense_api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AnyUseSuspenseInfiniteQueryOptions,\n InfiniteData,\n useSuspenseInfiniteQuery,\n useSuspenseQuery,\n UseSuspenseQueryOptions,\n} from '@tanstack/react-query'\nimport { ApiCollection, ApiResource, ResourceObject } from '../types'\nimport { FailedResponse } from '../types/api_primitives'\nimport { Log } from '../utils'\nimport { GetRequest, RequestData } from '../utils/client'\nimport { ResponseError } from '../utils/response_error'\nimport { getNextPageParamFromMeta } from './paginator_meta'\nimport { App, useApiClient } from './use_api_client'\n\ninterface SuspenseGetOptions extends GetRequest {\n app?: App\n reply_root_id?: string | null\n}\n\nexport type SuspenseGetQueryOptions<T extends ResourceObject | ResourceObject[]> = Omit<\n UseSuspenseQueryOptions<ApiResource<T>, FailedResponse>,\n 'queryKey' | 'queryFn'\n>\n\nexport const useSuspenseGet = <T extends ResourceObject | ResourceObject[]>(\n args: SuspenseGetOptions,\n options?: SuspenseGetQueryOptions<T>\n) => {\n type Resource = ApiResource<T>\n const apiClient = useApiClient()\n\n const { data, ...query } = useSuspenseQuery<Resource, FailedResponse>({\n queryKey: getRequestQueryKey(args),\n queryFn: ({ queryKey }) => {\n const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey\n return apiClient[app]\n .get({ url, data: d, headers })\n .catch(throwResponseError) as Promise<Resource>\n },\n ...options,\n })\n\n return { ...data, ...query }\n}\n\nexport type SuspensePaginatorOptions = Omit<\n AnyUseSuspenseInfiniteQueryOptions,\n 'getNextPageParam' | 'initialPageParam' | 'queryFn' | 'queryKey'\n>\n\nexport const useSuspensePaginator = <T extends ResourceObject>(\n args: SuspenseGetOptions,\n opts?: SuspensePaginatorOptions\n) => {\n const apiClient = useApiClient()\n const query = useSuspenseInfiniteQuery<\n ApiCollection<T>,\n Response,\n InfiniteData<ApiCollection<T>>,\n any,\n Partial<RequestData> | undefined\n >({\n queryKey: getRequestQueryKey(args),\n queryFn: ({ pageParam }) => {\n Log.info('useSuspenseGet', { pageParam })\n\n const pageParmWhere = pageParam?.where || {}\n const argsWhere = args.data.where || {}\n const where = { ...argsWhere, ...pageParmWhere }\n const app = args.app || 'chat'\n const offset = pageParam?.offset || args.data.offset\n const data = { ...args.data, where, offset }\n\n return apiClient[app]\n .get<ApiCollection<T>>({\n url: args.url,\n data,\n })\n .catch(throwResponseError)\n },\n initialPageParam: {} as Partial<RequestData>,\n getNextPageParam: lastPage => getNextPageParamFromMeta(lastPage.meta?.next),\n ...(opts || {}),\n })\n\n const data: T[] = query.data?.pages.flatMap(page => page.data) || []\n const totalCount = query.data?.pages[0]?.meta?.totalCount || data.length\n\n return { ...query, data, totalCount }\n}\n\nexport const throwResponseError = (error: unknown) => {\n if (error instanceof Response) {\n throw new ResponseError(error as FailedResponse)\n }\n\n return Promise.reject(error)\n}\n\nexport type RequestQueryKey = [\n SuspenseGetOptions['url'],\n SuspenseGetOptions['data'],\n SuspenseGetOptions['headers'],\n SuspenseGetOptions['app'],\n SuspenseGetOptions['reply_root_id'],\n]\nexport const getRequestQueryKey = (args: SuspenseGetOptions): RequestQueryKey => [\n args.url,\n args.data,\n args.headers,\n args.app || 'chat',\n args.reply_root_id,\n]\n"]}
1
+ {"version":3,"file":"use_suspense_api.js","sourceRoot":"","sources":["../../src/hooks/use_suspense_api.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n AnyUseSuspenseInfiniteQueryOptions,\n InfiniteData,\n useSuspenseInfiniteQuery,\n useSuspenseQuery,\n UseSuspenseQueryOptions,\n} from '@tanstack/react-query'\nimport { ApiCollection, ApiResource, ResourceObject } from '../types'\nimport { FailedResponse } from '../types/api_primitives'\nimport { Log } from '../utils'\nimport { GetRequest, RequestData } from '../utils/client'\nimport { ResponseError } from '../utils/response_error'\nimport { getNextPageParamFromMeta } from './paginator_meta'\nimport { App, useApiClient } from './use_api_client'\n\ninterface SuspenseGetOptions extends GetRequest {\n app?: App\n reply_root_id?: string | null\n}\n\nexport type SuspenseGetQueryOptions<T extends ResourceObject | ResourceObject[]> = Omit<\n UseSuspenseQueryOptions<ApiResource<T>, FailedResponse>,\n 'queryKey' | 'queryFn'\n>\n\nexport const useSuspenseGet = <T extends ResourceObject | ResourceObject[]>(\n args: SuspenseGetOptions,\n options?: SuspenseGetQueryOptions<T>\n) => {\n type Resource = ApiResource<T>\n const apiClient = useApiClient()\n\n const { data, ...query } = useSuspenseQuery<Resource, FailedResponse>({\n queryKey: getRequestQueryKey(args),\n queryFn: ({ queryKey }) => {\n const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey\n return apiClient[app]\n .get({ url, data: d, headers })\n .catch(throwResponseError) as Promise<Resource>\n },\n ...options,\n })\n\n return { ...data, ...query }\n}\n\nexport type SuspensePaginatorOptions = Omit<\n AnyUseSuspenseInfiniteQueryOptions,\n 'getNextPageParam' | 'initialPageParam' | 'queryFn' | 'queryKey'\n>\n\nexport const useSuspensePaginator = <T extends ResourceObject>(\n args: SuspenseGetOptions,\n opts?: SuspensePaginatorOptions\n) => {\n const apiClient = useApiClient()\n const query = useSuspenseInfiniteQuery<\n ApiCollection<T>,\n Response,\n InfiniteData<ApiCollection<T>>,\n any,\n Partial<RequestData> | undefined\n >({\n queryKey: getRequestQueryKey(args),\n queryFn: ({ pageParam }) => {\n Log.info('useSuspenseGet', { pageParam })\n\n const pageParmWhere = pageParam?.where || {}\n const argsWhere = args.data.where || {}\n const where = { ...argsWhere, ...pageParmWhere }\n const app = args.app || 'chat'\n const offset = pageParam?.offset || args.data.offset\n const data = { ...args.data, where, offset }\n\n return apiClient[app]\n .get<ApiCollection<T>>({\n url: args.url,\n data,\n })\n .catch(throwResponseError)\n },\n initialPageParam: {} as Partial<RequestData>,\n getNextPageParam: lastPage => getNextPageParamFromMeta(lastPage.meta?.next),\n ...(opts || {}),\n })\n\n const data: T[] = query.data?.pages.flatMap(page => page.data) || []\n const totalCount = query.data?.pages[0]?.meta?.totalCount || data.length\n\n return { ...query, data, totalCount }\n}\n\nconst throwResponseError = (error: unknown) => {\n if (error instanceof Response) {\n throw new ResponseError(error as FailedResponse)\n }\n\n return Promise.reject(error)\n}\n\nexport type RequestQueryKey = [\n SuspenseGetOptions['url'],\n SuspenseGetOptions['data'],\n SuspenseGetOptions['headers'],\n SuspenseGetOptions['app'],\n SuspenseGetOptions['reply_root_id'],\n]\nexport const getRequestQueryKey = (args: SuspenseGetOptions): RequestQueryKey => [\n args.url,\n args.data,\n args.headers,\n args.app || 'chat',\n args.reply_root_id,\n]\n"]}
@@ -6,10 +6,6 @@ export interface FileForUploadClient {
6
6
  }
7
7
  export declare const useUploadClient: () => UploadClient;
8
8
  declare class UploadClient extends Client {
9
- private videoModerationEnabled;
10
- constructor({ videoModerationEnabled, ...rest }: ConstructorParameters<typeof Client>[0] & {
11
- videoModerationEnabled: boolean;
12
- });
13
9
  uploadFile(file: FileForUploadClient): Promise<UploadedResource>;
14
10
  }
15
11
  interface UploadedResource {
@@ -1 +1 @@
1
- {"version":3,"file":"use_upload_client.d.ts","sourceRoot":"","sources":["../../src/hooks/use_upload_client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAIjC,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,eAAO,MAAM,eAAe,oBAoB3B,CAAA;AAED,cAAM,YAAa,SAAQ,MAAM;IAC/B,OAAO,CAAC,sBAAsB,CAAS;gBAE3B,EACV,sBAAsB,EACtB,GAAG,IAAI,EACR,EAAE,qBAAqB,CAAC,OAAO,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,sBAAsB,EAAE,OAAO,CAAA;KAAE;IAK1E,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAqCvE;AAED,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE;QACV,eAAe,EAAE,MAAM,CAAA;QACvB,SAAS,EAAE,MAAM,CAAA;QACjB,GAAG,EAAE,MAAM,CAAA;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,MAAM,CAAA;QACZ,YAAY,EAAE,MAAM,CAAA;QACpB,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF"}
1
+ {"version":3,"file":"use_upload_client.d.ts","sourceRoot":"","sources":["../../src/hooks/use_upload_client.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AAGjC,MAAM,WAAW,mBAAmB;IAClC,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;CACb;AAED,eAAO,MAAM,eAAe,oBAiB3B,CAAA;AAED,cAAM,YAAa,SAAQ,MAAM;IACzB,UAAU,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,gBAAgB,CAAC;CAiCvE;AAED,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,EAAE;QACV,eAAe,EAAE,MAAM,CAAA;QACvB,SAAS,EAAE,MAAM,CAAA;QACjB,GAAG,EAAE,MAAM,CAAA;QACX,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAA;QAClB,SAAS,EAAE,MAAM,CAAA;QACjB,IAAI,EAAE,MAAM,CAAA;QACZ,YAAY,EAAE,MAAM,CAAA;QACpB,SAAS,EAAE,MAAM,CAAA;QACjB,QAAQ,EAAE,MAAM,CAAA;KACjB,CAAA;CACF"}
@@ -2,27 +2,18 @@ import { useContext, useMemo } from 'react';
2
2
  import { ChatContext } from '../contexts/chat_context';
3
3
  import { Client } from '../utils';
4
4
  import { UploadUri } from '../utils/upload_uri';
5
- import { availableFeatures, useFeatures } from './use_features';
6
5
  export const useUploadClient = () => {
7
6
  const { session, onUnauthorizedResponse } = useContext(ChatContext);
8
- const { featureEnabled } = useFeatures();
9
- const videoModerationEnabled = featureEnabled(availableFeatures.video_moderation);
10
7
  const uri = useMemo(() => new UploadUri({ session }), [session]);
11
8
  const api = useMemo(() => new UploadClient({
12
9
  version: '2025-05-16', // not really needed, but required by the Client constructor
13
10
  root: uri.baseUrl,
14
11
  defaultHeaders: uri.headers,
15
12
  onUnauthorizedResponse,
16
- videoModerationEnabled,
17
- }), [uri, onUnauthorizedResponse, videoModerationEnabled]);
13
+ }), [uri, onUnauthorizedResponse]);
18
14
  return api;
19
15
  };
20
16
  class UploadClient extends Client {
21
- videoModerationEnabled;
22
- constructor({ videoModerationEnabled, ...rest }) {
23
- super(rest);
24
- this.videoModerationEnabled = videoModerationEnabled;
25
- }
26
17
  async uploadFile(file) {
27
18
  const formData = new FormData();
28
19
  formData.append('file', {
@@ -32,9 +23,6 @@ class UploadClient extends Client {
32
23
  });
33
24
  const headers = { ...this.headers };
34
25
  delete headers['Content-Type'];
35
- if (this.videoModerationEnabled && file.type.startsWith('video/')) {
36
- headers['X-PCO-Moderate-Video'] = 'true';
37
- }
38
26
  const response = await fetch(`${this.root}/v2/files`, {
39
27
  method: 'POST',
40
28
  headers,
@@ -1 +1 @@
1
- {"version":3,"file":"use_upload_client.js","sourceRoot":"","sources":["../../src/hooks/use_upload_client.ts"],"names":[],"mappings":"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","sourcesContent":["import { useContext, useMemo } from 'react'\nimport { ChatContext } from '../contexts/chat_context'\nimport { Client } from '../utils'\nimport { UploadUri } from '../utils/upload_uri'\nimport { availableFeatures, useFeatures } from './use_features'\n\nexport interface FileForUploadClient {\n uri: string\n name: string\n type: string // Should be a MIME type\n}\n\nexport const useUploadClient = () => {\n const { session, onUnauthorizedResponse } = useContext(ChatContext)\n const { featureEnabled } = useFeatures()\n const videoModerationEnabled = featureEnabled(availableFeatures.video_moderation)\n\n const uri = useMemo(() => new UploadUri({ session }), [session])\n\n const api = useMemo(\n () =>\n new UploadClient({\n version: '2025-05-16', // not really needed, but required by the Client constructor\n root: uri.baseUrl,\n defaultHeaders: uri.headers,\n onUnauthorizedResponse,\n videoModerationEnabled,\n }),\n [uri, onUnauthorizedResponse, videoModerationEnabled]\n )\n\n return api\n}\n\nclass UploadClient extends Client {\n private videoModerationEnabled: boolean\n\n constructor({\n videoModerationEnabled,\n ...rest\n }: ConstructorParameters<typeof Client>[0] & { videoModerationEnabled: boolean }) {\n super(rest)\n this.videoModerationEnabled = videoModerationEnabled\n }\n\n async uploadFile(file: FileForUploadClient): Promise<UploadedResource> {\n const formData = new FormData()\n formData.append('file', {\n uri: file.uri,\n name: file.name,\n type: file.type,\n })\n\n const headers: RequestInit['headers'] = { ...this.headers }\n delete headers['Content-Type']\n\n if (this.videoModerationEnabled && file.type.startsWith('video/')) {\n headers['X-PCO-Moderate-Video'] = 'true'\n }\n\n const response = await fetch(`${this.root}/v2/files`, {\n method: 'POST',\n headers,\n body: formData,\n })\n\n if (response.status === 403) {\n const errorBody = await response.json().catch(() => null)\n if (errorBody?.detail === 'Image was flagged') {\n return Promise.reject({ code: 'image_flagged' })\n }\n return this.handleNotOk(response)\n }\n\n if (!response.ok) {\n return this.handleNotOk(response)\n }\n\n const jsonResponse = await response.json()\n\n return jsonResponse.data[0]\n }\n}\n\ninterface UploadedResource {\n id: string\n type: string\n attributes: {\n organization_id: string\n person_id: string\n md5: string\n created_at: string\n expires_at: string\n source_ip: string\n name: string\n content_type: string\n file_size: number\n location: string\n }\n}\n"]}
1
+ {"version":3,"file":"use_upload_client.js","sourceRoot":"","sources":["../../src/hooks/use_upload_client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,OAAO,CAAA;AAC3C,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAA;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAQ/C,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE;IAClC,MAAM,EAAE,OAAO,EAAE,sBAAsB,EAAE,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IAEnE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAA;IAEhE,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CACH,IAAI,YAAY,CAAC;QACf,OAAO,EAAE,YAAY,EAAE,4DAA4D;QACnF,IAAI,EAAE,GAAG,CAAC,OAAO;QACjB,cAAc,EAAE,GAAG,CAAC,OAAO;QAC3B,sBAAsB;KACvB,CAAC,EACJ,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAC9B,CAAA;IAED,OAAO,GAAG,CAAA;AACZ,CAAC,CAAA;AAED,MAAM,YAAa,SAAQ,MAAM;IAC/B,KAAK,CAAC,UAAU,CAAC,IAAyB;QACxC,MAAM,QAAQ,GAAG,IAAI,QAAQ,EAAE,CAAA;QAC/B,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;YACtB,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC,CAAA;QAEF,MAAM,OAAO,GAA2B,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAA;QAC3D,OAAO,OAAO,CAAC,cAAc,CAAC,CAAA;QAE9B,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,IAAI,WAAW,EAAE;YACpD,MAAM,EAAE,MAAM;YACd,OAAO;YACP,IAAI,EAAE,QAAQ;SACf,CAAC,CAAA;QAEF,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAA;YACzD,IAAI,SAAS,EAAE,MAAM,KAAK,mBAAmB,EAAE,CAAC;gBAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,eAAe,EAAE,CAAC,CAAA;YAClD,CAAC;YACD,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;QACnC,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;QACnC,CAAC;QAED,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;QAE1C,OAAO,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAC7B,CAAC;CACF","sourcesContent":["import { useContext, useMemo } from 'react'\nimport { ChatContext } from '../contexts/chat_context'\nimport { Client } from '../utils'\nimport { UploadUri } from '../utils/upload_uri'\n\nexport interface FileForUploadClient {\n uri: string\n name: string\n type: string // Should be a MIME type\n}\n\nexport const useUploadClient = () => {\n const { session, onUnauthorizedResponse } = useContext(ChatContext)\n\n const uri = useMemo(() => new UploadUri({ session }), [session])\n\n const api = useMemo(\n () =>\n new UploadClient({\n version: '2025-05-16', // not really needed, but required by the Client constructor\n root: uri.baseUrl,\n defaultHeaders: uri.headers,\n onUnauthorizedResponse,\n }),\n [uri, onUnauthorizedResponse]\n )\n\n return api\n}\n\nclass UploadClient extends Client {\n async uploadFile(file: FileForUploadClient): Promise<UploadedResource> {\n const formData = new FormData()\n formData.append('file', {\n uri: file.uri,\n name: file.name,\n type: file.type,\n })\n\n const headers: RequestInit['headers'] = { ...this.headers }\n delete headers['Content-Type']\n\n const response = await fetch(`${this.root}/v2/files`, {\n method: 'POST',\n headers,\n body: formData,\n })\n\n if (response.status === 403) {\n const errorBody = await response.json().catch(() => null)\n if (errorBody?.detail === 'Image was flagged') {\n return Promise.reject({ code: 'image_flagged' })\n }\n return this.handleNotOk(response)\n }\n\n if (!response.ok) {\n return this.handleNotOk(response)\n }\n\n const jsonResponse = await response.json()\n\n return jsonResponse.data[0]\n }\n}\n\ninterface UploadedResource {\n id: string\n type: string\n attributes: {\n organization_id: string\n person_id: string\n md5: string\n created_at: string\n expires_at: string\n source_ip: string\n name: string\n content_type: string\n file_size: number\n location: string\n }\n}\n"]}
package/build/jest.js CHANGED
@@ -16,7 +16,7 @@
16
16
  */
17
17
  export const jestTransformPackages = [
18
18
  '@planningcenter/chat-react-native',
19
- '@planningcenter/emoji-keyboard',
20
19
  '@fortawesome',
20
+ 'rn-emoji-keyboard',
21
21
  ];
22
22
  //# sourceMappingURL=jest.js.map
package/build/jest.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"jest.js","sourceRoot":"","sources":["../src/jest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,mCAAmC;IACnC,gCAAgC;IAChC,cAAc;CACf,CAAA","sourcesContent":["/**\n * Jest configuration helpers for consuming apps.\n *\n * Usage in jest.config.js:\n *\n * const { jestTransformPackages } = require('@planningcenter/chat-react-native/jest')\n *\n * const ignorePatterns = [\n * ...yourPatterns,\n * ...jestTransformPackages,\n * ].join('|')\n *\n * module.exports = {\n * transformIgnorePatterns: [`node_modules/(?!${ignorePatterns})`],\n * }\n */\nexport const jestTransformPackages = [\n '@planningcenter/chat-react-native',\n '@planningcenter/emoji-keyboard',\n '@fortawesome',\n]\n"]}
1
+ {"version":3,"file":"jest.js","sourceRoot":"","sources":["../src/jest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,mCAAmC;IACnC,cAAc;IACd,mBAAmB;CACpB,CAAA","sourcesContent":["/**\n * Jest configuration helpers for consuming apps.\n *\n * Usage in jest.config.js:\n *\n * const { jestTransformPackages } = require('@planningcenter/chat-react-native/jest')\n *\n * const ignorePatterns = [\n * ...yourPatterns,\n * ...jestTransformPackages,\n * ].join('|')\n *\n * module.exports = {\n * transformIgnorePatterns: [`node_modules/(?!${ignorePatterns})`],\n * }\n */\nexport const jestTransformPackages = [\n '@planningcenter/chat-react-native',\n '@fortawesome',\n 'rn-emoji-keyboard',\n]\n"]}
@@ -21,7 +21,7 @@ export function AgeCheckUnderageScreen({ contactEmail } = {}) {
21
21
 
22
22
  <View style={styles.content}>
23
23
  <Heading variant="h3" style={styles.baseText}>
24
- Chat is only available for users 13 and older.
24
+ Your age does not meet the minimum safety requirements to use chat.
25
25
  </Heading>
26
26
  <Text variant="tertiary" style={styles.baseText}>
27
27
  If you submitted the wrong birthdate by accident,{` `}
@@ -1 +1 @@
1
- {"version":3,"file":"age_check_underage_screen.js","sourceRoot":"","sources":["../../../src/screens/age_check/age_check_underage_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAOtC,MAAM,UAAU,sBAAsB,CAAC,EAAE,YAAY,KAAkC,EAAE;IACvF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAG,QAAQ,EAA+C,CAAA;IAErE,MAAM,KAAK,GAAG,YAAY,IAAI,KAAK,EAAE,MAAM,EAAE,YAAY,CAAA;IAEzD,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,OAAO,CAAC,OAAO,CAAC,UAAU,KAAK,EAAE,CAAC,CAAA;IACpC,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,OAAO,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAA;IACzD,CAAC,CAAA;IAED,OAAO,CACL,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5E;MAAA,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAEtE;;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAC1B;QAAA,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3C;;QACF,EAAE,OAAO,CACT;QAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC9C;2DAAiD,CAAC,GAAG,CACrD;UAAA,CAAC,KAAK,CAAC,CAAC,CAAC,CACP,CAAC,gBAAgB,CACf,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAC7B,iBAAiB,CAAC,MAAM,CACxB,iBAAiB,CAAC,yDAAyD,CAC3E,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAEvB;;YACF,EAAE,gBAAgB,CAAC,CACpB,CAAC,CAAC,CAAC,CACF,EAAE,wCAAwC,GAAG,CAC9C,CACD;UAAA,CAAC,GAAG,CACJ;;QACF,EAAE,IAAI,CACN;QAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC9C;wCAA8B,CAAC,GAAG,CAClC;UAAA,CAAC,gBAAgB,CACf,OAAO,CAAC,CAAC,SAAS,CAAC,CACnB,iBAAiB,CAAC,MAAM,CACxB,iBAAiB,CAAC,mCAAmC,CACrD,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAEvB;;UACF,EAAE,gBAAgB,CAClB;;QACF,EAAE,IAAI,CACR;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,UAAU,CAAC,CACd,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE;YACV,IAAI,EAAE,CAAC;SACR;QACD,SAAS,EAAE;YACT,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,GAAG,EAAE,EAAE;YACP,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,MAAM;SAClB;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC,wBAAwB;SACvC;QACD,OAAO,EAAE;YACP,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,QAAQ,EAAE,GAAG;SACd;QACD,QAAQ,EAAE;YACR,SAAS,EAAE,QAAQ;YACnB,KAAK,EAAE,MAAM,CAAC,yBAAyB;SACxC;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,EAAE;SACb;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useRoute, RouteProp } from '@react-navigation/native'\nimport React from 'react'\nimport { Linking, StyleSheet, View, ScrollView } from 'react-native'\nimport { Heading } from '../../components'\nimport { Icon, Text, TextInlineButton } from '../../components/display'\nimport { useTheme } from '../../hooks'\nimport type { AgeCheckParams } from './screen_props'\n\nexport interface AgeCheckUnderageScreenProps {\n contactEmail?: string\n}\n\nexport function AgeCheckUnderageScreen({ contactEmail }: AgeCheckUnderageScreenProps = {}) {\n const styles = useStyles()\n const route = useRoute<RouteProp<AgeCheckParams, 'UnderagePerson'>>()\n\n const email = contactEmail ?? route?.params?.contactEmail\n\n const openChurchAdminHelp = () => {\n if (!email) return\n Linking.openURL(`mailto:${email}`)\n }\n\n const openTerms = () => {\n Linking.openURL('https://www.planningcenter.com/terms')\n }\n\n return (\n <ScrollView style={styles.scrollView} contentContainerStyle={styles.container}>\n <Icon name=\"general.outlinedTextMessage\" size={32} style={styles.icon} />\n\n <View style={styles.content}>\n <Heading variant=\"h3\" style={styles.baseText}>\n Chat is only available for users 13 and older.\n </Heading>\n <Text variant=\"tertiary\" style={styles.baseText}>\n If you submitted the wrong birthdate by accident,{` `}\n {email ? (\n <TextInlineButton\n onPress={openChurchAdminHelp}\n accessibilityRole=\"link\"\n accessibilityHint=\"Opens email client to contact your church administrator\"\n style={styles.linkText}\n >\n please contact your church administrator\n </TextInlineButton>\n ) : (\n <>please contact your church administrator</>\n )}\n {` `}\n to update your profile.\n </Text>\n <Text variant=\"tertiary\" style={styles.baseText}>\n For more information, view our{` `}\n <TextInlineButton\n onPress={openTerms}\n accessibilityRole=\"link\"\n accessibilityHint=\"Opens terms of service in browser\"\n style={styles.linkText}\n >\n terms of service\n </TextInlineButton>\n .\n </Text>\n </View>\n </ScrollView>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n scrollView: {\n flex: 1,\n },\n container: {\n alignItems: 'center',\n justifyContent: 'center',\n gap: 16,\n padding: 16,\n minHeight: '100%',\n },\n icon: {\n color: colors.iconColorDefaultDisabled,\n },\n content: {\n alignItems: 'center',\n gap: 8,\n maxWidth: 250,\n },\n baseText: {\n textAlign: 'center',\n color: colors.textColorDefaultSecondary,\n },\n linkText: {\n fontSize: 14,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"age_check_underage_screen.js","sourceRoot":"","sources":["../../../src/screens/age_check/age_check_underage_screen.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAa,MAAM,0BAA0B,CAAA;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC1C,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AACvE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAOtC,MAAM,UAAU,sBAAsB,CAAC,EAAE,YAAY,KAAkC,EAAE;IACvF,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,KAAK,GAAG,QAAQ,EAA+C,CAAA;IAErE,MAAM,KAAK,GAAG,YAAY,IAAI,KAAK,EAAE,MAAM,EAAE,YAAY,CAAA;IAEzD,MAAM,mBAAmB,GAAG,GAAG,EAAE;QAC/B,IAAI,CAAC,KAAK;YAAE,OAAM;QAClB,OAAO,CAAC,OAAO,CAAC,UAAU,KAAK,EAAE,CAAC,CAAA;IACpC,CAAC,CAAA;IAED,MAAM,SAAS,GAAG,GAAG,EAAE;QACrB,OAAO,CAAC,OAAO,CAAC,sCAAsC,CAAC,CAAA;IACzD,CAAC,CAAA;IAED,OAAO,CACL,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,qBAAqB,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5E;MAAA,CAAC,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAEtE;;MAAA,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAC1B;QAAA,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC3C;;QACF,EAAE,OAAO,CACT;QAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC9C;2DAAiD,CAAC,GAAG,CACrD;UAAA,CAAC,KAAK,CAAC,CAAC,CAAC,CACP,CAAC,gBAAgB,CACf,OAAO,CAAC,CAAC,mBAAmB,CAAC,CAC7B,iBAAiB,CAAC,MAAM,CACxB,iBAAiB,CAAC,yDAAyD,CAC3E,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAEvB;;YACF,EAAE,gBAAgB,CAAC,CACpB,CAAC,CAAC,CAAC,CACF,EAAE,wCAAwC,GAAG,CAC9C,CACD;UAAA,CAAC,GAAG,CACJ;;QACF,EAAE,IAAI,CACN;QAAA,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAC9C;wCAA8B,CAAC,GAAG,CAClC;UAAA,CAAC,gBAAgB,CACf,OAAO,CAAC,CAAC,SAAS,CAAC,CACnB,iBAAiB,CAAC,MAAM,CACxB,iBAAiB,CAAC,mCAAmC,CACrD,KAAK,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAEvB;;UACF,EAAE,gBAAgB,CAClB;;QACF,EAAE,IAAI,CACR;MAAA,EAAE,IAAI,CACR;IAAA,EAAE,UAAU,CAAC,CACd,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAC7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,UAAU,EAAE;YACV,IAAI,EAAE,CAAC;SACR;QACD,SAAS,EAAE;YACT,UAAU,EAAE,QAAQ;YACpB,cAAc,EAAE,QAAQ;YACxB,GAAG,EAAE,EAAE;YACP,OAAO,EAAE,EAAE;YACX,SAAS,EAAE,MAAM;SAClB;QACD,IAAI,EAAE;YACJ,KAAK,EAAE,MAAM,CAAC,wBAAwB;SACvC;QACD,OAAO,EAAE;YACP,UAAU,EAAE,QAAQ;YACpB,GAAG,EAAE,CAAC;YACN,QAAQ,EAAE,GAAG;SACd;QACD,QAAQ,EAAE;YACR,SAAS,EAAE,QAAQ;YACnB,KAAK,EAAE,MAAM,CAAC,yBAAyB;SACxC;QACD,QAAQ,EAAE;YACR,QAAQ,EAAE,EAAE;SACb;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { useRoute, RouteProp } from '@react-navigation/native'\nimport React from 'react'\nimport { Linking, StyleSheet, View, ScrollView } from 'react-native'\nimport { Heading } from '../../components'\nimport { Icon, Text, TextInlineButton } from '../../components/display'\nimport { useTheme } from '../../hooks'\nimport type { AgeCheckParams } from './screen_props'\n\nexport interface AgeCheckUnderageScreenProps {\n contactEmail?: string\n}\n\nexport function AgeCheckUnderageScreen({ contactEmail }: AgeCheckUnderageScreenProps = {}) {\n const styles = useStyles()\n const route = useRoute<RouteProp<AgeCheckParams, 'UnderagePerson'>>()\n\n const email = contactEmail ?? route?.params?.contactEmail\n\n const openChurchAdminHelp = () => {\n if (!email) return\n Linking.openURL(`mailto:${email}`)\n }\n\n const openTerms = () => {\n Linking.openURL('https://www.planningcenter.com/terms')\n }\n\n return (\n <ScrollView style={styles.scrollView} contentContainerStyle={styles.container}>\n <Icon name=\"general.outlinedTextMessage\" size={32} style={styles.icon} />\n\n <View style={styles.content}>\n <Heading variant=\"h3\" style={styles.baseText}>\n Your age does not meet the minimum safety requirements to use chat.\n </Heading>\n <Text variant=\"tertiary\" style={styles.baseText}>\n If you submitted the wrong birthdate by accident,{` `}\n {email ? (\n <TextInlineButton\n onPress={openChurchAdminHelp}\n accessibilityRole=\"link\"\n accessibilityHint=\"Opens email client to contact your church administrator\"\n style={styles.linkText}\n >\n please contact your church administrator\n </TextInlineButton>\n ) : (\n <>please contact your church administrator</>\n )}\n {` `}\n to update your profile.\n </Text>\n <Text variant=\"tertiary\" style={styles.baseText}>\n For more information, view our{` `}\n <TextInlineButton\n onPress={openTerms}\n accessibilityRole=\"link\"\n accessibilityHint=\"Opens terms of service in browser\"\n style={styles.linkText}\n >\n terms of service\n </TextInlineButton>\n .\n </Text>\n </View>\n </ScrollView>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n return StyleSheet.create({\n scrollView: {\n flex: 1,\n },\n container: {\n alignItems: 'center',\n justifyContent: 'center',\n gap: 16,\n padding: 16,\n minHeight: '100%',\n },\n icon: {\n color: colors.iconColorDefaultDisabled,\n },\n content: {\n alignItems: 'center',\n gap: 8,\n maxWidth: 250,\n },\n baseText: {\n textAlign: 'center',\n color: colors.textColorDefaultSecondary,\n },\n linkText: {\n fontSize: 14,\n },\n })\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"emoji_tab.d.ts","sourceRoot":"","sources":["../../../src/screens/avatar_picker/emoji_tab.tsx"],"names":[],"mappings":"AACA,OAAO,KAAsB,MAAM,OAAO,CAAA;AAW1C,UAAU,aAAa;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC;AAED,wBAAgB,QAAQ,CAAC,EAAE,aAAa,EAAE,EAAE,aAAa,qBAwDxD"}
1
+ {"version":3,"file":"emoji_tab.d.ts","sourceRoot":"","sources":["../../../src/screens/avatar_picker/emoji_tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsB,MAAM,OAAO,CAAA;AAgB1C,UAAU,aAAa;IACrB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACvC;AAED,wBAAgB,QAAQ,CAAC,EAAE,aAAa,EAAE,EAAE,aAAa,qBAwDxD"}
@@ -1,9 +1,13 @@
1
- import { EmojiKeyboard, emojisByCategory } from '@planningcenter/emoji-keyboard';
2
1
  import React, { useCallback } from 'react';
3
2
  import { StyleSheet, View } from 'react-native';
3
+ import { EmojiKeyboard } from 'rn-emoji-keyboard';
4
+ // rn-emoji-keyboard exposes no public exclusion API, so we reach into its
5
+ // internal src/ tree for the emoji JSON. Version is pinned in package.json
6
+ // — verify this path still resolves before bumping rn-emoji-keyboard.
7
+ import emojiData from 'rn-emoji-keyboard/src/assets/emojis.json';
4
8
  import { useTheme } from '../../hooks';
5
9
  const BLOCKED_EMOJIS = new Set(['🖕']);
6
- const filteredEmojis = emojisByCategory.map(category => ({
10
+ const filteredEmojis = emojiData.map(category => ({
7
11
  ...category,
8
12
  data: category.data.filter(e => !BLOCKED_EMOJIS.has(e.emoji)),
9
13
  }));
@@ -1 +1 @@
1
- {"version":3,"file":"emoji_tab.js","sourceRoot":"","sources":["../../../src/screens/avatar_picker/emoji_tab.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAkB,MAAM,gCAAgC,CAAA;AAChG,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;AAEtC,MAAM,cAAc,GAAG,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACvD,GAAG,QAAQ;IACX,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAC9D,CAAC,CAAC,CAAA;AAMH,MAAM,UAAU,QAAQ,CAAC,EAAE,aAAa,EAAiB;IACvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,WAAsB,EAAE,EAAE;QACzB,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAA;IAED,MAAM,UAAU,GAAG;QACjB,SAAS,EAAE,MAAM,CAAC,2BAA2B;QAC7C,MAAM,EAAE,MAAM,CAAC,yBAAyB;QACxC,IAAI,EAAE,MAAM,CAAC,mBAAmB;QAChC,kBAAkB,EAAE,MAAM,CAAC,mBAAmB;QAC9C,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC,yBAAyB;YACtC,UAAU,EAAE,MAAM,CAAC,WAAW;YAC9B,SAAS,EAAE,MAAM,CAAC,2BAA2B;YAC7C,eAAe,EAAE,MAAM,CAAC,mBAAmB;SAC5C;QACD,MAAM,EAAE;YACN,UAAU,EAAE,MAAM,CAAC,mBAAmB;YACtC,IAAI,EAAE,MAAM,CAAC,uBAAuB;YACpC,WAAW,EAAE,MAAM,CAAC,yBAAyB;YAC7C,IAAI,EAAE,MAAM,CAAC,yBAAyB;SACvC;QACD,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC,mBAAmB;SACrC;KACF,CAAA;IAED,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,aAAa,CACZ,gBAAgB,CAAC,KAAK,CACtB,gBAAgB,CAAC,CAAC,cAAc,CAAC,CACjC,eAAe,CAAC,CAAC,mBAAmB,CAAC,CACrC,eAAe,CACf,kBAAkB,CAClB,KAAK,CAAC,CAAC,UAAU,CAAC,CAClB,MAAM,CAAC,CAAC;YACN,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE;YAC9B,QAAQ,EAAE;gBACR,SAAS,EAAE;oBACT,YAAY,EAAE,CAAC;oBACf,SAAS,EAAE,CAAC,CAAC;oBACb,iBAAiB,EAAE,CAAC;oBACpB,iBAAiB,EAAE,MAAM,CAAC,qBAAqB;iBAChD;aACF;SACF,CAAC,EAEN;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,eAAe,EAAE,MAAM,CAAC,2BAA2B;SACpD;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import { EmojiKeyboard, emojisByCategory, type EmojiType } from '@planningcenter/emoji-keyboard'\nimport React, { useCallback } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { useTheme } from '../../hooks'\n\nconst BLOCKED_EMOJIS = new Set(['🖕'])\n\nconst filteredEmojis = emojisByCategory.map(category => ({\n ...category,\n data: category.data.filter(e => !BLOCKED_EMOJIS.has(e.emoji)),\n}))\n\ninterface EmojiTabProps {\n onEmojiSelect: (emoji: string) => void\n}\n\nexport function EmojiTab({ onEmojiSelect }: EmojiTabProps) {\n const styles = useStyles()\n const { colors } = useTheme()\n\n const handleEmojiSelected = useCallback(\n (emojiObject: EmojiType) => {\n onEmojiSelect(emojiObject.emoji)\n },\n [onEmojiSelect]\n )\n\n const emojiTheme = {\n container: colors.fillColorNeutral100Inverted,\n header: colors.textColorDefaultSecondary,\n knob: colors.fillColorNeutral040,\n skinTonesContainer: colors.fillColorNeutral060,\n category: {\n icon: colors.textColorDefaultSecondary,\n iconActive: colors.interaction,\n container: colors.fillColorNeutral100Inverted,\n containerActive: colors.fillColorNeutral080,\n },\n search: {\n background: colors.fillColorNeutral080,\n text: colors.textColorDefaultPrimary,\n placeholder: colors.textColorDefaultSecondary,\n icon: colors.textColorDefaultSecondary,\n },\n emoji: {\n selected: colors.fillColorNeutral080,\n },\n }\n\n return (\n <View style={styles.container}>\n <EmojiKeyboard\n categoryPosition=\"top\"\n emojisByCategory={filteredEmojis}\n onEmojiSelected={handleEmojiSelected}\n enableSearchBar\n enableRecentlyUsed\n theme={emojiTheme}\n styles={{\n container: { borderRadius: 0 },\n category: {\n container: {\n borderRadius: 0,\n marginTop: -6,\n borderBottomWidth: 1,\n borderBottomColor: colors.borderColorDefaultDim,\n },\n },\n }}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: colors.fillColorNeutral100Inverted,\n },\n })\n}\n"]}
1
+ {"version":3,"file":"emoji_tab.js","sourceRoot":"","sources":["../../../src/screens/avatar_picker/emoji_tab.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,WAAW,EAAE,MAAM,OAAO,CAAA;AAC1C,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAA;AAC/C,OAAO,EAAE,aAAa,EAAyC,MAAM,mBAAmB,CAAA;AACxF,0EAA0E;AAC1E,2EAA2E;AAC3E,sEAAsE;AACtE,OAAO,SAAS,MAAM,0CAA0C,CAAA;AAChE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;AAEtC,MAAM,cAAc,GAAI,SAAgC,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IACxE,GAAG,QAAQ;IACX,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;CAC9D,CAAC,CAAC,CAAA;AAMH,MAAM,UAAU,QAAQ,CAAC,EAAE,aAAa,EAAiB;IACvD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAA;IAC1B,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,MAAM,mBAAmB,GAAG,WAAW,CACrC,CAAC,WAAsB,EAAE,EAAE;QACzB,aAAa,CAAC,WAAW,CAAC,KAAK,CAAC,CAAA;IAClC,CAAC,EACD,CAAC,aAAa,CAAC,CAChB,CAAA;IAED,MAAM,UAAU,GAAG;QACjB,SAAS,EAAE,MAAM,CAAC,2BAA2B;QAC7C,MAAM,EAAE,MAAM,CAAC,yBAAyB;QACxC,IAAI,EAAE,MAAM,CAAC,mBAAmB;QAChC,kBAAkB,EAAE,MAAM,CAAC,mBAAmB;QAC9C,QAAQ,EAAE;YACR,IAAI,EAAE,MAAM,CAAC,yBAAyB;YACtC,UAAU,EAAE,MAAM,CAAC,WAAW;YAC9B,SAAS,EAAE,MAAM,CAAC,2BAA2B;YAC7C,eAAe,EAAE,MAAM,CAAC,mBAAmB;SAC5C;QACD,MAAM,EAAE;YACN,UAAU,EAAE,MAAM,CAAC,mBAAmB;YACtC,IAAI,EAAE,MAAM,CAAC,uBAAuB;YACpC,WAAW,EAAE,MAAM,CAAC,yBAAyB;YAC7C,IAAI,EAAE,MAAM,CAAC,yBAAyB;SACvC;QACD,KAAK,EAAE;YACL,QAAQ,EAAE,MAAM,CAAC,mBAAmB;SACrC;KACF,CAAA;IAED,OAAO,CACL,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAC5B;MAAA,CAAC,aAAa,CACZ,gBAAgB,CAAC,KAAK,CACtB,gBAAgB,CAAC,CAAC,cAAc,CAAC,CACjC,eAAe,CAAC,CAAC,mBAAmB,CAAC,CACrC,eAAe,CACf,kBAAkB,CAClB,KAAK,CAAC,CAAC,UAAU,CAAC,CAClB,MAAM,CAAC,CAAC;YACN,SAAS,EAAE,EAAE,YAAY,EAAE,CAAC,EAAE;YAC9B,QAAQ,EAAE;gBACR,SAAS,EAAE;oBACT,YAAY,EAAE,CAAC;oBACf,SAAS,EAAE,CAAC,CAAC;oBACb,iBAAiB,EAAE,CAAC;oBACpB,iBAAiB,EAAE,MAAM,CAAC,qBAAqB;iBAChD;aACF;SACF,CAAC,EAEN;IAAA,EAAE,IAAI,CAAC,CACR,CAAA;AACH,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,EAAE;IACrB,MAAM,EAAE,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAA;IAE7B,OAAO,UAAU,CAAC,MAAM,CAAC;QACvB,SAAS,EAAE;YACT,IAAI,EAAE,CAAC;YACP,eAAe,EAAE,MAAM,CAAC,2BAA2B;SACpD;KACF,CAAC,CAAA;AACJ,CAAC,CAAA","sourcesContent":["import React, { useCallback } from 'react'\nimport { StyleSheet, View } from 'react-native'\nimport { EmojiKeyboard, type EmojiType, type EmojisByCategory } from 'rn-emoji-keyboard'\n// rn-emoji-keyboard exposes no public exclusion API, so we reach into its\n// internal src/ tree for the emoji JSON. Version is pinned in package.json\n// — verify this path still resolves before bumping rn-emoji-keyboard.\nimport emojiData from 'rn-emoji-keyboard/src/assets/emojis.json'\nimport { useTheme } from '../../hooks'\n\nconst BLOCKED_EMOJIS = new Set(['🖕'])\n\nconst filteredEmojis = (emojiData as EmojisByCategory[]).map(category => ({\n ...category,\n data: category.data.filter(e => !BLOCKED_EMOJIS.has(e.emoji)),\n}))\n\ninterface EmojiTabProps {\n onEmojiSelect: (emoji: string) => void\n}\n\nexport function EmojiTab({ onEmojiSelect }: EmojiTabProps) {\n const styles = useStyles()\n const { colors } = useTheme()\n\n const handleEmojiSelected = useCallback(\n (emojiObject: EmojiType) => {\n onEmojiSelect(emojiObject.emoji)\n },\n [onEmojiSelect]\n )\n\n const emojiTheme = {\n container: colors.fillColorNeutral100Inverted,\n header: colors.textColorDefaultSecondary,\n knob: colors.fillColorNeutral040,\n skinTonesContainer: colors.fillColorNeutral060,\n category: {\n icon: colors.textColorDefaultSecondary,\n iconActive: colors.interaction,\n container: colors.fillColorNeutral100Inverted,\n containerActive: colors.fillColorNeutral080,\n },\n search: {\n background: colors.fillColorNeutral080,\n text: colors.textColorDefaultPrimary,\n placeholder: colors.textColorDefaultSecondary,\n icon: colors.textColorDefaultSecondary,\n },\n emoji: {\n selected: colors.fillColorNeutral080,\n },\n }\n\n return (\n <View style={styles.container}>\n <EmojiKeyboard\n categoryPosition=\"top\"\n emojisByCategory={filteredEmojis}\n onEmojiSelected={handleEmojiSelected}\n enableSearchBar\n enableRecentlyUsed\n theme={emojiTheme}\n styles={{\n container: { borderRadius: 0 },\n category: {\n container: {\n borderRadius: 0,\n marginTop: -6,\n borderBottomWidth: 1,\n borderBottomColor: colors.borderColorDefaultDim,\n },\n },\n }}\n />\n </View>\n )\n}\n\nconst useStyles = () => {\n const { colors } = useTheme()\n\n return StyleSheet.create({\n container: {\n flex: 1,\n backgroundColor: colors.fillColorNeutral100Inverted,\n },\n })\n}\n"]}
@@ -9,7 +9,6 @@ export type ConversationRouteProps = {
9
9
  chat_group_graph_id?: string;
10
10
  clear_input?: boolean;
11
11
  editing_message_id?: number | null;
12
- message_id?: string;
13
12
  title?: string;
14
13
  subtitle?: string;
15
14
  badge?: ConversationBadgeResource;
@@ -1 +1 @@
1
- {"version":3,"file":"conversation_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAC7F,OAAO,EAGL,iBAAiB,EAIlB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAA4D,MAAM,OAAO,CAAA;AA6ChF,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AAiBjF,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,CAAA;AAE/E,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBA6BpE;AAkSD,UAAU,4BAA6B,SAAQ,gBAAgB;IAC7D,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,eAAO,MAAM,uBAAuB,GAAI,8DAOrC,4BAA4B,sBAoC9B,CAAA"}
1
+ {"version":3,"file":"conversation_screen.d.ts","sourceRoot":"","sources":["../../src/screens/conversation_screen.tsx"],"names":[],"mappings":"AACA,OAAO,EAAe,gBAAgB,EAAqB,MAAM,4BAA4B,CAAA;AAC7F,OAAO,EAGL,iBAAiB,EAIlB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAmD,MAAM,OAAO,CAAA;AA+BvE,OAAO,EAAE,yBAAyB,EAAE,MAAM,uCAAuC,CAAA;AAOjF,MAAM,MAAM,sBAAsB,GAAG;IACnC,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAA;IAC/B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAClC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAA;AAED,MAAM,MAAM,uBAAuB,GAAG,iBAAiB,CAAC,sBAAsB,CAAC,CAAA;AAE/E,wBAAgB,kBAAkB,CAAC,EAAE,KAAK,EAAE,EAAE,uBAAuB,qBAkBpE;AA2ND,UAAU,4BAA6B,SAAQ,gBAAgB;IAC7D,eAAe,EAAE,MAAM,CAAA;IACvB,KAAK,CAAC,EAAE,yBAAyB,CAAA;IACjC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB;AAED,eAAO,MAAM,uBAAuB,GAAI,8DAOrC,4BAA4B,sBAoC9B,CAAA"}
@@ -1,142 +1,85 @@
1
1
  import { date as formatDate } from '@planningcenter/datetime-fmt';
2
2
  import { HeaderTitle, PlatformPressable } from '@react-navigation/elements';
3
3
  import { CommonActions, useNavigation, useTheme as useNavigationTheme, useRoute, } from '@react-navigation/native';
4
- import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
5
- import { ActivityIndicator, Platform, StyleSheet, View } from 'react-native';
6
- import Animated, { FadeIn, FadeOut } from 'react-native-reanimated';
4
+ import React, { useCallback, useEffect, useRef, useState } from 'react';
5
+ import { FlatList, Platform, StyleSheet, View } from 'react-native';
7
6
  import { useSafeAreaInsets } from 'react-native-safe-area-context';
8
7
  import { Badge, Icon, Text } from '../components';
9
8
  import { EmptyConversationBlankState } from '../components/conversation/empty_conversation_blank_state';
10
9
  import { JumpToBottomButton } from '../components/conversation/jump_to_bottom_button';
11
10
  import { Message } from '../components/conversation/message';
12
11
  import { MessageForm } from '../components/conversation/message_form';
13
- import { MessageList } from '../components/conversation/message_list';
14
12
  import { ConversationDisabledBanner, LeaderMessagesDisabledBanner, MemberMessagesDisabledBanner, } from '../components/conversation/messages_disabled_banners';
15
13
  import { ReplyShadowMessage } from '../components/conversation/reply_shadow_message';
16
14
  import { SystemMessage } from '../components/conversation/system_message';
17
15
  import { TypingIndicator } from '../components/conversation/typing_indicator';
18
- import { UnreadDivider } from '../components/conversation/unread_divider';
19
16
  import { KeyboardView } from '../components/display/keyboard_view';
20
17
  import BlankState from '../components/primitive/blank_state_primitive';
21
- import { ConversationContextProvider, useConversationContext, } from '../contexts/conversation_context';
18
+ import { ConversationContextProvider } from '../contexts/conversation_context';
22
19
  import { useTheme } from '../hooks';
23
20
  import { useConversation } from '../hooks/use_conversation';
24
21
  import { useConversationJoltEvents } from '../hooks/use_conversation_jolt_events';
25
22
  import { useConversationMessages } from '../hooks/use_conversation_messages';
26
23
  import { useConversationMessagesJoltEvents } from '../hooks/use_conversation_messages_jolt_events';
27
- import { availableFeatures, useFeatures } from '../hooks/use_features';
28
- import { useFlatListViewability } from '../hooks/use_flat_list_viewability';
29
- import { useJumpToBottomAction } from '../hooks/use_jump_to_bottom_action';
30
- import { useJumpToUnreadAnchor } from '../hooks/use_jump_to_unread_anchor';
31
- import { useJumpToUnreadGates } from '../hooks/use_jump_to_unread_gates';
32
24
  import { useMarkLatestMessageRead } from '../hooks/use_mark_latest_message_read';
33
25
  import { analyticsEvents, normalizeAnalyticsMetadata, usePublishProductAnalyticsEvent, } from '../hooks/use_product_analytics';
34
- import { useScrollTracking } from '../hooks/use_scroll_tracking';
35
- import { useTrackHighestSeenMessage } from '../hooks/use_track_highest_seen_message';
36
26
  import { getRelativeDateStatus } from '../utils/date';
37
- import { groupMessages, UNREAD_DIVIDER_KEY, } from '../utils/group_messages';
38
- import { detectDividerExitTowardNewer, reportViewableMessages, } from '../utils/message_viewability';
27
+ import { groupMessages } from '../utils/group_messages';
39
28
  import { CONVERSATION_MESSAGE_LIST_PADDING_HORIZONTAL } from '../utils/styles';
40
29
  import { isSystemMessage } from '../utils/system_messages';
41
30
  export function ConversationScreen({ route }) {
42
- const { conversation_id, message_id, reply_root_id } = route.params;
31
+ const { conversation_id, reply_root_id } = route.params;
43
32
  const { data: conversation } = useConversation({ conversation_id });
44
- const { featureEnabled } = useFeatures();
45
33
  usePublishProductAnalyticsEvent(analyticsEvents.conversation_show_opened, {
46
34
  reply_root_id,
47
35
  ...normalizeAnalyticsMetadata(conversation),
48
36
  });
49
- const lastReadMessageSortKey = conversation.conversationMembership?.lastReadMessageSortKey ?? null;
50
- const jumpToUnreadAnchor = featureEnabled(availableFeatures.jump_to_unread) && !reply_root_id
51
- ? lastReadMessageSortKey
52
- : null;
53
- const initialMessageId = message_id ?? jumpToUnreadAnchor;
54
- const initialMessageIdIsAnchor = !!initialMessageId && !message_id;
55
- return (<ConversationContextProvider conversationId={conversation_id} currentPageReplyRootId={reply_root_id ?? null} initialMessageId={initialMessageId} initialMessageIdIsAnchor={initialMessageIdIsAnchor}>
37
+ return (<ConversationContextProvider conversationId={conversation_id} currentPageReplyRootId={reply_root_id ?? null}>
56
38
  <ConversationScreenContent route={route}/>
57
39
  </ConversationContextProvider>);
58
40
  }
59
41
  function ConversationScreenContent({ route }) {
60
42
  const styles = useStyles();
61
43
  const navigation = useNavigation();
62
- const { conversation_id: conversationId, editing_message_id: editingMessageId, reply_root_id: replyRootId, reply_root_author_name: replyRootAuthorName, } = route.params;
44
+ const { conversation_id, editing_message_id, reply_root_id, reply_root_author_name } = route.params;
63
45
  const { data: conversation } = useConversation(route.params);
64
- const { messages, fetchOlderMessages, fetchNewerMessages, hasMoreNewerMessages, isFetchingNewerMessages, cancelFetchNewerMessages, } = useConversationMessages({ conversation_id: conversationId, reply_root_id: replyRootId });
65
- const { jumpToUnreadActive } = useJumpToUnreadGates();
66
- const { initialMessageId } = useConversationContext();
67
- useConversationJoltEvents({ conversationId });
68
- useConversationMessagesJoltEvents({ conversationId });
46
+ const { messages, fetchNextPage } = useConversationMessages({
47
+ conversation_id,
48
+ reply_root_id,
49
+ });
50
+ useConversationJoltEvents({ conversationId: conversation_id });
51
+ useConversationMessagesJoltEvents({ conversationId: conversation_id });
69
52
  useEnsureConversationsRouteExists();
70
53
  useMarkLatestMessageRead({ conversation, messages });
71
- const { onMessageSeen } = useTrackHighestSeenMessage();
72
- const items = useMemo(() => groupMessages({
54
+ const messagesWithSeparators = groupMessages({
73
55
  ms: messages,
74
- inReplyScreen: !!replyRootId,
75
- jumpToUnreadActive,
76
- initialMessageId,
77
- }), [messages, replyRootId, jumpToUnreadActive, initialMessageId]);
78
- const noMessages = items.length === 0;
56
+ inReplyScreen: !!reply_root_id,
57
+ });
58
+ const noMessages = messagesWithSeparators.length === 0;
79
59
  const { repliesDisabled, memberAbility, badges, title } = conversation;
80
60
  const canReply = memberAbility?.canReply;
81
61
  const showLeaderDisabledReplyBanner = canReply && repliesDisabled;
82
62
  const canDeleteNonAuthoredMessages = memberAbility?.canDeleteNonAuthoredMessages ?? false;
83
- const currentlyEditingMessage = messages.find(m => String(m.id) === String(editingMessageId));
84
- const replyRootAuthorFirstName = replyRootAuthorName?.split(' ')[0];
63
+ const currentlyEditingMessage = messages.find(m => String(m.id) === String(editing_message_id));
64
+ const replyRootAuthorFirstName = reply_root_author_name?.split(' ')[0];
85
65
  const replyHeaderTitle = replyRootAuthorFirstName
86
66
  ? `Reply to ${replyRootAuthorFirstName}`
87
67
  : 'Reply';
88
68
  // Prefer the membership for optimistic updates.
89
69
  const muted = conversation.conversationMembership?.muted ?? conversation.muted;
90
70
  const listRef = useRef(null);
91
- const [dividerScrolledPast, setDividerScrolledPast] = useState(false);
92
- const observers = useMemo(() => [
93
- reportViewableMessages(onMessageSeen),
94
- detectDividerExitTowardNewer({
95
- dividerKey: UNREAD_DIVIDER_KEY,
96
- initialMessageId,
97
- onExited: () => setDividerScrolledPast(true),
98
- }),
99
- ], [onMessageSeen, initialMessageId]);
100
- const { viewabilityConfigCallbackPairs, onScrollBeginDrag: viewabilityOnScrollBeginDrag } = useFlatListViewability({ observers });
101
- const { onContentSizeChange, onScrollToIndexFailed, onScrollBeginDrag: anchorOnScrollBeginDrag, } = useJumpToUnreadAnchor({ listRef, items });
102
- const onScrollBeginDrag = useCallback(() => {
103
- viewabilityOnScrollBeginDrag();
104
- anchorOnScrollBeginDrag();
105
- }, [viewabilityOnScrollBeginDrag, anchorOnScrollBeginDrag]);
106
- const { onScroll, showJumpToBottomButton } = useScrollTracking({
107
- hasMoreNewerMessages,
108
- isFetchingNewerMessages,
109
- fetchNewerMessages,
110
- cancelFetchNewerMessages,
111
- });
112
- const { handleJumpToBottom, isJumpingToBottom } = useJumpToBottomAction({ listRef });
113
- const listHeader = useMemo(() => (<View>
114
- {isFetchingNewerMessages && (<Animated.View entering={FadeIn.duration(750)} exiting={FadeOut.duration(750)} style={styles.loadingFooter} accessibilityRole="progressbar" accessibilityLabel="Loading more messages">
115
- <ActivityIndicator />
116
- </Animated.View>)}
117
- <View style={styles.listHeader}/>
118
- </View>), [isFetchingNewerMessages, styles.loadingFooter, styles.listHeader]);
119
- const renderItem = useCallback(({ item }) => {
120
- if (item.type === 'DateSeparator')
121
- return <InlineDateSeparator {...item}/>;
122
- if (item.type === 'UnreadDivider')
123
- return <UnreadDivider scrolledPast={dividerScrolledPast}/>;
124
- if (item.type === 'ReplyShadowMessage') {
125
- return (<ReplyShadowMessage {...item} conversation_id={conversationId} inReplyScreen={!!replyRootId}/>);
126
- }
127
- if (isSystemMessage(item)) {
128
- return <SystemMessage message={item} conversationId={conversationId}/>;
129
- }
130
- return (<Message {...item} canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages} conversation_id={conversationId} latestReadMessageSortKey={conversation?.latestReadMessageSortKey} inReplyScreen={!!replyRootId}/>);
131
- }, [
132
- dividerScrolledPast,
133
- conversationId,
134
- replyRootId,
135
- canDeleteNonAuthoredMessages,
136
- conversation?.latestReadMessageSortKey,
137
- ]);
71
+ const [showJumpToBottomButton, setShowJumpToBottomButton] = useState(false);
72
+ const trackScroll = (event) => {
73
+ const offsetY = event.nativeEvent.contentOffset.y;
74
+ setShowJumpToBottomButton(offsetY > 200);
75
+ };
76
+ const handleReturnToBottom = useCallback(() => {
77
+ listRef.current?.scrollToOffset({
78
+ offset: 0,
79
+ });
80
+ }, []);
138
81
  useEffect(() => {
139
- if (replyRootId) {
82
+ if (reply_root_id) {
140
83
  navigation.setParams({
141
84
  title: replyHeaderTitle,
142
85
  });
@@ -149,7 +92,7 @@ function ConversationScreenContent({ route }) {
149
92
  muted,
150
93
  });
151
94
  }
152
- }, [navigation, title, badges, conversation?.deleted, replyRootId, replyHeaderTitle, muted]);
95
+ }, [navigation, title, badges, conversation?.deleted, reply_root_id, replyHeaderTitle, muted]);
153
96
  if (!conversation || conversation.deleted) {
154
97
  return (<View style={styles.container}>
155
98
  <BlankState.Root>
@@ -163,11 +106,22 @@ function ConversationScreenContent({ route }) {
163
106
  }
164
107
  return (<View style={styles.container}>
165
108
  <KeyboardView>
166
- {noMessages ? (<EmptyConversationBlankState />) : (<MessageList listRef={listRef} data={items} onScroll={onScroll} onScrollBeginDrag={onScrollBeginDrag} viewabilityConfigCallbackPairs={viewabilityConfigCallbackPairs} onContentSizeChange={onContentSizeChange} onScrollToIndexFailed={onScrollToIndexFailed} renderItem={renderItem} onEndReached={() => fetchOlderMessages()} ListHeaderComponent={listHeader}/>)}
167
- <JumpToBottomButton onPress={handleJumpToBottom} visible={showJumpToBottomButton} loading={isJumpingToBottom}/>
109
+ {noMessages ? (<EmptyConversationBlankState />) : (<FlatList inverted ref={listRef} contentContainerStyle={styles.listContainer} data={messagesWithSeparators} keyExtractor={item => item.id} onScroll={trackScroll} scrollEventThrottle={10} renderItem={({ item }) => {
110
+ if (item.type === 'DateSeparator') {
111
+ return <InlineDateSeparator {...item}/>;
112
+ }
113
+ if (item.type === 'ReplyShadowMessage') {
114
+ return (<ReplyShadowMessage {...item} conversation_id={conversation_id} inReplyScreen={!!reply_root_id}/>);
115
+ }
116
+ if (isSystemMessage(item)) {
117
+ return <SystemMessage message={item} conversationId={conversation_id}/>;
118
+ }
119
+ return (<Message {...item} canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages} conversation_id={conversation_id} latestReadMessageSortKey={conversation?.latestReadMessageSortKey} inReplyScreen={!!reply_root_id}/>);
120
+ }} onEndReached={() => fetchNextPage()} ListHeaderComponent={<View style={styles.listHeader}/>}/>)}
121
+ <JumpToBottomButton onPress={handleReturnToBottom} visible={showJumpToBottomButton}/>
168
122
  {!noMessages && <TypingIndicator />}
169
123
  {showLeaderDisabledReplyBanner && <LeaderMessagesDisabledBanner />}
170
- <ConversationBottomBar conversation={conversation} canReply={canReply} replyRootAuthorFirstName={replyRootAuthorFirstName} replyRootId={replyRootId} currentlyEditingMessage={currentlyEditingMessage}/>
124
+ <ConversationBottomBar conversation={conversation} canReply={canReply} replyRootAuthorFirstName={replyRootAuthorFirstName} replyRootId={reply_root_id} currentlyEditingMessage={currentlyEditingMessage}/>
171
125
  </KeyboardView>
172
126
  </View>);
173
127
  }
@@ -274,14 +228,13 @@ const useStyles = () => {
274
228
  backgroundColor: navigationTheme.colors.card,
275
229
  paddingBottom: bottom,
276
230
  },
231
+ listContainer: {
232
+ paddingVertical: 12,
233
+ },
277
234
  listHeader: {
278
235
  // Just whitespace to provide space where the typing indicator can be
279
236
  height: 16,
280
237
  },
281
- loadingFooter: {
282
- paddingVertical: 12,
283
- alignItems: 'center',
284
- },
285
238
  });
286
239
  };
287
240
  /**