@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
@@ -0,0 +1,76 @@
1
+ import { DefaultTheme, ThemeProvider } from '@react-navigation/native'
2
+ import { fireEvent, render, screen, waitFor } from '@testing-library/react-native'
3
+ import React from 'react'
4
+ import { Platform } from 'react-native'
5
+ import { SafeAreaProvider } from 'react-native-safe-area-context'
6
+ import { FilterContext } from '../../screens/conversation_filters/context/conversation_filter_context'
7
+ import { ConversationFiltersHeader } from '../../screens/conversation_filters_screen'
8
+
9
+ const mockGoBack = jest.fn()
10
+
11
+ jest.mock('@react-navigation/elements', () => ({
12
+ ...jest.requireActual('@react-navigation/elements'),
13
+ useHeaderHeight: () => 0,
14
+ }))
15
+ jest.mock('@react-navigation/native', () => ({
16
+ ...jest.requireActual('@react-navigation/native'),
17
+ useNavigation: () => ({ goBack: mockGoBack }),
18
+ useRoute: () => ({ params: {} }),
19
+ }))
20
+ jest.mock('../../hooks/use_filter_dropdown_enabled', () => ({
21
+ useFilterDropdownEnabled: () => true,
22
+ }))
23
+
24
+ const safeAreaMetrics = {
25
+ frame: { x: 0, y: 0, width: 390, height: 844 },
26
+ insets: { top: 0, right: 0, bottom: 0, left: 0 },
27
+ }
28
+
29
+ const renderHeader = () =>
30
+ render(
31
+ <SafeAreaProvider initialMetrics={safeAreaMetrics}>
32
+ <ThemeProvider value={DefaultTheme}>
33
+ <FilterContext.Provider
34
+ value={{
35
+ params: {},
36
+ scrollOffset: 0,
37
+ setScrollOffset: jest.fn(),
38
+ setFormSheetHeaderHeight: jest.fn(),
39
+ resetFilter: jest.fn(),
40
+ setGroupFilter: jest.fn(),
41
+ setAppFilter: jest.fn(),
42
+ applyFilters: jest.fn(),
43
+ platformListPaddingBottom: 0,
44
+ }}
45
+ >
46
+ <ConversationFiltersHeader />
47
+ </FilterContext.Provider>
48
+ </ThemeProvider>
49
+ </SafeAreaProvider>
50
+ )
51
+
52
+ describe('ConversationFiltersHeader', () => {
53
+ afterEach(() => {
54
+ jest.restoreAllMocks()
55
+ mockGoBack.mockClear()
56
+ })
57
+
58
+ it('shows a back button that dismisses the sheet on Android', async () => {
59
+ jest.replaceProperty(Platform, 'OS', 'android')
60
+
61
+ renderHeader()
62
+
63
+ fireEvent.press(screen.getByLabelText('Back'))
64
+
65
+ await waitFor(() => expect(mockGoBack).toHaveBeenCalledTimes(1))
66
+ })
67
+
68
+ it('does not show a back button on iOS', () => {
69
+ jest.replaceProperty(Platform, 'OS', 'ios')
70
+
71
+ renderHeader()
72
+
73
+ expect(screen.getByText('More filters')).toBeTruthy()
74
+ expect(screen.queryByLabelText('Back')).toBeNull()
75
+ })
76
+ })
@@ -9,6 +9,7 @@ import { ServicesForm } from '../../../../screens/conversation_new/components/se
9
9
  jest.mock('react-native-reanimated', () => ({
10
10
  ...jest.requireActual('react-native-reanimated/mock'),
11
11
  LayoutAnimationConfig: ({ children }: { children: React.ReactNode }) => children,
12
+ useReducedMotion: () => false,
12
13
  }))
13
14
  jest.mock('@react-navigation/native', () => ({
14
15
  ...jest.requireActual('@react-navigation/native'),
@@ -9,7 +9,7 @@ import {
9
9
  MessageActionsScreen,
10
10
  MessageActionsScreenProps,
11
11
  } from '../../screens/message_actions_screen'
12
- import { MessageResource } from '../../types'
12
+ import { ConversationResource, MessageResource } from '../../types'
13
13
  import {
14
14
  AudioAdapter,
15
15
  ChatAdapters,
@@ -36,7 +36,15 @@ const mockMessage: MessageResource = {
36
36
  messageType: 'user',
37
37
  }
38
38
 
39
+ const myMessageWithLinkPreview = {
40
+ ...mockMessage,
41
+ mine: true,
42
+ attachments: [{ type: 'ExpandedLink', id: '9' }],
43
+ } as MessageResource
44
+
39
45
  let mockCurrentMessage = mockMessage
46
+ let mockConversation = { id: 1, disabled: false } as ConversationResource
47
+ let mockEnabledFeatures: string[] = []
40
48
 
41
49
  const mockGoBack = jest.fn()
42
50
  jest.mock('@react-navigation/native', () => ({
@@ -44,9 +52,15 @@ jest.mock('@react-navigation/native', () => ({
44
52
  useNavigation: () => ({ navigate: jest.fn(), dispatch: jest.fn(), goBack: mockGoBack }),
45
53
  }))
46
54
  jest.mock('../../hooks/use_api_client', () => ({ useApiClient: () => ({}) }))
55
+ jest.mock('../../hooks/use_conversation', () => ({
56
+ useConversation: () => ({ data: mockConversation }),
57
+ }))
47
58
  jest.mock('../../hooks/use_features', () => ({
48
59
  ...jest.requireActual('../../hooks/use_features'),
49
- useFeatures: () => ({ features: [], featureEnabled: () => false }),
60
+ useFeatures: () => ({
61
+ features: [],
62
+ featureEnabled: (name: string) => mockEnabledFeatures.includes(name),
63
+ }),
50
64
  }))
51
65
  jest.mock('../../hooks/use_message_reaction_toggle', () => ({
52
66
  useMessageReactionToggle: () => ({ handleReactionToggle: jest.fn(), isPending: false }),
@@ -108,6 +122,55 @@ describe('MessageActionsScreen', () => {
108
122
  beforeEach(() => {
109
123
  jest.clearAllMocks()
110
124
  mockCurrentMessage = mockMessage
125
+ mockConversation = { id: 1, disabled: false } as ConversationResource
126
+ mockEnabledFeatures = []
127
+ })
128
+
129
+ it('offers Delete on my own message', () => {
130
+ mockCurrentMessage = { ...mockMessage, mine: true }
131
+ const { getByText } = renderScreen()
132
+
133
+ expect(getByText('Delete message')).toBeTruthy()
134
+ })
135
+
136
+ it('hides Delete when the conversation is disabled', () => {
137
+ mockCurrentMessage = { ...mockMessage, mine: true }
138
+ mockConversation = { id: 1, disabled: true, disabledReason: 'locked' } as ConversationResource
139
+ const { queryByText, getByText } = renderScreen()
140
+
141
+ expect(queryByText('Delete message')).toBeNull()
142
+ expect(getByText('Copy text')).toBeTruthy()
143
+ })
144
+
145
+ it('offers reactions, reply, edit, and link preview removal on my message', () => {
146
+ mockCurrentMessage = myMessageWithLinkPreview
147
+ const { getByText } = renderScreen()
148
+
149
+ expect(getByText('👍')).toBeTruthy()
150
+ expect(getByText('Reply to message')).toBeTruthy()
151
+ expect(getByText('Edit message')).toBeTruthy()
152
+ expect(getByText('Remove link preview')).toBeTruthy()
153
+ })
154
+
155
+ it('hides reactions, reply, edit, and link preview removal when the conversation is disabled', () => {
156
+ mockCurrentMessage = myMessageWithLinkPreview
157
+ mockConversation = { id: 1, disabled: true, disabledReason: 'archived' } as ConversationResource
158
+ const { getByText, queryByText } = renderScreen()
159
+
160
+ expect(queryByText('👍')).toBeNull()
161
+ expect(queryByText('Reply to message')).toBeNull()
162
+ expect(queryByText('Edit message')).toBeNull()
163
+ expect(queryByText('Remove link preview')).toBeNull()
164
+ expect(getByText('Copy text')).toBeTruthy()
165
+ expect(getByText('View read receipts')).toBeTruthy()
166
+ })
167
+
168
+ it('keeps Report when the conversation is disabled', () => {
169
+ mockEnabledFeatures = ['ROLLOUT_MOBILE_message_reporting']
170
+ mockConversation = { id: 1, disabled: true, disabledReason: 'archived' } as ConversationResource
171
+ const { getByText } = renderScreen()
172
+
173
+ expect(getByText('Report message')).toBeTruthy()
111
174
  })
112
175
 
113
176
  it('copies the message text and gives success haptic feedback before closing', async () => {
@@ -0,0 +1,102 @@
1
+ import { HeaderHeightContext } from '@react-navigation/elements'
2
+ import { DefaultTheme, ThemeProvider } from '@react-navigation/native'
3
+ import { QueryClientProvider, notifyManager } from '@tanstack/react-query'
4
+ import { act, fireEvent, render, screen } from '@testing-library/react-native'
5
+ import React from 'react'
6
+ import { SafeAreaProvider } from 'react-native-safe-area-context'
7
+ import { chatQueryClient } from '../../contexts/api_provider'
8
+ import { SendGiphyScreen, SendGiphyScreenProps } from '../../screens/send_giphy_screen'
9
+
10
+ jest.mock('../../contexts/api_provider', () => {
11
+ const { buildTestQueryClient } = require('../../__utils__/query_client')
12
+ return { chatQueryClient: buildTestQueryClient() }
13
+ })
14
+
15
+ const mockPost = jest.fn()
16
+ jest.mock('../../hooks/use_api_client', () => ({
17
+ useApiClient: () => ({ chat: { post: mockPost, patch: jest.fn() } }),
18
+ }))
19
+
20
+ jest.mock('../../hooks/use_current_person', () => ({
21
+ useCurrentPerson: () => ({ type: 'Person', id: 1, name: 'Me', avatar: null }),
22
+ }))
23
+
24
+ jest.mock('../../hooks/use_giphy', () => ({
25
+ useGiphy: () => ({
26
+ isSearching: false,
27
+ result: { type: 'giphy', title: 'cat', giphy: { fixed_width: { url: 'https://gif' } } },
28
+ nextResult: jest.fn(),
29
+ prevResult: jest.fn(),
30
+ }),
31
+ }))
32
+
33
+ const mockDispatch = jest.fn()
34
+ jest.mock('@react-navigation/native', () => ({
35
+ ...jest.requireActual('@react-navigation/native'),
36
+ useNavigation: () => ({
37
+ dispatch: mockDispatch,
38
+ goBack: jest.fn(),
39
+ getState: () => ({
40
+ routes: [
41
+ { name: 'Conversation', params: { conversation_id: 7 } },
42
+ { name: 'ConversationReply', params: { conversation_id: 7, reply_root_id: '42' } },
43
+ { name: 'SendGiphy' },
44
+ ],
45
+ }),
46
+ }),
47
+ }))
48
+
49
+ notifyManager.setNotifyFunction(fn => act(fn))
50
+
51
+ const safeAreaMetrics = {
52
+ frame: { x: 0, y: 0, width: 390, height: 844 },
53
+ insets: { top: 0, right: 0, bottom: 0, left: 0 },
54
+ }
55
+
56
+ describe('SendGiphyScreen', () => {
57
+ let finishSend: (value: unknown) => void
58
+
59
+ beforeEach(() => {
60
+ chatQueryClient.clear()
61
+ mockDispatch.mockReset()
62
+ mockPost.mockReset().mockReturnValue(new Promise(resolve => (finishSend = resolve)))
63
+ })
64
+
65
+ afterEach(async () => {
66
+ await act(async () => finishSend({ data: { type: 'Message', id: 'sent', mine: true } }))
67
+ })
68
+
69
+ it('sends from a reply thread as a reply and returns to the thread', async () => {
70
+ const route = {
71
+ params: { conversation_id: 7, reply_root_id: '42', search_term: 'cat' },
72
+ } as unknown as SendGiphyScreenProps['route']
73
+
74
+ render(
75
+ <QueryClientProvider client={chatQueryClient}>
76
+ <SafeAreaProvider initialMetrics={safeAreaMetrics}>
77
+ <ThemeProvider value={DefaultTheme}>
78
+ <HeaderHeightContext.Provider value={0}>
79
+ <SendGiphyScreen route={route} />
80
+ </HeaderHeightContext.Provider>
81
+ </ThemeProvider>
82
+ </SafeAreaProvider>
83
+ </QueryClientProvider>
84
+ )
85
+
86
+ await act(async () => {
87
+ fireEvent.press(screen.getByLabelText('Send Giphy'))
88
+ })
89
+
90
+ const [{ data }] = mockPost.mock.calls[0]
91
+ expect(data.data.attributes.reply_root).toEqual({ id: '42' })
92
+ expect(mockDispatch).toHaveBeenCalledWith(
93
+ expect.objectContaining({
94
+ type: 'POP_TO',
95
+ payload: expect.objectContaining({
96
+ name: 'ConversationReply',
97
+ params: expect.objectContaining({ reply_root_id: '42', clear_input: true }),
98
+ }),
99
+ })
100
+ )
101
+ })
102
+ })
@@ -18,62 +18,49 @@ const makeMessage = (overrides: Partial<MessageResource> = {}): MessageResource
18
18
  messageType: 'user',
19
19
  personIdsForSystemEvent: null,
20
20
  systemTextParts: null,
21
+ systemTextFormat: null,
21
22
  ...overrides,
22
23
  })
23
24
 
25
+ const joinedParts = { names: ['Alice'], overflowCount: 0, action: 'joined the conversation' }
26
+
24
27
  describe('isSystemMessage', () => {
25
- it('returns true for user_joined messages', () => {
28
+ it('returns true for people messages with names and person ids', () => {
26
29
  const message = makeMessage({
27
30
  messageType: 'user_joined',
31
+ systemTextFormat: 'people',
28
32
  personIdsForSystemEvent: [1],
29
- systemTextParts: { names: ['Alice'], overflowCount: 0, action: 'joined the conversation' },
33
+ systemTextParts: joinedParts,
30
34
  })
31
35
  expect(isSystemMessage(message)).toBe(true)
32
36
  })
33
37
 
34
- it('narrows the type so systemTextParts and personIdsForSystemEvent are non-null', () => {
38
+ it('returns true for actor messages of a type the client does not know', () => {
35
39
  const message = makeMessage({
36
- messageType: 'user_joined',
37
- personIdsForSystemEvent: [1, 2],
38
- systemTextParts: {
39
- names: ['Alice', 'Bob'],
40
- overflowCount: 0,
41
- action: 'joined the conversation',
42
- },
40
+ messageType: 'some_future_type',
41
+ systemTextFormat: 'actor',
42
+ text: 'This conversation was archived by Alice',
43
43
  })
44
- if (isSystemMessage(message)) {
45
- expect(message.systemTextParts.names).toEqual(['Alice', 'Bob'])
46
- expect(message.personIdsForSystemEvent).toEqual([1, 2])
47
- } else {
48
- throw new Error('Expected isSystemMessage to return true')
49
- }
44
+ expect(isSystemMessage(message)).toBe(true)
50
45
  })
51
46
 
52
- it('returns false for regular user messages', () => {
53
- const message = makeMessage({ messageType: 'user' })
47
+ it('returns false for messages without a system text format', () => {
48
+ const message = makeMessage({ messageType: 'user_joined', systemTextParts: joinedParts })
54
49
  expect(isSystemMessage(message)).toBe(false)
55
50
  })
56
51
 
57
- it('returns false for unknown message types', () => {
58
- const message = makeMessage({ messageType: 'some_future_type' })
52
+ it('returns false for people messages without systemTextParts', () => {
53
+ const message = makeMessage({ systemTextFormat: 'people', personIdsForSystemEvent: [1] })
59
54
  expect(isSystemMessage(message)).toBe(false)
60
55
  })
61
56
 
62
- it('returns false when systemTextParts is null', () => {
63
- const message = makeMessage({
64
- messageType: 'user_joined',
65
- personIdsForSystemEvent: [1],
66
- systemTextParts: null,
67
- })
57
+ it('returns false for people messages without personIdsForSystemEvent', () => {
58
+ const message = makeMessage({ systemTextFormat: 'people', systemTextParts: joinedParts })
68
59
  expect(isSystemMessage(message)).toBe(false)
69
60
  })
70
61
 
71
- it('returns false when personIdsForSystemEvent is null', () => {
72
- const message = makeMessage({
73
- messageType: 'user_joined',
74
- personIdsForSystemEvent: null,
75
- systemTextParts: { names: ['Alice'], overflowCount: 0, action: 'joined the conversation' },
76
- })
62
+ it.each([null, ''])('returns false for actor messages with text %p', text => {
63
+ const message = makeMessage({ systemTextFormat: 'actor', text })
77
64
  expect(isSystemMessage(message)).toBe(false)
78
65
  })
79
66
  })
@@ -5,7 +5,7 @@ import {
5
5
  QueryClient,
6
6
  QueryClientProvider,
7
7
  } from '@tanstack/react-query'
8
- import { act, render, screen } from '@testing-library/react-native'
8
+ import { act, fireEvent, render, screen } from '@testing-library/react-native'
9
9
  import React from 'react'
10
10
  import { FlatList } from 'react-native'
11
11
  import { buildTestQueryClient } from '../../../__utils__/query_client'
@@ -37,9 +37,18 @@ jest.mock('../../../hooks/use_animated_message_background_color', () => ({
37
37
  handleMessagePressOut: jest.fn(),
38
38
  }),
39
39
  }))
40
+ const mockNavigate = jest.fn()
40
41
  jest.mock('@react-navigation/native', () => ({
41
42
  ...jest.requireActual('@react-navigation/native'),
42
- useNavigation: () => ({ navigate: jest.fn() }),
43
+ useNavigation: () => ({ navigate: mockNavigate }),
44
+ }))
45
+ const mockToggleReaction = jest.fn()
46
+ jest.mock('../../../hooks/use_message_reaction_toggle', () => ({
47
+ useMessageReactionToggle: () => ({ handleReactionToggle: mockToggleReaction, isPending: false }),
48
+ }))
49
+ jest.mock('../../../utils/native_adapters', () => ({
50
+ ...jest.requireActual('../../../utils/native_adapters'),
51
+ Haptic: { impactLight: jest.fn() },
43
52
  }))
44
53
  // Every row calls this hook on each render, so its calls count row renders.
45
54
  jest.mock('../../../hooks/use_live_relative_time', () => {
@@ -293,6 +302,63 @@ describe('MessageList', () => {
293
302
  expect(renderedRowIds()).toEqual([])
294
303
  })
295
304
 
305
+ describe('in a disabled conversation', () => {
306
+ const reacted = buildMessage(1, {
307
+ reactionCounts: [
308
+ {
309
+ type: 'ReactionCount',
310
+ id: 'heart',
311
+ messageId: messageId(1),
312
+ value: 'heart',
313
+ count: 1,
314
+ mine: 0,
315
+ authorIds: [OTHER],
316
+ },
317
+ ],
318
+ })
319
+ const archived = buildMessage(2, {
320
+ text: 'This conversation was archived by Ann',
321
+ systemTextFormat: 'actor',
322
+ })
323
+ const disable = () => act(() => setHarnessConversation({ ...conversation, disabled: true }))
324
+
325
+ it('toggles a reaction pill while the conversation is active', () => {
326
+ renderList([reacted])
327
+
328
+ fireEvent.press(screen.getByTestId(`reaction-${reacted.id}-heart`))
329
+
330
+ expect(mockToggleReaction).toHaveBeenCalledWith({ value: 'heart', mine: false })
331
+ })
332
+
333
+ it('keeps reaction pills read-only but still shows who reacted', () => {
334
+ renderList([reacted])
335
+ disable()
336
+ const pill = screen.getByTestId(`reaction-${reacted.id}-heart`)
337
+
338
+ fireEvent.press(pill)
339
+ fireEvent(pill, 'longPress')
340
+
341
+ expect(mockToggleReaction).not.toHaveBeenCalled()
342
+ expect(mockNavigate).toHaveBeenCalledWith('Reactions', expect.anything())
343
+ })
344
+
345
+ it('opens message actions on a system message only while the conversation is active', () => {
346
+ queryClient.setQueryData<MessagesQueryData>(messagesQueryKey, {
347
+ pages: [{ data: [archived], links: {}, meta: { count: 1, totalCount: 1 } }],
348
+ pageParams: [{}],
349
+ })
350
+ render(<Harness />, { wrapper: Wrapper })
351
+ fireEvent(screen.getByText(/archived by Ann/), 'longPress')
352
+ expect(mockNavigate).toHaveBeenCalledWith('MessageActions', expect.anything())
353
+
354
+ mockNavigate.mockClear()
355
+ disable()
356
+ fireEvent(screen.getByText(/archived by Ann/), 'longPress')
357
+
358
+ expect(mockNavigate).not.toHaveBeenCalled()
359
+ })
360
+ })
361
+
296
362
  describe('opened at an anchor message', () => {
297
363
  const anchor = messages[4]
298
364
 
@@ -0,0 +1,106 @@
1
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
2
+ import { render } from '@testing-library/react-native'
3
+ import React from 'react'
4
+ import { buildTestQueryClient } from '../../../__utils__/query_client'
5
+ import { ChatProvider } from '../../../contexts/chat_context'
6
+ import type { PersonResource } from '../../../types/resources/person'
7
+ import type { SystemMessageResource } from '../../../utils/system_messages'
8
+ import { SystemMessage } from '../system_message'
9
+
10
+ jest.mock('@react-navigation/native', () => ({
11
+ useNavigation: () => ({ navigate: jest.fn() }),
12
+ }))
13
+ jest.mock('../../../hooks/use_animated_message_background_color', () => ({
14
+ useAnimatedMessageBackgroundColor: () => ({
15
+ animatedBackgroundColor: {},
16
+ handleMessagePressIn: jest.fn(),
17
+ handleMessagePressOut: jest.fn(),
18
+ }),
19
+ }))
20
+
21
+ const author = { id: 1, type: 'Person', name: 'Wes', avatar: null } as unknown as PersonResource
22
+
23
+ const systemMessage = (overrides: Partial<SystemMessageResource>): SystemMessageResource =>
24
+ ({
25
+ type: 'Message',
26
+ id: '01',
27
+ text: null,
28
+ html: '',
29
+ createdAt: '2026-02-03T14:18:00',
30
+ deletedAt: null,
31
+ textEditedAt: null,
32
+ mine: false,
33
+ attachments: [],
34
+ author,
35
+ reactionCounts: [],
36
+ replyCount: 0,
37
+ replyRootId: null,
38
+ messageType: 'user_joined',
39
+ personIdsForSystemEvent: null,
40
+ systemTextParts: null,
41
+ ...overrides,
42
+ }) as SystemMessageResource
43
+
44
+ let queryClient: QueryClient
45
+
46
+ const Wrapper = ({ children }: { children: React.ReactNode }) => (
47
+ <QueryClientProvider client={queryClient}>
48
+ <ChatProvider
49
+ value={{
50
+ token: {
51
+ access_token: '',
52
+ created_at: 0,
53
+ expires_in: 0,
54
+ scope: '',
55
+ refresh_token: '',
56
+ token_type: '',
57
+ },
58
+ onUnauthorizedResponse: () => {},
59
+ theme: { theme: { colors: { interaction: 'rgb(0, 0, 255)' } } },
60
+ }}
61
+ >
62
+ {children}
63
+ </ChatProvider>
64
+ </QueryClientProvider>
65
+ )
66
+
67
+ const renderSystemMessage = (message: SystemMessageResource) =>
68
+ render(<SystemMessage message={message} conversationId={1} conversationDisabled={false} />, {
69
+ wrapper: Wrapper,
70
+ })
71
+
72
+ beforeEach(() => {
73
+ jest.useFakeTimers({ now: new Date(2026, 5, 15, 12, 0) })
74
+ queryClient = buildTestQueryClient()
75
+ })
76
+
77
+ afterEach(() => {
78
+ queryClient.clear()
79
+ jest.useRealTimers()
80
+ })
81
+
82
+ describe('SystemMessage', () => {
83
+ it('renders actor messages as their text followed by the local date and time', () => {
84
+ const view = renderSystemMessage(
85
+ systemMessage({
86
+ messageType: 'conversation_archived',
87
+ systemTextFormat: 'actor',
88
+ text: 'This conversation was archived by Wes',
89
+ })
90
+ )
91
+
92
+ expect(view.getByText('This conversation was archived by Wes on Feb 3 at 2:18pm')).toBeTruthy()
93
+ })
94
+
95
+ it('builds people messages from their names', () => {
96
+ const view = renderSystemMessage(
97
+ systemMessage({
98
+ systemTextFormat: 'people',
99
+ systemTextParts: { names: ['Ann', 'Bo'], overflowCount: 0, action: 'joined' },
100
+ personIdsForSystemEvent: [1, 2],
101
+ })
102
+ )
103
+
104
+ expect(view.getByText('Ann and Bo joined')).toBeTruthy()
105
+ })
106
+ })
@@ -8,7 +8,7 @@ import Animated, {
8
8
  ReduceMotion,
9
9
  withSpring,
10
10
  } from 'react-native-reanimated'
11
- import { useTheme } from '../../hooks'
11
+ import { useReduceMotion, useTheme } from '../../hooks'
12
12
  import { platformFontWeightMedium } from '../../utils'
13
13
  import { Icon, Text } from '../display'
14
14
 
@@ -20,6 +20,7 @@ interface JumpToBottomButtonProps {
20
20
  export const JumpToBottomButton = ({ onPress, visible }: JumpToBottomButtonProps) => {
21
21
  const styles = useStyles()
22
22
  const progress = useSharedValue(0)
23
+ const reduceMotion = useReduceMotion()
23
24
 
24
25
  useEffect(() => {
25
26
  progress.value = withSpring(visible ? 1 : 0, {
@@ -27,9 +28,9 @@ export const JumpToBottomButton = ({ onPress, visible }: JumpToBottomButtonProps
27
28
  damping: 16,
28
29
  stiffness: 170,
29
30
  overshootClamping: false,
30
- reduceMotion: ReduceMotion.System,
31
+ reduceMotion: reduceMotion ? ReduceMotion.Always : ReduceMotion.Never,
31
32
  })
32
- }, [visible, progress])
33
+ }, [visible, progress, reduceMotion])
33
34
 
34
35
  const animatedStyle = useAnimatedStyle(() => {
35
36
  return {
@@ -43,6 +43,7 @@ import { TheirReplyConnector, MyReplyConnector, AVATAR_CONNECTOR_SPACING } from
43
43
  */
44
44
  interface MessageProps extends MessageResource {
45
45
  canDeleteNonAuthoredMessages: boolean
46
+ conversationDisabled: boolean
46
47
  conversation_id: number
47
48
  readByOthers?: boolean
48
49
  inReplyScreen?: boolean
@@ -52,6 +53,7 @@ interface MessageProps extends MessageResource {
52
53
 
53
54
  export const Message = memo(function MessageRow({
54
55
  canDeleteNonAuthoredMessages,
56
+ conversationDisabled,
55
57
  conversation_id,
56
58
  readByOthers,
57
59
  inReplyScreen,
@@ -296,6 +298,7 @@ export const Message = memo(function MessageRow({
296
298
  onLongPress={handleReactionLongPress}
297
299
  message={message}
298
300
  conversationId={conversation_id}
301
+ disabled={conversationDisabled}
299
302
  />
300
303
  ))}
301
304
  </View>
@@ -214,18 +214,20 @@ function MessageFormRoot({
214
214
  if (!Keyboard.isVisible() || Platform.OS === 'ios') {
215
215
  navigation.navigate('SendGiphy', {
216
216
  conversation_id: conversation.id,
217
+ reply_root_id: replyRootId,
217
218
  search_term: text,
218
219
  })
219
220
  } else {
220
221
  const keyboardListener = Keyboard.addListener('keyboardDidHide', () => {
221
222
  navigation.navigate('SendGiphy', {
222
223
  conversation_id: conversation.id,
224
+ reply_root_id: replyRootId,
223
225
  search_term: text,
224
226
  })
225
227
  keyboardListener?.remove()
226
228
  })
227
229
  }
228
- }, [conversation.id, navigation, text])
230
+ }, [conversation.id, navigation, replyRootId, text])
229
231
 
230
232
  const catchingUp = useRef(false)
231
233
 
@@ -72,6 +72,7 @@ export function MessageList({
72
72
  const inReplyScreen = !!replyRootId
73
73
  const canDeleteNonAuthoredMessages =
74
74
  conversation.memberAbility?.canDeleteNonAuthoredMessages ?? false
75
+ const conversationDisabled = conversation.disabled ?? false
75
76
  const latestRead = conversation.latestReadMessageSortKey
76
77
  const messagesWithSeparators = groupMessages({ ms: messages, inReplyScreen })
77
78
  const anchorIndex = anchorMessageId
@@ -193,7 +194,13 @@ export function MessageList({
193
194
  }
194
195
 
195
196
  if (isSystemMessage(item)) {
196
- return <SystemMessage message={item} conversationId={conversationId} />
197
+ return (
198
+ <SystemMessage
199
+ message={item}
200
+ conversationId={conversationId}
201
+ conversationDisabled={conversationDisabled}
202
+ />
203
+ )
197
204
  }
198
205
 
199
206
  const readByOthers = item.mine && !!latestRead && item.id <= latestRead
@@ -201,6 +208,7 @@ export function MessageList({
201
208
  <Message
202
209
  {...item}
203
210
  canDeleteNonAuthoredMessages={canDeleteNonAuthoredMessages}
211
+ conversationDisabled={conversationDisabled}
204
212
  conversation_id={conversationId}
205
213
  readByOthers={readByOthers}
206
214
  inReplyScreen={inReplyScreen}