@planningcenter/chat-react-native 4.4.0-rc.7 → 4.4.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 (339) hide show
  1. package/build/components/conversation/jump_to_bottom_button.d.ts.map +1 -1
  2. package/build/components/conversation/jump_to_bottom_button.js +42 -40
  3. package/build/components/conversation/jump_to_bottom_button.js.map +1 -1
  4. package/build/components/conversation/message.d.ts +2 -1
  5. package/build/components/conversation/message.d.ts.map +1 -1
  6. package/build/components/conversation/message.js +3 -1
  7. package/build/components/conversation/message.js.map +1 -1
  8. package/build/components/conversation/message_form.d.ts.map +1 -1
  9. package/build/components/conversation/message_form.js +3 -1
  10. package/build/components/conversation/message_form.js.map +1 -1
  11. package/build/components/conversation/message_list.d.ts.map +1 -1
  12. package/build/components/conversation/message_list.js +35 -31
  13. package/build/components/conversation/message_list.js.map +1 -1
  14. package/build/components/conversation/message_reaction.d.ts +2 -1
  15. package/build/components/conversation/message_reaction.d.ts.map +1 -1
  16. package/build/components/conversation/message_reaction.js +67 -60
  17. package/build/components/conversation/message_reaction.js.map +1 -1
  18. package/build/components/conversation/messages_disabled_banners.d.ts +7 -5
  19. package/build/components/conversation/messages_disabled_banners.d.ts.map +1 -1
  20. package/build/components/conversation/messages_disabled_banners.js +15 -14
  21. package/build/components/conversation/messages_disabled_banners.js.map +1 -1
  22. package/build/components/conversation/system_message.d.ts +2 -1
  23. package/build/components/conversation/system_message.d.ts.map +1 -1
  24. package/build/components/conversation/system_message.js +133 -100
  25. package/build/components/conversation/system_message.js.map +1 -1
  26. package/build/components/conversations/archived_results_footer.d.ts +6 -0
  27. package/build/components/conversations/archived_results_footer.d.ts.map +1 -0
  28. package/build/components/conversations/archived_results_footer.js +51 -0
  29. package/build/components/conversations/archived_results_footer.js.map +1 -0
  30. package/build/components/conversations/conversation_actions.d.ts.map +1 -1
  31. package/build/components/conversations/conversation_actions.js +241 -206
  32. package/build/components/conversations/conversation_actions.js.map +1 -1
  33. package/build/components/conversations/conversation_preview.d.ts.map +1 -1
  34. package/build/components/conversations/conversation_preview.js +102 -93
  35. package/build/components/conversations/conversation_preview.js.map +1 -1
  36. package/build/components/conversations/conversations.d.ts.map +1 -1
  37. package/build/components/conversations/conversations.js +66 -41
  38. package/build/components/conversations/conversations.js.map +1 -1
  39. package/build/components/conversations/conversations_blank_state.d.ts.map +1 -1
  40. package/build/components/conversations/conversations_blank_state.js +55 -12
  41. package/build/components/conversations/conversations_blank_state.js.map +1 -1
  42. package/build/components/conversations/filtered_results_footer.d.ts +2 -0
  43. package/build/components/conversations/filtered_results_footer.d.ts.map +1 -0
  44. package/build/components/conversations/filtered_results_footer.js +77 -0
  45. package/build/components/conversations/filtered_results_footer.js.map +1 -0
  46. package/build/components/display/action_button.d.ts.map +1 -1
  47. package/build/components/display/action_button.js +18 -16
  48. package/build/components/display/action_button.js.map +1 -1
  49. package/build/components/display/filter_dropdown.d.ts +14 -0
  50. package/build/components/display/filter_dropdown.d.ts.map +1 -0
  51. package/build/components/display/filter_dropdown.js +193 -0
  52. package/build/components/display/filter_dropdown.js.map +1 -0
  53. package/build/components/display/icon_tile.d.ts +13 -0
  54. package/build/components/display/icon_tile.d.ts.map +1 -0
  55. package/build/components/display/icon_tile.js +149 -0
  56. package/build/components/display/icon_tile.js.map +1 -0
  57. package/build/components/display/index.d.ts +2 -0
  58. package/build/components/display/index.d.ts.map +1 -1
  59. package/build/components/display/index.js +2 -0
  60. package/build/components/display/index.js.map +1 -1
  61. package/build/contexts/api_provider.d.ts.map +1 -1
  62. package/build/contexts/api_provider.js +21 -9
  63. package/build/contexts/api_provider.js.map +1 -1
  64. package/build/contexts/conversations_context.d.ts.map +1 -1
  65. package/build/contexts/conversations_context.js +21 -18
  66. package/build/contexts/conversations_context.js.map +1 -1
  67. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts +196 -16
  68. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts.map +1 -1
  69. package/build/hooks/groups/use_group_members_for_new_conversation.js +72 -58
  70. package/build/hooks/groups/use_group_members_for_new_conversation.js.map +1 -1
  71. package/build/hooks/index.d.ts +3 -0
  72. package/build/hooks/index.d.ts.map +1 -1
  73. package/build/hooks/index.js +3 -0
  74. package/build/hooks/index.js.map +1 -1
  75. package/build/hooks/use_animated_message_background_color.d.ts.map +1 -1
  76. package/build/hooks/use_animated_message_background_color.js +5 -3
  77. package/build/hooks/use_animated_message_background_color.js.map +1 -1
  78. package/build/hooks/use_api.d.ts +3 -2
  79. package/build/hooks/use_api.d.ts.map +1 -1
  80. package/build/hooks/use_api.js.map +1 -1
  81. package/build/hooks/use_can_browse_archived_conversations.d.ts +2 -0
  82. package/build/hooks/use_can_browse_archived_conversations.d.ts.map +1 -0
  83. package/build/hooks/use_can_browse_archived_conversations.js +29 -0
  84. package/build/hooks/use_can_browse_archived_conversations.js.map +1 -0
  85. package/build/hooks/use_clear_conversation_filters.d.ts +2 -0
  86. package/build/hooks/use_clear_conversation_filters.d.ts.map +1 -0
  87. package/build/hooks/use_clear_conversation_filters.js +25 -0
  88. package/build/hooks/use_clear_conversation_filters.js.map +1 -0
  89. package/build/hooks/use_conversation.d.ts +73 -1
  90. package/build/hooks/use_conversation.d.ts.map +1 -1
  91. package/build/hooks/use_conversation.js +130 -3
  92. package/build/hooks/use_conversation.js.map +1 -1
  93. package/build/hooks/use_conversation_messages.d.ts.map +1 -1
  94. package/build/hooks/use_conversation_messages.js +29 -26
  95. package/build/hooks/use_conversation_messages.js.map +1 -1
  96. package/build/hooks/use_current_person.d.ts.map +1 -1
  97. package/build/hooks/use_current_person.js +1 -1
  98. package/build/hooks/use_current_person.js.map +1 -1
  99. package/build/hooks/use_jolt.d.ts +1 -0
  100. package/build/hooks/use_jolt.d.ts.map +1 -1
  101. package/build/hooks/use_jolt.js +59 -0
  102. package/build/hooks/use_jolt.js.map +1 -1
  103. package/build/hooks/use_manual_archiving_enabled.d.ts +2 -0
  104. package/build/hooks/use_manual_archiving_enabled.d.ts.map +1 -0
  105. package/build/hooks/use_manual_archiving_enabled.js +18 -0
  106. package/build/hooks/use_manual_archiving_enabled.js.map +1 -0
  107. package/build/hooks/use_mark_latest_message_read.d.ts.map +1 -1
  108. package/build/hooks/use_mark_latest_message_read.js +3 -3
  109. package/build/hooks/use_mark_latest_message_read.js.map +1 -1
  110. package/build/hooks/use_reduce_motion.d.ts +2 -0
  111. package/build/hooks/use_reduce_motion.d.ts.map +1 -0
  112. package/build/hooks/use_reduce_motion.js +28 -0
  113. package/build/hooks/use_reduce_motion.js.map +1 -0
  114. package/build/hooks/use_unarchive_conversation_action.d.ts +7 -0
  115. package/build/hooks/use_unarchive_conversation_action.d.ts.map +1 -0
  116. package/build/hooks/use_unarchive_conversation_action.js +52 -0
  117. package/build/hooks/use_unarchive_conversation_action.js.map +1 -0
  118. package/build/screens/attachment_actions/attachment_actions_screen.d.ts.map +1 -1
  119. package/build/screens/attachment_actions/attachment_actions_screen.js +84 -61
  120. package/build/screens/attachment_actions/attachment_actions_screen.js.map +1 -1
  121. package/build/screens/conversation_details_screen.d.ts.map +1 -1
  122. package/build/screens/conversation_details_screen.js +490 -395
  123. package/build/screens/conversation_details_screen.js.map +1 -1
  124. package/build/screens/conversation_filters/components/conversation_filters.d.ts.map +1 -1
  125. package/build/screens/conversation_filters/components/conversation_filters.js +88 -18
  126. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  127. package/build/screens/conversation_filters/components/rows.d.ts +9 -0
  128. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  129. package/build/screens/conversation_filters/components/rows.js +93 -1
  130. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  131. package/build/screens/conversation_filters/context/conversation_filter_context.d.ts.map +1 -1
  132. package/build/screens/conversation_filters/context/conversation_filter_context.js +8 -4
  133. package/build/screens/conversation_filters/context/conversation_filter_context.js.map +1 -1
  134. package/build/screens/conversation_filters/filter_types.d.ts +1 -0
  135. package/build/screens/conversation_filters/filter_types.d.ts.map +1 -1
  136. package/build/screens/conversation_filters/filter_types.js +1 -0
  137. package/build/screens/conversation_filters/filter_types.js.map +1 -1
  138. package/build/screens/conversation_filters/screen_props.d.ts +1 -0
  139. package/build/screens/conversation_filters/screen_props.d.ts.map +1 -1
  140. package/build/screens/conversation_filters/screen_props.js.map +1 -1
  141. package/build/screens/conversation_filters_screen.d.ts +1 -0
  142. package/build/screens/conversation_filters_screen.d.ts.map +1 -1
  143. package/build/screens/conversation_filters_screen.js +79 -48
  144. package/build/screens/conversation_filters_screen.js.map +1 -1
  145. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  146. package/build/screens/conversation_new/components/groups_form.js +37 -34
  147. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  148. package/build/screens/conversation_screen.d.ts.map +1 -1
  149. package/build/screens/conversation_screen.js +13 -10
  150. package/build/screens/conversation_screen.js.map +1 -1
  151. package/build/screens/conversations/components/filter_dropdown_list_header_component.d.ts +2 -0
  152. package/build/screens/conversations/components/filter_dropdown_list_header_component.d.ts.map +1 -0
  153. package/build/screens/conversations/components/filter_dropdown_list_header_component.js +580 -0
  154. package/build/screens/conversations/components/filter_dropdown_list_header_component.js.map +1 -0
  155. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  156. package/build/screens/conversations/components/list_header_component.js +95 -90
  157. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  158. package/build/screens/conversations/components/search_list_header_component.d.ts.map +1 -1
  159. package/build/screens/conversations/components/search_list_header_component.js +100 -95
  160. package/build/screens/conversations/components/search_list_header_component.js.map +1 -1
  161. package/build/screens/conversations/conversations_screen.d.ts +1 -0
  162. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  163. package/build/screens/conversations/conversations_screen.js +15 -2
  164. package/build/screens/conversations/conversations_screen.js.map +1 -1
  165. package/build/screens/design_system_screen.d.ts.map +1 -1
  166. package/build/screens/design_system_screen.js +275 -215
  167. package/build/screens/design_system_screen.js.map +1 -1
  168. package/build/screens/message_actions_screen.d.ts.map +1 -1
  169. package/build/screens/message_actions_screen.js +112 -92
  170. package/build/screens/message_actions_screen.js.map +1 -1
  171. package/build/screens/search/search_screen.d.ts.map +1 -1
  172. package/build/screens/search/search_screen.js +10 -2
  173. package/build/screens/search/search_screen.js.map +1 -1
  174. package/build/screens/send_giphy_screen.d.ts +1 -0
  175. package/build/screens/send_giphy_screen.d.ts.map +1 -1
  176. package/build/screens/send_giphy_screen.js +108 -106
  177. package/build/screens/send_giphy_screen.js.map +1 -1
  178. package/build/screens/team_conversation_screen.js +1 -1
  179. package/build/screens/team_conversation_screen.js.map +1 -1
  180. package/build/types/jolt_events/message_events.d.ts +2 -0
  181. package/build/types/jolt_events/message_events.d.ts.map +1 -1
  182. package/build/types/jolt_events/message_events.js.map +1 -1
  183. package/build/types/resources/conversation.d.ts +2 -2
  184. package/build/types/resources/conversation.d.ts.map +1 -1
  185. package/build/types/resources/conversation.js.map +1 -1
  186. package/build/types/resources/member_ability.d.ts +2 -0
  187. package/build/types/resources/member_ability.d.ts.map +1 -1
  188. package/build/types/resources/member_ability.js.map +1 -1
  189. package/build/types/resources/message.d.ts +2 -0
  190. package/build/types/resources/message.d.ts.map +1 -1
  191. package/build/types/resources/message.js.map +1 -1
  192. package/build/types/resources/person.d.ts +1 -0
  193. package/build/types/resources/person.d.ts.map +1 -1
  194. package/build/types/resources/person.js.map +1 -1
  195. package/build/utils/archived_conversation.d.ts +5 -0
  196. package/build/utils/archived_conversation.d.ts.map +1 -0
  197. package/build/utils/archived_conversation.js +5 -0
  198. package/build/utils/archived_conversation.js.map +1 -0
  199. package/build/utils/date.d.ts +1 -0
  200. package/build/utils/date.d.ts.map +1 -1
  201. package/build/utils/date.js +9 -0
  202. package/build/utils/date.js.map +1 -1
  203. package/build/utils/index.d.ts +1 -0
  204. package/build/utils/index.d.ts.map +1 -1
  205. package/build/utils/index.js +1 -0
  206. package/build/utils/index.js.map +1 -1
  207. package/build/utils/jolt/transform_message_event_data_to_message_resource.d.ts.map +1 -1
  208. package/build/utils/jolt/transform_message_event_data_to_message_resource.js +2 -1
  209. package/build/utils/jolt/transform_message_event_data_to_message_resource.js.map +1 -1
  210. package/build/utils/native_adapters/configuration.d.ts +3 -0
  211. package/build/utils/native_adapters/configuration.d.ts.map +1 -1
  212. package/build/utils/native_adapters/configuration.js +3 -0
  213. package/build/utils/native_adapters/configuration.js.map +1 -1
  214. package/build/utils/native_adapters/index.d.ts +1 -0
  215. package/build/utils/native_adapters/index.d.ts.map +1 -1
  216. package/build/utils/native_adapters/index.js +1 -0
  217. package/build/utils/native_adapters/index.js.map +1 -1
  218. package/build/utils/native_adapters/menu.d.ts +41 -0
  219. package/build/utils/native_adapters/menu.d.ts.map +1 -0
  220. package/build/utils/native_adapters/menu.js +56 -0
  221. package/build/utils/native_adapters/menu.js.map +1 -0
  222. package/build/utils/request/conversation.d.ts +2 -1
  223. package/build/utils/request/conversation.d.ts.map +1 -1
  224. package/build/utils/request/conversation.js +4 -1
  225. package/build/utils/request/conversation.js.map +1 -1
  226. package/build/utils/request/messages_data_options.d.ts.map +1 -1
  227. package/build/utils/request/messages_data_options.js +1 -1
  228. package/build/utils/request/messages_data_options.js.map +1 -1
  229. package/build/utils/system_messages.d.ts +7 -5
  230. package/build/utils/system_messages.d.ts.map +1 -1
  231. package/build/utils/system_messages.js +10 -2
  232. package/build/utils/system_messages.js.map +1 -1
  233. package/build/vendor/font_awesome_pro_solid_icons.d.ts +1 -0
  234. package/build/vendor/font_awesome_pro_solid_icons.d.ts.map +1 -1
  235. package/build/vendor/font_awesome_pro_solid_icons.js +5 -0
  236. package/build/vendor/font_awesome_pro_solid_icons.js.map +1 -1
  237. package/package.json +3 -3
  238. package/src/__tests__/hooks/use_can_browse_archived_conversations.test.tsx +98 -0
  239. package/src/__tests__/screens/conversation_filters/components/conversation_filters.test.tsx +132 -0
  240. package/src/__tests__/screens/conversation_filters_screen.test.tsx +76 -0
  241. package/src/__tests__/screens/conversation_new/components/services_form.test.tsx +1 -0
  242. package/src/__tests__/screens/message_actions_screen.test.tsx +65 -2
  243. package/src/__tests__/screens/send_giphy_screen.test.tsx +102 -0
  244. package/src/__tests__/utils/system_messages.ts +19 -32
  245. package/src/components/conversation/__tests__/message_list.test.tsx +68 -2
  246. package/src/components/conversation/__tests__/system_message.test.tsx +106 -0
  247. package/src/components/conversation/jump_to_bottom_button.tsx +4 -3
  248. package/src/components/conversation/message.tsx +3 -0
  249. package/src/components/conversation/message_form.tsx +3 -1
  250. package/src/components/conversation/message_list.tsx +9 -1
  251. package/src/components/conversation/message_reaction.tsx +7 -2
  252. package/src/components/conversation/messages_disabled_banners.tsx +17 -18
  253. package/src/components/conversation/system_message.tsx +44 -16
  254. package/src/components/conversations/__tests__/conversation_actions.test.tsx +67 -0
  255. package/src/components/conversations/__tests__/conversation_preview.test.tsx +105 -0
  256. package/src/components/conversations/__tests__/conversations.test.tsx +93 -0
  257. package/src/components/conversations/__tests__/conversations_blank_state.test.tsx +73 -0
  258. package/src/components/conversations/archived_results_footer.tsx +36 -0
  259. package/src/components/conversations/conversation_actions.tsx +27 -19
  260. package/src/components/conversations/conversation_preview.tsx +39 -10
  261. package/src/components/conversations/conversations.tsx +26 -3
  262. package/src/components/conversations/conversations_blank_state.tsx +21 -0
  263. package/src/components/conversations/filtered_results_footer.tsx +38 -0
  264. package/src/components/display/__tests__/filter_dropdown.test.tsx +114 -0
  265. package/src/components/display/__tests__/icon_tile.test.tsx +16 -0
  266. package/src/components/display/action_button.tsx +4 -3
  267. package/src/components/display/filter_dropdown.tsx +124 -0
  268. package/src/components/display/icon_tile.tsx +67 -0
  269. package/src/components/display/index.ts +2 -0
  270. package/src/contexts/api_provider.tsx +8 -0
  271. package/src/contexts/conversations_context.tsx +2 -1
  272. package/src/hooks/__tests__/use_conversation_archive.test.tsx +152 -0
  273. package/src/hooks/__tests__/use_conversation_jolt_events.test.tsx +74 -0
  274. package/src/hooks/__tests__/use_conversation_messages.test.tsx +10 -2
  275. package/src/hooks/__tests__/use_jolt.test.tsx +100 -1
  276. package/src/hooks/__tests__/use_mark_latest_message_read.test.tsx +21 -7
  277. package/src/hooks/__tests__/use_reduce_motion.test.tsx +61 -0
  278. package/src/hooks/__tests__/use_unarchive_conversation_action.test.tsx +67 -0
  279. package/src/hooks/groups/use_group_members_for_new_conversation.ts +21 -16
  280. package/src/hooks/index.ts +3 -0
  281. package/src/hooks/use_animated_message_background_color.ts +6 -3
  282. package/src/hooks/use_api.ts +9 -2
  283. package/src/hooks/use_can_browse_archived_conversations.ts +17 -0
  284. package/src/hooks/use_clear_conversation_filters.ts +16 -0
  285. package/src/hooks/use_conversation.ts +44 -3
  286. package/src/hooks/use_conversation_messages.ts +7 -5
  287. package/src/hooks/use_current_person.ts +1 -0
  288. package/src/hooks/use_jolt.ts +57 -1
  289. package/src/hooks/use_manual_archiving_enabled.ts +10 -0
  290. package/src/hooks/use_mark_latest_message_read.ts +4 -3
  291. package/src/hooks/use_reduce_motion.ts +19 -0
  292. package/src/hooks/use_unarchive_conversation_action.ts +24 -0
  293. package/src/screens/__tests__/conversation_details_screen.test.tsx +305 -0
  294. package/src/screens/attachment_actions/__tests__/attachment_actions_screen.test.tsx +72 -0
  295. package/src/screens/attachment_actions/attachment_actions_screen.tsx +3 -1
  296. package/src/screens/conversation_details_screen.tsx +80 -16
  297. package/src/screens/conversation_filters/__tests__/conversation_filters.test.tsx +101 -0
  298. package/src/screens/conversation_filters/components/conversation_filters.tsx +40 -7
  299. package/src/screens/conversation_filters/components/rows.tsx +29 -1
  300. package/src/screens/conversation_filters/context/conversation_filter_context.tsx +4 -0
  301. package/src/screens/conversation_filters/filter_types.ts +1 -0
  302. package/src/screens/conversation_filters/screen_props.ts +1 -0
  303. package/src/screens/conversation_filters_screen.tsx +25 -5
  304. package/src/screens/conversation_new/components/groups_form.tsx +1 -0
  305. package/src/screens/conversation_screen.tsx +4 -2
  306. package/src/screens/conversations/__tests__/conversations_screen.test.tsx +52 -0
  307. package/src/screens/conversations/components/__tests__/filter_dropdown_list_header_component.test.tsx +259 -0
  308. package/src/screens/conversations/components/__tests__/list_header_component.test.tsx +21 -4
  309. package/src/screens/conversations/components/filter_dropdown_list_header_component.tsx +286 -0
  310. package/src/screens/conversations/components/list_header_component.tsx +17 -12
  311. package/src/screens/conversations/components/search_list_header_component.tsx +17 -12
  312. package/src/screens/conversations/conversations_screen.tsx +15 -2
  313. package/src/screens/design_system_screen.tsx +26 -0
  314. package/src/screens/message_actions_screen.tsx +29 -20
  315. package/src/screens/search/__tests__/search_screen.test.tsx +13 -1
  316. package/src/screens/search/search_screen.tsx +8 -2
  317. package/src/screens/send_giphy_screen.tsx +6 -3
  318. package/src/screens/team_conversation_screen.tsx +1 -1
  319. package/src/types/jolt_events/message_events.ts +2 -0
  320. package/src/types/resources/conversation.ts +2 -2
  321. package/src/types/resources/member_ability.ts +2 -0
  322. package/src/types/resources/message.ts +3 -0
  323. package/src/types/resources/person.ts +1 -0
  324. package/src/utils/__tests__/conversation.test.ts +1 -0
  325. package/src/utils/__tests__/date.test.ts +23 -0
  326. package/src/utils/__tests__/group_messages.test.ts +1 -0
  327. package/src/utils/archived_conversation.ts +13 -0
  328. package/src/utils/date.ts +8 -0
  329. package/src/utils/index.ts +1 -0
  330. package/src/utils/jolt/__tests__/transform_message_event_data_to_message_resource.test.ts +35 -0
  331. package/src/utils/jolt/transform_message_event_data_to_message_resource.ts +1 -0
  332. package/src/utils/native_adapters/__tests__/menu.test.tsx +46 -0
  333. package/src/utils/native_adapters/configuration.ts +5 -0
  334. package/src/utils/native_adapters/index.ts +1 -0
  335. package/src/utils/native_adapters/menu.tsx +70 -0
  336. package/src/utils/request/conversation.ts +4 -0
  337. package/src/utils/request/messages_data_options.ts +1 -0
  338. package/src/utils/system_messages.ts +19 -10
  339. package/src/vendor/font_awesome_pro_solid_icons.ts +12 -0
@@ -16,11 +16,13 @@ export function MessageReaction({
16
16
  onLongPress,
17
17
  message,
18
18
  conversationId,
19
+ disabled = false,
19
20
  }: {
20
21
  reaction: ReactionCountResource
21
22
  onLongPress: (_reaction: ReactionCountResource) => void
22
23
  message: MessageResource
23
24
  conversationId: number
25
+ disabled?: boolean
24
26
  }) {
25
27
  const styles = useReactionStyles(reaction)
26
28
  const { handleReactionToggle } = useMessageReactionToggle({
@@ -46,8 +48,11 @@ export function MessageReaction({
46
48
  testID={`reaction-${message.id}-${reaction.value}`}
47
49
  style={styles.reaction}
48
50
  onLongPress={() => onLongPress(reaction)}
49
- onPress={handlePress}
50
- android_ripple={{ color: androidRippleColor, borderless: false, foreground: true }}
51
+ onPress={disabled ? undefined : handlePress}
52
+ pressOpacity={disabled ? 1 : undefined}
53
+ android_ripple={
54
+ disabled ? undefined : { color: androidRippleColor, borderless: false, foreground: true }
55
+ }
51
56
  >
52
57
  <Text style={styles.reactionEmoji}>{REACTION_EMOJIS[reaction.value]}</Text>
53
58
  <Text style={styles.reactionText}>{reaction.count}</Text>
@@ -22,38 +22,36 @@ export const MemberMessagesDisabledBanner = () => {
22
22
 
23
23
  const DEFAULT_DISABLED_TEXT = 'This conversation has been disabled.'
24
24
 
25
+ interface BannerAction {
26
+ label: string
27
+ onPress: () => void
28
+ loading?: boolean
29
+ }
30
+
25
31
  interface ConversationDisabledBannerProps {
26
32
  message: string | null
27
- messageLink?: { label: string; onPress: () => void }
33
+ action?: BannerAction
28
34
  }
29
35
 
30
36
  export const ConversationDisabledBanner = ({
31
37
  message,
32
- messageLink,
38
+ action,
33
39
  }: ConversationDisabledBannerProps) => {
34
40
  const styles = useStyles()
35
41
  const description = message ?? DEFAULT_DISABLED_TEXT
36
42
 
37
43
  return (
38
- <MessagesDisabledBanner
39
- description={description}
40
- style={styles.memberBanner}
41
- messageLink={messageLink}
42
- />
44
+ <MessagesDisabledBanner description={description} style={styles.memberBanner} action={action} />
43
45
  )
44
46
  }
45
47
 
46
48
  interface MessagesDisabledBannerProps {
47
49
  description: string
48
50
  style?: ViewStyle
49
- messageLink?: { label: string; onPress: () => void }
51
+ action?: BannerAction
50
52
  }
51
53
 
52
- const MessagesDisabledBanner = ({
53
- description,
54
- style,
55
- messageLink,
56
- }: MessagesDisabledBannerProps) => {
54
+ const MessagesDisabledBanner = ({ description, style, action }: MessagesDisabledBannerProps) => {
57
55
  const styles = useStyles()
58
56
 
59
57
  return (
@@ -61,13 +59,14 @@ const MessagesDisabledBanner = ({
61
59
  <Text style={styles.text} variant="tertiary">
62
60
  {description}
63
61
  </Text>
64
- {messageLink && (
62
+ {action && (
65
63
  <Button
66
64
  variant="fill"
67
65
  size="lg"
68
- title={messageLink.label}
69
- onPress={messageLink.onPress}
70
- style={styles.messageButton}
66
+ title={action.label}
67
+ onPress={action.onPress}
68
+ loading={action.loading}
69
+ style={styles.actionButton}
71
70
  />
72
71
  )}
73
72
  </View>
@@ -94,7 +93,7 @@ const useStyles = () => {
94
93
  paddingBottom: 16 + bottom,
95
94
  marginBottom: -bottom,
96
95
  },
97
- messageButton: {
96
+ actionButton: {
98
97
  marginTop: 12,
99
98
  },
100
99
  })
@@ -4,6 +4,7 @@ import { Pressable, StyleSheet, View } from 'react-native'
4
4
  import Animated from 'react-native-reanimated'
5
5
  import { useAnimatedMessageBackgroundColor, useTheme } from '../../hooks'
6
6
  import { ReactionCountResource } from '../../types/resources/reaction'
7
+ import { formatEventDateTime } from '../../utils/date'
7
8
  import { Haptic } from '../../utils/native_adapters'
8
9
  import { SystemMessageResource } from '../../utils/system_messages'
9
10
  import { Text } from '../display'
@@ -12,24 +13,32 @@ import { MessageReaction } from './message_reaction'
12
13
  interface SystemMessageProps {
13
14
  message: SystemMessageResource
14
15
  conversationId: number
16
+ conversationDisabled: boolean
15
17
  }
16
18
 
17
- export function SystemMessage({ message, conversationId }: SystemMessageProps) {
18
- const { reactionCounts, systemTextParts, personIdsForSystemEvent } = message
19
- const { names, overflowCount, action } = systemTextParts
19
+ export function SystemMessage({
20
+ message,
21
+ conversationId,
22
+ conversationDisabled,
23
+ }: SystemMessageProps) {
24
+ const { reactionCounts } = message
20
25
  const styles = useStyles()
21
26
  const navigation = useNavigation()
22
27
  const { colors } = useTheme()
23
- const text = systemMessageText(names, overflowCount, action)
24
- const isTruncated = overflowCount > 0
28
+ const text = systemMessageText(message)
29
+ const isTruncated =
30
+ message.systemTextFormat === 'people' && message.systemTextParts.overflowCount > 0
31
+ const pressable = isTruncated || !conversationDisabled
25
32
  const hasReactions = reactionCounts.length > 0
26
33
  const { animatedBackgroundColor, handleMessagePressIn, handleMessagePressOut } =
27
34
  useAnimatedMessageBackgroundColor()
28
35
 
29
36
  const handlePress = () => {
37
+ if (message.systemTextFormat !== 'people') return
38
+
30
39
  navigation.navigate('SystemMessagePeople', {
31
40
  conversation_id: conversationId,
32
- person_ids: personIdsForSystemEvent,
41
+ person_ids: message.personIdsForSystemEvent,
33
42
  })
34
43
  }
35
44
 
@@ -54,16 +63,16 @@ export function SystemMessage({ message, conversationId }: SystemMessageProps) {
54
63
  return (
55
64
  <Pressable
56
65
  onPress={isTruncated ? handlePress : undefined}
57
- onLongPress={handleLongPress}
58
- onPressIn={handleMessagePressIn}
59
- onPressOut={handleMessagePressOut}
60
- android_ripple={{ color: colors.androidRippleNeutral, borderless: false, foreground: true }}
61
- accessibilityRole="button"
62
- accessibilityHint={
63
- isTruncated
64
- ? 'Tap to see people. Long press for message actions.'
65
- : 'Long press for message actions.'
66
+ onLongPress={conversationDisabled ? undefined : handleLongPress}
67
+ onPressIn={pressable ? handleMessagePressIn : undefined}
68
+ onPressOut={pressable ? handleMessagePressOut : undefined}
69
+ android_ripple={
70
+ pressable
71
+ ? { color: colors.androidRippleNeutral, borderless: false, foreground: true }
72
+ : undefined
66
73
  }
74
+ accessibilityRole={pressable ? 'button' : undefined}
75
+ accessibilityHint={systemMessageHint(isTruncated, conversationDisabled)}
67
76
  >
68
77
  <Animated.View style={[styles.container, animatedBackgroundColor]}>
69
78
  <Text variant="tertiary" style={styles.text}>
@@ -78,6 +87,7 @@ export function SystemMessage({ message, conversationId }: SystemMessageProps) {
78
87
  onLongPress={handleReactionLongPress}
79
88
  message={message}
80
89
  conversationId={conversationId}
90
+ disabled={conversationDisabled}
81
91
  />
82
92
  ))}
83
93
  </View>
@@ -87,7 +97,25 @@ export function SystemMessage({ message, conversationId }: SystemMessageProps) {
87
97
  )
88
98
  }
89
99
 
90
- function systemMessageText(names: string[], overflowCount: number, action: string): string {
100
+ function systemMessageHint(isTruncated: boolean, conversationDisabled: boolean) {
101
+ if (conversationDisabled) return isTruncated ? 'Tap to see people.' : undefined
102
+ return isTruncated
103
+ ? 'Tap to see people. Long press for message actions.'
104
+ : 'Long press for message actions.'
105
+ }
106
+
107
+ function systemMessageText(message: SystemMessageResource): string {
108
+ switch (message.systemTextFormat) {
109
+ case 'people': {
110
+ const { names, overflowCount, action } = message.systemTextParts
111
+ return peopleSystemMessageText(names, overflowCount, action)
112
+ }
113
+ case 'actor':
114
+ return `${message.text} on ${formatEventDateTime(message.createdAt)}`
115
+ }
116
+ }
117
+
118
+ function peopleSystemMessageText(names: string[], overflowCount: number, action: string): string {
91
119
  if (overflowCount > 0) {
92
120
  const overflowLabel = `${overflowCount} ${overflowCount === 1 ? 'other' : 'others'}`
93
121
  return `${names.join(', ')}, and ${overflowLabel} ${action}`
@@ -0,0 +1,67 @@
1
+ import { render } from '@testing-library/react-native'
2
+ import React from 'react'
3
+ import { Text } from 'react-native'
4
+ import type { ConversationResource } from '../../../types'
5
+ import { ConversationActions } from '../conversation_actions'
6
+
7
+ jest.mock('react-native-gesture-handler/ReanimatedSwipeable', () => {
8
+ const { View: MockView } = jest.requireActual('react-native')
9
+ return {
10
+ __esModule: true,
11
+ default: ({
12
+ children,
13
+ renderLeftActions,
14
+ }: {
15
+ children: React.ReactNode
16
+ renderLeftActions: () => React.ReactNode
17
+ }) => (
18
+ <MockView>
19
+ {renderLeftActions()}
20
+ {children}
21
+ </MockView>
22
+ ),
23
+ }
24
+ })
25
+ jest.mock('../../../hooks/use_conversations_actions', () => ({
26
+ useConversationsMute: () => ({ muted: false, setMuted: jest.fn(), isPending: false }),
27
+ useConversationsMarkRead: () => ({ read: false, markRead: jest.fn(), isPending: false }),
28
+ }))
29
+
30
+ const createdAt = '2026-10-01T12:00:00Z'
31
+
32
+ const conversation = (overrides: Partial<ConversationResource>): ConversationResource => ({
33
+ type: 'Conversation',
34
+ id: 7,
35
+ title: 'Youth Group',
36
+ conversationPreview: null,
37
+ createdAt,
38
+ lastMessageCreatedAt: createdAt,
39
+ muted: false,
40
+ repliesDisabled: false,
41
+ unreadCount: 1,
42
+ unreadReaction: false,
43
+ updatedAt: createdAt,
44
+ ...overrides,
45
+ })
46
+
47
+ const renderActions = (overrides: Partial<ConversationResource>) =>
48
+ render(
49
+ <ConversationActions conversation={conversation(overrides)} onPress={jest.fn()}>
50
+ <Text>Youth Group</Text>
51
+ </ConversationActions>
52
+ )
53
+
54
+ describe('ConversationActions', () => {
55
+ it('offers mark read but not mute on an archived conversation', () => {
56
+ const view = renderActions({ disabled: true, disabledReason: 'archived' })
57
+
58
+ expect(view.getByText('Mark read')).toBeTruthy()
59
+ expect(view.queryByText('Silence')).toBeNull()
60
+ })
61
+
62
+ it('offers mute on a conversation disabled for another reason', () => {
63
+ const view = renderActions({ disabled: true, disabledReason: 'safety_check' })
64
+
65
+ expect(view.getByText('Silence')).toBeTruthy()
66
+ })
67
+ })
@@ -0,0 +1,105 @@
1
+ import { render } from '@testing-library/react-native'
2
+ import React from 'react'
3
+ import type { ConversationPreviewData, ConversationResource } from '../../../types'
4
+ import { formatDatePreview } from '../../../utils/date'
5
+ import { ConversationPreview } from '../conversation_preview'
6
+
7
+ jest.mock('../conversation_actions', () => ({
8
+ ConversationActions: ({
9
+ children,
10
+ accessibilityLabel,
11
+ }: {
12
+ children: React.ReactNode
13
+ accessibilityLabel?: string
14
+ }) => {
15
+ const { View: MockView } = jest.requireActual('react-native')
16
+ return <MockView accessibilityLabel={accessibilityLabel}>{children}</MockView>
17
+ },
18
+ }))
19
+
20
+ const createdAt = '2026-03-04T15:30:00Z'
21
+
22
+ const conversation = (
23
+ conversationPreview: ConversationPreviewData,
24
+ overrides: Partial<ConversationResource> = {}
25
+ ): ConversationResource => ({
26
+ type: 'Conversation',
27
+ id: 7,
28
+ title: 'Worship Team',
29
+ conversationPreview,
30
+ createdAt,
31
+ lastMessageCreatedAt: createdAt,
32
+ muted: false,
33
+ repliesDisabled: false,
34
+ unreadCount: 0,
35
+ unreadReaction: false,
36
+ updatedAt: createdAt,
37
+ ...overrides,
38
+ })
39
+
40
+ const messagePreview: ConversationPreviewData = {
41
+ kind: 'message',
42
+ authorName: 'Ada Lovelace',
43
+ value: null,
44
+ text: 'See you Sunday',
45
+ createdAt,
46
+ }
47
+
48
+ const renderPreview = (
49
+ preview: ConversationPreviewData,
50
+ overrides: Partial<ConversationResource> = {}
51
+ ) =>
52
+ render(
53
+ <ConversationPreview conversation={conversation(preview, overrides)} onPress={jest.fn()} />
54
+ )
55
+
56
+ describe('ConversationPreview', () => {
57
+ it('prefixes message previews with the author', () => {
58
+ const view = renderPreview({
59
+ kind: 'message',
60
+ authorName: 'Ada Lovelace',
61
+ value: null,
62
+ text: 'See you Sunday',
63
+ createdAt,
64
+ })
65
+
66
+ expect(view.getByText('Ada Lovelace: See you Sunday')).toBeTruthy()
67
+ })
68
+
69
+ it('shows system previews as their text alone', () => {
70
+ const text = 'This conversation was unarchived by Ada Lovelace'
71
+ const view = renderPreview({
72
+ kind: 'system',
73
+ authorName: 'System',
74
+ value: null,
75
+ text,
76
+ createdAt,
77
+ })
78
+
79
+ expect(view.getByText(text)).toBeTruthy()
80
+ expect(view.queryByText('System', { exact: false })).toBeNull()
81
+ expect(
82
+ view.getByLabelText(
83
+ `Select Worship Team, Latest activity: ${text} at ${formatDatePreview(createdAt)}`
84
+ )
85
+ ).toBeTruthy()
86
+ })
87
+
88
+ it('marks an archived conversation with an archive icon instead of the disabled label', () => {
89
+ const view = renderPreview(messagePreview, { disabled: true, disabledReason: 'archived' })
90
+
91
+ expect(
92
+ view.getByTestId('conversation-archived-icon', { includeHiddenElements: true })
93
+ ).toBeTruthy()
94
+ expect(view.getByLabelText(/^Select Worship Team, Archived,/)).toBeTruthy()
95
+ })
96
+
97
+ it('keeps the disabled label for a conversation disabled for another reason', () => {
98
+ const view = renderPreview(messagePreview, { disabled: true, disabledReason: 'safety_check' })
99
+
100
+ expect(
101
+ view.queryByTestId('conversation-archived-icon', { includeHiddenElements: true })
102
+ ).toBeNull()
103
+ expect(view.getByLabelText(/^Select Worship Team, Disabled,/)).toBeTruthy()
104
+ })
105
+ })
@@ -0,0 +1,93 @@
1
+ import { fireEvent, render } from '@testing-library/react-native'
2
+ import React from 'react'
3
+ import { ConversationFiltersParams } from '../../../screens/conversation_filters/screen_props'
4
+ import { Conversations } from '../conversations'
5
+
6
+ const mockSetParams = jest.fn()
7
+ let mockArgs: ConversationFiltersParams = {}
8
+ let mockFilterDropdownEnabled = false
9
+ let mockHasNextPage = false
10
+
11
+ jest.mock('@react-navigation/native', () => ({
12
+ ...jest.requireActual('@react-navigation/native'),
13
+ useNavigation: () => ({ setParams: mockSetParams, navigate: jest.fn() }),
14
+ }))
15
+ jest.mock('../../../contexts/conversations_context', () => ({
16
+ useConversationsContext: () => ({
17
+ conversations: [{ id: 1, title: 'Youth Group' }],
18
+ isLoading: false,
19
+ isFetched: true,
20
+ isRefetching: false,
21
+ isError: false,
22
+ error: null,
23
+ hasNextPage: mockHasNextPage,
24
+ fetchNextPage: jest.fn(),
25
+ refetch: jest.fn(),
26
+ args: mockArgs,
27
+ }),
28
+ }))
29
+ jest.mock('../../../hooks/use_chat_permissions', () => ({
30
+ useCanCreateConversations: () => false,
31
+ }))
32
+ jest.mock('../../../hooks/use_filter_dropdown_enabled', () => ({
33
+ useFilterDropdownEnabled: () => mockFilterDropdownEnabled,
34
+ }))
35
+ jest.mock('../../../hooks/use_conversations_jolt_events', () => ({
36
+ useConversationsJoltEvents: () => {},
37
+ }))
38
+ jest.mock('../conversation_preview', () => ({
39
+ ConversationPreview: () => null,
40
+ ConversationPreviewSkeleton: () => null,
41
+ }))
42
+ jest.mock('../conversations_blank_state', () => ({
43
+ ConversationsBlankState: () => null,
44
+ }))
45
+
46
+ describe('Conversations archived footer', () => {
47
+ beforeEach(() => {
48
+ mockSetParams.mockClear()
49
+ mockFilterDropdownEnabled = false
50
+ mockHasNextPage = false
51
+ })
52
+
53
+ it('ends the archived list with a way back to active conversations', () => {
54
+ mockArgs = { show_archived: true }
55
+ const view = render(<Conversations />)
56
+
57
+ expect(view.getByText('You’re viewing archived results.')).toBeTruthy()
58
+
59
+ fireEvent.press(view.getByLabelText('View active conversations'))
60
+
61
+ expect(mockSetParams).toHaveBeenCalledWith({
62
+ title: undefined,
63
+ chat_group_graph_id: undefined,
64
+ group_source_app_name: undefined,
65
+ show_direct_messages: undefined,
66
+ show_archived: undefined,
67
+ })
68
+ })
69
+
70
+ it('shows the archived footer instead of the filtered one when the dropdown is on', () => {
71
+ mockArgs = { show_archived: true }
72
+ mockFilterDropdownEnabled = true
73
+ const view = render(<Conversations />)
74
+
75
+ expect(view.getByLabelText('View active conversations')).toBeTruthy()
76
+ expect(view.queryByText('You’re viewing filtered results')).toBeNull()
77
+ })
78
+
79
+ it('waits for the last page before showing the archived footer', () => {
80
+ mockArgs = { show_archived: true }
81
+ mockHasNextPage = true
82
+ const view = render(<Conversations />)
83
+
84
+ expect(view.queryByLabelText('View active conversations')).toBeNull()
85
+ })
86
+
87
+ it('leaves the active list without the archived footer', () => {
88
+ mockArgs = {}
89
+ const view = render(<Conversations />)
90
+
91
+ expect(view.queryByLabelText('View active conversations')).toBeNull()
92
+ })
93
+ })
@@ -0,0 +1,73 @@
1
+ import { fireEvent, render } from '@testing-library/react-native'
2
+ import React from 'react'
3
+ import { ConversationsBlankState } from '../conversations_blank_state'
4
+
5
+ const mockSetParams = jest.fn()
6
+ const mockUseFilterDropdownEnabled = jest.fn()
7
+
8
+ jest.mock('@react-navigation/native', () => ({
9
+ ...jest.requireActual('@react-navigation/native'),
10
+ useNavigation: () => ({ setParams: mockSetParams }),
11
+ }))
12
+
13
+ jest.mock('../../../hooks/use_filter_dropdown_enabled', () => ({
14
+ useFilterDropdownEnabled: () => mockUseFilterDropdownEnabled(),
15
+ }))
16
+
17
+ describe('ConversationsBlankState', () => {
18
+ beforeEach(() => {
19
+ mockSetParams.mockClear()
20
+ })
21
+
22
+ describe('with the filter dropdown on', () => {
23
+ beforeEach(() => {
24
+ mockUseFilterDropdownEnabled.mockReturnValue(true)
25
+ })
26
+
27
+ it('offers to view all conversations when a filter is applied', () => {
28
+ const view = render(
29
+ <ConversationsBlankState isFilterApplied={true} canCreateConversations={true} />
30
+ )
31
+
32
+ expect(view.getByText('No matches')).toBeTruthy()
33
+ expect(view.queryByText('No conversations yet.')).toBeNull()
34
+
35
+ fireEvent.press(view.getByText('View all conversations'))
36
+
37
+ expect(mockSetParams).toHaveBeenCalledTimes(1)
38
+ expect(mockSetParams.mock.calls[0][0]).toStrictEqual({
39
+ title: undefined,
40
+ chat_group_graph_id: undefined,
41
+ group_source_app_name: undefined,
42
+ show_direct_messages: undefined,
43
+ show_archived: undefined,
44
+ })
45
+ })
46
+
47
+ it('keeps the compose prompt when no filter is applied', () => {
48
+ const view = render(
49
+ <ConversationsBlankState isFilterApplied={false} canCreateConversations={true} />
50
+ )
51
+
52
+ expect(view.getByText('No conversations yet.')).toBeTruthy()
53
+ expect(view.getByText('Tap the compose button to get started.')).toBeTruthy()
54
+ expect(view.queryByText('View all conversations')).toBeNull()
55
+ })
56
+ })
57
+
58
+ describe('with the filter dropdown off', () => {
59
+ beforeEach(() => {
60
+ mockUseFilterDropdownEnabled.mockReturnValue(false)
61
+ })
62
+
63
+ it('keeps the adjust-your-filters copy when a filter is applied', () => {
64
+ const view = render(
65
+ <ConversationsBlankState isFilterApplied={true} canCreateConversations={true} />
66
+ )
67
+
68
+ expect(view.getByText('No conversations yet.')).toBeTruthy()
69
+ expect(view.getByText('Adjust your filters to find conversations.')).toBeTruthy()
70
+ expect(view.queryByText('View all conversations')).toBeNull()
71
+ })
72
+ })
73
+ })
@@ -0,0 +1,36 @@
1
+ import React from 'react'
2
+ import { StyleSheet, View } from 'react-native'
3
+ import { Text, TextInlineButton } from '../display'
4
+
5
+ interface ArchivedResultsFooterProps {
6
+ onViewActiveConversations: () => void
7
+ }
8
+
9
+ export function ArchivedResultsFooter({ onViewActiveConversations }: ArchivedResultsFooterProps) {
10
+ return (
11
+ <View style={styles.container}>
12
+ <Text variant="tertiary" style={styles.text}>
13
+ You&rsquo;re viewing archived results.
14
+ </Text>
15
+ <TextInlineButton
16
+ variant="tertiary"
17
+ onPress={onViewActiveConversations}
18
+ accessibilityLabel="View active conversations"
19
+ >
20
+ View active conversations
21
+ </TextInlineButton>
22
+ </View>
23
+ )
24
+ }
25
+
26
+ const styles = StyleSheet.create({
27
+ container: {
28
+ alignItems: 'center',
29
+ gap: 4,
30
+ paddingVertical: 24,
31
+ paddingHorizontal: 16,
32
+ },
33
+ text: {
34
+ textAlign: 'center',
35
+ },
36
+ })