@planningcenter/chat-react-native 3.2.0-rc.0 → 3.2.0-rc.10

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 (337) hide show
  1. package/build/components/conversation/message_form.d.ts +2 -2
  2. package/build/components/conversation/message_form.d.ts.map +1 -1
  3. package/build/components/conversation/message_form.js +95 -41
  4. package/build/components/conversation/message_form.js.map +1 -1
  5. package/build/components/conversation/message_reaction.d.ts +2 -2
  6. package/build/components/conversations/action_toggle_button.d.ts +21 -0
  7. package/build/components/conversations/action_toggle_button.d.ts.map +1 -0
  8. package/build/components/conversations/action_toggle_button.js +48 -0
  9. package/build/components/conversations/action_toggle_button.js.map +1 -0
  10. package/build/components/conversations/conversation_actions.d.ts +10 -0
  11. package/build/components/conversations/conversation_actions.d.ts.map +1 -0
  12. package/build/components/conversations/conversation_actions.js +84 -0
  13. package/build/components/conversations/conversation_actions.js.map +1 -0
  14. package/build/components/conversations/conversation_preview.d.ts +2 -1
  15. package/build/components/conversations/conversation_preview.d.ts.map +1 -1
  16. package/build/components/conversations/conversation_preview.js +27 -9
  17. package/build/components/conversations/conversation_preview.js.map +1 -1
  18. package/build/components/conversations/conversations.d.ts +2 -3
  19. package/build/components/conversations/conversations.d.ts.map +1 -1
  20. package/build/components/conversations/conversations.js +5 -11
  21. package/build/components/conversations/conversations.js.map +1 -1
  22. package/build/components/conversations/mute_indicator.d.ts +5 -0
  23. package/build/components/conversations/mute_indicator.d.ts.map +1 -0
  24. package/build/components/conversations/mute_indicator.js +19 -0
  25. package/build/components/conversations/mute_indicator.js.map +1 -0
  26. package/build/components/conversations/unread_count_badge.d.ts +2 -1
  27. package/build/components/conversations/unread_count_badge.d.ts.map +1 -1
  28. package/build/components/conversations/unread_count_badge.js +9 -1
  29. package/build/components/conversations/unread_count_badge.js.map +1 -1
  30. package/build/components/display/action_button.js +1 -2
  31. package/build/components/display/action_button.js.map +1 -1
  32. package/build/components/display/badge.d.ts +5 -4
  33. package/build/components/display/badge.d.ts.map +1 -1
  34. package/build/components/display/badge.js +5 -2
  35. package/build/components/display/badge.js.map +1 -1
  36. package/build/components/display/button.d.ts +3 -2
  37. package/build/components/display/button.d.ts.map +1 -1
  38. package/build/components/display/button.js.map +1 -1
  39. package/build/components/display/icon.d.ts +14 -1
  40. package/build/components/display/icon.d.ts.map +1 -1
  41. package/build/components/display/icon.js +9 -0
  42. package/build/components/display/icon.js.map +1 -1
  43. package/build/components/display/icon_button.d.ts +2 -2
  44. package/build/components/display/icon_button.d.ts.map +1 -1
  45. package/build/components/display/icon_button.js.map +1 -1
  46. package/build/components/display/index.d.ts +1 -0
  47. package/build/components/display/index.d.ts.map +1 -1
  48. package/build/components/display/index.js +1 -0
  49. package/build/components/display/index.js.map +1 -1
  50. package/build/components/display/person.d.ts +3 -1
  51. package/build/components/display/person.d.ts.map +1 -1
  52. package/build/components/display/person.js +2 -2
  53. package/build/components/display/person.js.map +1 -1
  54. package/build/components/display/text.js.map +1 -1
  55. package/build/components/display/toggle_button.d.ts +43 -0
  56. package/build/components/display/toggle_button.d.ts.map +1 -0
  57. package/build/components/display/toggle_button.js +67 -0
  58. package/build/components/display/toggle_button.js.map +1 -0
  59. package/build/components/display/utils/button_colors.d.ts +3 -3
  60. package/build/components/display/utils/button_colors.d.ts.map +1 -1
  61. package/build/components/display/utils/button_colors.js +1 -1
  62. package/build/components/display/utils/button_colors.js.map +1 -1
  63. package/build/components/page/error_boundary.d.ts +1 -1
  64. package/build/components/primitive/avatar_primitive.d.ts.map +1 -1
  65. package/build/components/primitive/avatar_primitive.js +3 -2
  66. package/build/components/primitive/avatar_primitive.js.map +1 -1
  67. package/build/components/primitive/banner_primitive.d.ts +2 -1
  68. package/build/components/primitive/banner_primitive.d.ts.map +1 -1
  69. package/build/components/primitive/banner_primitive.js +0 -1
  70. package/build/components/primitive/banner_primitive.js.map +1 -1
  71. package/build/contexts/api_provider.js.map +1 -1
  72. package/build/contexts/chat_context.d.ts +2 -0
  73. package/build/contexts/chat_context.d.ts.map +1 -1
  74. package/build/contexts/chat_context.js +6 -1
  75. package/build/contexts/chat_context.js.map +1 -1
  76. package/build/contexts/conversations_context.d.ts +14 -0
  77. package/build/contexts/conversations_context.d.ts.map +1 -0
  78. package/build/contexts/conversations_context.js +38 -0
  79. package/build/contexts/conversations_context.js.map +1 -0
  80. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts +214 -0
  81. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts.map +1 -0
  82. package/build/hooks/groups/use_group_members_for_new_conversation.js +50 -0
  83. package/build/hooks/groups/use_group_members_for_new_conversation.js.map +1 -0
  84. package/build/hooks/use_conversation.d.ts +1 -1
  85. package/build/hooks/use_conversation.d.ts.map +1 -1
  86. package/build/hooks/use_conversation.js +1 -1
  87. package/build/hooks/use_conversation.js.map +1 -1
  88. package/build/hooks/use_conversations.d.ts +6 -32
  89. package/build/hooks/use_conversations.d.ts.map +1 -1
  90. package/build/hooks/use_conversations.js +15 -14
  91. package/build/hooks/use_conversations.js.map +1 -1
  92. package/build/hooks/use_conversations_actions.d.ts +221 -0
  93. package/build/hooks/use_conversations_actions.d.ts.map +1 -0
  94. package/build/hooks/use_conversations_actions.js +93 -0
  95. package/build/hooks/use_conversations_actions.js.map +1 -0
  96. package/build/hooks/use_conversations_cache.d.ts +18 -0
  97. package/build/hooks/use_conversations_cache.d.ts.map +1 -0
  98. package/build/hooks/{use_conversation_jolt_events.js → use_conversations_cache.js} +27 -17
  99. package/build/hooks/use_conversations_cache.js.map +1 -0
  100. package/build/hooks/use_conversations_jolt_events.d.ts +3 -0
  101. package/build/hooks/use_conversations_jolt_events.d.ts.map +1 -0
  102. package/build/hooks/use_conversations_jolt_events.js +12 -0
  103. package/build/hooks/use_conversations_jolt_events.js.map +1 -0
  104. package/build/hooks/use_create_android_ripple_color.d.ts +1 -1
  105. package/build/hooks/use_create_android_ripple_color.d.ts.map +1 -1
  106. package/build/hooks/use_giphy.d.ts +9 -0
  107. package/build/hooks/use_giphy.d.ts.map +1 -0
  108. package/build/hooks/use_giphy.js +63 -0
  109. package/build/hooks/use_giphy.js.map +1 -0
  110. package/build/hooks/use_jolt.d.ts.map +1 -1
  111. package/build/hooks/use_jolt.js +39 -10
  112. package/build/hooks/use_jolt.js.map +1 -1
  113. package/build/hooks/use_message_create.d.ts +11 -0
  114. package/build/hooks/use_message_create.d.ts.map +1 -0
  115. package/build/hooks/use_message_create.js +35 -0
  116. package/build/hooks/use_message_create.js.map +1 -0
  117. package/build/navigation/index.d.ts +24 -7
  118. package/build/navigation/index.d.ts.map +1 -1
  119. package/build/navigation/index.js +26 -9
  120. package/build/navigation/index.js.map +1 -1
  121. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -0
  122. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js.map +1 -0
  123. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  124. package/build/screens/conversation_filters/components/rows.d.ts +2 -1
  125. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  126. package/build/screens/conversation_filters/components/rows.js +19 -14
  127. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  128. package/build/screens/conversation_filters/hooks/filters.js +1 -1
  129. package/build/screens/conversation_filters/hooks/filters.js.map +1 -1
  130. package/build/screens/conversation_new/components/form_list.d.ts +12 -0
  131. package/build/screens/conversation_new/components/form_list.d.ts.map +1 -0
  132. package/build/screens/conversation_new/components/form_list.js +42 -0
  133. package/build/screens/conversation_new/components/form_list.js.map +1 -0
  134. package/build/screens/conversation_new/components/groups_form.d.ts +7 -0
  135. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -0
  136. package/build/screens/conversation_new/components/groups_form.js +128 -0
  137. package/build/screens/conversation_new/components/groups_form.js.map +1 -0
  138. package/build/screens/conversation_new/components/member_error_card.d.ts +5 -0
  139. package/build/screens/conversation_new/components/member_error_card.d.ts.map +1 -0
  140. package/build/screens/conversation_new/components/member_error_card.js +17 -0
  141. package/build/screens/conversation_new/components/member_error_card.js.map +1 -0
  142. package/build/screens/conversation_new/components/source_app_error_card.d.ts +2 -0
  143. package/build/screens/conversation_new/components/source_app_error_card.d.ts.map +1 -0
  144. package/build/screens/conversation_new/components/source_app_error_card.js +16 -0
  145. package/build/screens/conversation_new/components/source_app_error_card.js.map +1 -0
  146. package/build/screens/conversation_new/components/team_form.d.ts +8 -0
  147. package/build/screens/conversation_new/components/team_form.d.ts.map +1 -0
  148. package/build/screens/conversation_new/components/team_form.js +11 -0
  149. package/build/screens/conversation_new/components/team_form.js.map +1 -0
  150. package/build/screens/conversation_new/conversation_new_screen.d.ts +12 -0
  151. package/build/screens/conversation_new/conversation_new_screen.d.ts.map +1 -0
  152. package/build/screens/conversation_new/conversation_new_screen.js +16 -0
  153. package/build/screens/conversation_new/conversation_new_screen.js.map +1 -0
  154. package/build/screens/conversation_new/utils/fake_member_data.d.ts +3 -0
  155. package/build/screens/conversation_new/utils/fake_member_data.d.ts.map +1 -0
  156. package/build/screens/conversation_new/utils/fake_member_data.js +129 -0
  157. package/build/screens/conversation_new/utils/fake_member_data.js.map +1 -0
  158. package/build/screens/conversation_screen.d.ts +1 -0
  159. package/build/screens/conversation_screen.d.ts.map +1 -1
  160. package/build/screens/conversation_screen.js +1 -1
  161. package/build/screens/conversation_screen.js.map +1 -1
  162. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts.map +1 -0
  163. package/build/screens/{create → conversation_select_recipients}/conversation_select_recipients_screen.js +6 -5
  164. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js.map +1 -0
  165. package/build/screens/conversations/components/chat_group_badge.d.ts +3 -0
  166. package/build/screens/conversations/components/chat_group_badge.d.ts.map +1 -0
  167. package/build/screens/conversations/components/chat_group_badge.js +40 -0
  168. package/build/screens/conversations/components/chat_group_badge.js.map +1 -0
  169. package/build/screens/conversations/components/list_header_component.d.ts +3 -0
  170. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -0
  171. package/build/screens/conversations/components/list_header_component.js +92 -0
  172. package/build/screens/conversations/components/list_header_component.js.map +1 -0
  173. package/build/screens/{conversations_screen.d.ts → conversations/conversations_screen.d.ts} +1 -1
  174. package/build/screens/conversations/conversations_screen.d.ts.map +1 -0
  175. package/build/screens/conversations/conversations_screen.js +28 -0
  176. package/build/screens/conversations/conversations_screen.js.map +1 -0
  177. package/build/screens/design_system_screen.d.ts.map +1 -1
  178. package/build/screens/design_system_screen.js +10 -1
  179. package/build/screens/design_system_screen.js.map +1 -1
  180. package/build/screens/message_actions_screen.d.ts +2 -2
  181. package/build/screens/message_actions_screen.d.ts.map +1 -1
  182. package/build/screens/message_actions_screen.js +1 -1
  183. package/build/screens/message_actions_screen.js.map +1 -1
  184. package/build/screens/send_giphy_screen.d.ts +10 -0
  185. package/build/screens/send_giphy_screen.d.ts.map +1 -0
  186. package/build/screens/send_giphy_screen.js +98 -0
  187. package/build/screens/send_giphy_screen.js.map +1 -0
  188. package/build/types/resources/groups/groups_group_resource.d.ts +1 -1
  189. package/build/types/resources/groups/groups_group_resource.js.map +1 -1
  190. package/build/types/resources/groups/groups_member_resource_with_person.d.ts +14 -0
  191. package/build/types/resources/groups/groups_member_resource_with_person.d.ts.map +1 -0
  192. package/build/types/resources/groups/groups_member_resource_with_person.js +2 -0
  193. package/build/types/resources/groups/groups_member_resource_with_person.js.map +1 -0
  194. package/build/types/resources/member.d.ts +0 -10
  195. package/build/types/resources/member.d.ts.map +1 -1
  196. package/build/types/resources/member.js.map +1 -1
  197. package/build/utils/cache/page_mutations.d.ts +18 -0
  198. package/build/utils/cache/page_mutations.d.ts.map +1 -1
  199. package/build/utils/cache/page_mutations.js +13 -0
  200. package/build/utils/cache/page_mutations.js.map +1 -1
  201. package/build/utils/client/client.d.ts +2 -2
  202. package/build/utils/client/client.d.ts.map +1 -1
  203. package/build/utils/client/client.js +12 -4
  204. package/build/utils/client/client.js.map +1 -1
  205. package/build/utils/client/request_helpers.d.ts +15 -8
  206. package/build/utils/client/request_helpers.d.ts.map +1 -1
  207. package/build/utils/client/request_helpers.js +2 -1
  208. package/build/utils/client/request_helpers.js.map +1 -1
  209. package/build/utils/client/transform_request_data.d.ts +11 -6
  210. package/build/utils/client/transform_request_data.d.ts.map +1 -1
  211. package/build/utils/client/transform_request_data.js +1 -1
  212. package/build/utils/client/transform_request_data.js.map +1 -1
  213. package/build/utils/client/transform_response.d.ts +1 -1
  214. package/build/utils/client/transform_response.d.ts.map +1 -1
  215. package/build/utils/client/transform_response.js +2 -0
  216. package/build/utils/client/transform_response.js.map +1 -1
  217. package/build/utils/client/utils.d.ts +3 -3
  218. package/build/utils/client/utils.d.ts.map +1 -1
  219. package/build/utils/client/utils.js +6 -6
  220. package/build/utils/client/utils.js.map +1 -1
  221. package/build/utils/date.d.ts.map +1 -1
  222. package/build/utils/date.js +1 -0
  223. package/build/utils/date.js.map +1 -1
  224. package/build/utils/deepCamelCaseKeys.d.ts.map +1 -1
  225. package/build/utils/deepCamelCaseKeys.js +3 -1
  226. package/build/utils/deepCamelCaseKeys.js.map +1 -1
  227. package/build/utils/parse_simple_markdown.d.ts +1 -1
  228. package/build/utils/parse_simple_markdown.d.ts.map +1 -1
  229. package/build/utils/parse_simple_markdown.js +2 -1
  230. package/build/utils/parse_simple_markdown.js.map +1 -1
  231. package/build/utils/request/conversation.d.ts +1 -3
  232. package/build/utils/request/conversation.d.ts.map +1 -1
  233. package/build/utils/request/conversation.js +37 -30
  234. package/build/utils/request/conversation.js.map +1 -1
  235. package/build/utils/space.js.map +1 -1
  236. package/build/utils/uri.d.ts +2 -2
  237. package/build/utils/uri.d.ts.map +1 -1
  238. package/build/utils/uri.js +2 -2
  239. package/build/utils/uri.js.map +1 -1
  240. package/build/vendor/tapestry/alias_tokens_color_map.d.ts +8 -0
  241. package/build/vendor/tapestry/alias_tokens_color_map.d.ts.map +1 -1
  242. package/build/vendor/tapestry/alias_tokens_color_map.js +8 -0
  243. package/build/vendor/tapestry/alias_tokens_color_map.js.map +1 -1
  244. package/build/vendor/tapestry/tokens.d.ts +2 -0
  245. package/build/vendor/tapestry/tokens.d.ts.map +1 -1
  246. package/build/vendor/tapestry/tokens.js +2 -0
  247. package/build/vendor/tapestry/tokens.js.map +1 -1
  248. package/package.json +8 -6
  249. package/src/__tests__/utils/cache/page_mutations.ts +49 -15
  250. package/src/components/conversation/message_form.tsx +127 -58
  251. package/src/components/conversations/action_toggle_button.tsx +84 -0
  252. package/src/components/conversations/conversation_actions.tsx +146 -0
  253. package/src/components/conversations/conversation_preview.tsx +46 -16
  254. package/src/components/conversations/conversations.tsx +13 -18
  255. package/src/components/conversations/mute_indicator.tsx +21 -0
  256. package/src/components/conversations/unread_count_badge.tsx +8 -1
  257. package/src/components/display/action_button.tsx +1 -2
  258. package/src/components/display/badge.tsx +12 -8
  259. package/src/components/display/button.tsx +3 -3
  260. package/src/components/display/icon.tsx +16 -3
  261. package/src/components/display/icon_button.tsx +2 -2
  262. package/src/components/display/index.ts +1 -0
  263. package/src/components/display/person.tsx +4 -3
  264. package/src/components/display/text.tsx +1 -1
  265. package/src/components/display/toggle_button.tsx +157 -0
  266. package/src/components/display/utils/button_colors.ts +8 -3
  267. package/src/components/primitive/avatar_primitive.tsx +5 -3
  268. package/src/components/primitive/banner_primitive.tsx +2 -3
  269. package/src/contexts/api_provider.tsx +1 -1
  270. package/src/contexts/chat_context.tsx +8 -1
  271. package/src/contexts/conversations_context.tsx +69 -0
  272. package/src/hooks/groups/use_group_members_for_new_conversation.ts +57 -0
  273. package/src/hooks/use_conversation.ts +5 -5
  274. package/src/hooks/use_conversations.ts +34 -16
  275. package/src/hooks/use_conversations_actions.ts +108 -0
  276. package/src/hooks/{use_conversation_jolt_events.ts → use_conversations_cache.ts} +35 -20
  277. package/src/hooks/use_conversations_jolt_events.ts +21 -0
  278. package/src/hooks/use_giphy.ts +97 -0
  279. package/src/hooks/use_jolt.ts +53 -12
  280. package/src/hooks/use_message_create.ts +55 -0
  281. package/src/navigation/index.tsx +32 -9
  282. package/src/screens/conversation_filters/components/conversation_filters.tsx +1 -1
  283. package/src/screens/conversation_filters/components/rows.tsx +44 -14
  284. package/src/screens/conversation_filters/hooks/filters.ts +1 -1
  285. package/src/screens/conversation_new/components/form_list.tsx +67 -0
  286. package/src/screens/conversation_new/components/groups_form.tsx +191 -0
  287. package/src/screens/conversation_new/components/member_error_card.tsx +20 -0
  288. package/src/screens/conversation_new/components/source_app_error_card.tsx +24 -0
  289. package/src/screens/conversation_new/components/team_form.tsx +18 -0
  290. package/src/screens/conversation_new/conversation_new_screen.tsx +26 -0
  291. package/src/screens/conversation_new/utils/fake_member_data.ts +130 -0
  292. package/src/screens/conversation_screen.tsx +2 -1
  293. package/src/screens/{create → conversation_select_recipients}/conversation_select_recipients_screen.tsx +6 -5
  294. package/src/screens/conversations/components/chat_group_badge.tsx +47 -0
  295. package/src/screens/conversations/components/list_header_component.tsx +130 -0
  296. package/src/screens/conversations/conversations_screen.tsx +43 -0
  297. package/src/screens/design_system_screen.tsx +29 -0
  298. package/src/screens/message_actions_screen.tsx +4 -4
  299. package/src/screens/send_giphy_screen.tsx +155 -0
  300. package/src/types/resources/groups/groups_group_resource.ts +1 -1
  301. package/src/types/resources/groups/groups_member_resource_with_person.ts +13 -0
  302. package/src/types/resources/member.ts +0 -11
  303. package/src/utils/cache/page_mutations.ts +22 -0
  304. package/src/utils/client/client.ts +15 -7
  305. package/src/utils/client/request_helpers.ts +15 -6
  306. package/src/utils/client/transform_request_data.ts +13 -4
  307. package/src/utils/client/transform_response.ts +3 -0
  308. package/src/utils/client/types.d.ts +2 -1
  309. package/src/utils/client/utils.ts +13 -12
  310. package/src/utils/date.ts +1 -0
  311. package/src/utils/deepCamelCaseKeys.ts +3 -2
  312. package/src/utils/parse_simple_markdown.ts +3 -1
  313. package/src/utils/request/conversation.ts +39 -34
  314. package/src/utils/space.ts +1 -1
  315. package/src/utils/uri.ts +2 -2
  316. package/src/vendor/tapestry/alias_tokens_color_map.ts +12 -0
  317. package/src/vendor/tapestry/tokens.ts +2 -0
  318. package/build/hooks/use_conversation_jolt_events.d.ts +0 -2
  319. package/build/hooks/use_conversation_jolt_events.d.ts.map +0 -1
  320. package/build/hooks/use_conversation_jolt_events.js.map +0 -1
  321. package/build/screens/conversations_screen.d.ts.map +0 -1
  322. package/build/screens/conversations_screen.js +0 -144
  323. package/build/screens/conversations_screen.js.map +0 -1
  324. package/build/screens/create/conversation_create_screen.d.ts +0 -9
  325. package/build/screens/create/conversation_create_screen.d.ts.map +0 -1
  326. package/build/screens/create/conversation_create_screen.js +0 -123
  327. package/build/screens/create/conversation_create_screen.js.map +0 -1
  328. package/build/screens/create/conversation_filter_recipients_screen.d.ts.map +0 -1
  329. package/build/screens/create/conversation_filter_recipients_screen.js.map +0 -1
  330. package/build/screens/create/conversation_select_recipients_screen.d.ts.map +0 -1
  331. package/build/screens/create/conversation_select_recipients_screen.js.map +0 -1
  332. package/src/screens/conversations_screen.tsx +0 -222
  333. package/src/screens/create/conversation_create_screen.tsx +0 -148
  334. /package/build/screens/{create → conversation_filter_recipients}/conversation_filter_recipients_screen.d.ts +0 -0
  335. /package/build/screens/{create → conversation_filter_recipients}/conversation_filter_recipients_screen.js +0 -0
  336. /package/build/screens/{create → conversation_select_recipients}/conversation_select_recipients_screen.d.ts +0 -0
  337. /package/src/screens/{create → conversation_filter_recipients}/conversation_filter_recipients_screen.tsx +0 -0
@@ -0,0 +1,47 @@
1
+ import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
2
+ import React, { useCallback } from 'react'
3
+ import { StyleSheet, View } from 'react-native'
4
+ import { Badge } from '../../../components'
5
+ import { useApiGet } from '../../../hooks/use_api'
6
+ import { GroupResource } from '../../../types/resources/group_resource'
7
+ import { ConversationScreenProps } from '../conversations_screen'
8
+
9
+ export const ChatGroupBadge = () => {
10
+ const styles = useStyles()
11
+ const navigation = useNavigation()
12
+ const route = useRoute<RouteProp<ConversationScreenProps['route']>>()
13
+ const { chat_group_graph_id } = route.params || {}
14
+ const { data: group } = useApiGet<GroupResource>({
15
+ url: `/me/groups/${chat_group_graph_id}`,
16
+ data: {
17
+ fields: {
18
+ Group: [],
19
+ },
20
+ },
21
+ enabled: !!chat_group_graph_id,
22
+ app: 'chat',
23
+ })
24
+
25
+ const handleBadgePress = useCallback(() => {
26
+ navigation.setParams({
27
+ chat_group_graph_id: undefined,
28
+ group_source_app_name: undefined,
29
+ })
30
+ }, [navigation])
31
+
32
+ if (!group) return null
33
+
34
+ return (
35
+ <View style={styles.row}>
36
+ <Badge iconNameRight="general.x" label={group?.name || ''} onPress={handleBadgePress} />
37
+ </View>
38
+ )
39
+ }
40
+
41
+ const useStyles = () => {
42
+ return StyleSheet.create({
43
+ row: {
44
+ flexDirection: 'row',
45
+ },
46
+ })
47
+ }
@@ -0,0 +1,130 @@
1
+ import { RouteProp, useNavigation, useRoute } from '@react-navigation/native'
2
+ import React, { useMemo } from 'react'
3
+ import { StyleSheet, View } from 'react-native'
4
+ import { Heading, TextButton, ToggleButton } from '../../../components'
5
+ import { useTheme } from '../../../hooks'
6
+ import { useMarkAllRead } from '../../../hooks/use_conversations_actions'
7
+ import { useCanDisplayGroups } from '../../../hooks/use_groups'
8
+ import { ConversationScreenProps } from '../conversations_screen'
9
+ import { ChatGroupBadge } from './chat_group_badge'
10
+
11
+ enum FilterTypes {
12
+ All = 'All',
13
+ Groups = 'Groups',
14
+ Teams = 'Teams',
15
+ More = 'More',
16
+ }
17
+
18
+ export const ListHeaderComponent = () => {
19
+ const styles = useStyles()
20
+ const navigation = useNavigation()
21
+ const canFilterByTeams = useCanDisplayGroups({ source_app_name: 'Services', source_type: 'Team' })
22
+ const canFilterByGroups = useCanDisplayGroups({ source_app_name: 'Groups', source_type: 'Group' })
23
+ const route = useRoute<RouteProp<ConversationScreenProps['route']>>()
24
+ const { chat_group_graph_id, group_source_app_name = '' } = route.params || {}
25
+
26
+ const { markAllRead, isPending } = useMarkAllRead()
27
+
28
+ const active: FilterTypes = useMemo(() => {
29
+ if (chat_group_graph_id) {
30
+ return FilterTypes.More
31
+ } else if (/groups/i.test(group_source_app_name)) {
32
+ return FilterTypes.Groups
33
+ } else if (/services/i.test(group_source_app_name)) {
34
+ return FilterTypes.Teams
35
+ }
36
+
37
+ return FilterTypes.All
38
+ }, [chat_group_graph_id, group_source_app_name])
39
+
40
+ const showAppFilters = canFilterByGroups && canFilterByTeams
41
+
42
+ return (
43
+ <View style={styles.listHeader}>
44
+ <View style={styles.titleRow}>
45
+ <Heading numberOfLines={1} variant="h2">
46
+ Conversations
47
+ </Heading>
48
+ <TextButton onPress={() => markAllRead()} disabled={isPending}>
49
+ Mark all read
50
+ </TextButton>
51
+ </View>
52
+ <View style={styles.filterRow}>
53
+ {showAppFilters && (
54
+ <>
55
+ <ToggleButton
56
+ title={FilterTypes.All}
57
+ active={active === FilterTypes.All}
58
+ onPress={() =>
59
+ navigation.setParams({
60
+ chat_group_graph_id: undefined,
61
+ group_source_app_name: undefined,
62
+ })
63
+ }
64
+ accessibilityLabel="Show all conversations"
65
+ />
66
+ <ToggleButton
67
+ title={FilterTypes.Groups}
68
+ active={active === FilterTypes.Groups}
69
+ onPress={() =>
70
+ navigation.setParams({
71
+ chat_group_graph_id: undefined,
72
+ group_source_app_name: 'Groups',
73
+ })
74
+ }
75
+ accessibilityLabel="Filter to group conversations"
76
+ />
77
+
78
+ <ToggleButton
79
+ title={FilterTypes.Teams}
80
+ active={active === FilterTypes.Teams}
81
+ onPress={() =>
82
+ navigation.setParams({
83
+ chat_group_graph_id: undefined,
84
+ group_source_app_name: 'Services',
85
+ })
86
+ }
87
+ accessibilityLabel="Filter to team conversations"
88
+ />
89
+ </>
90
+ )}
91
+ <ToggleButton
92
+ title={showAppFilters ? FilterTypes.More : 'Filter'}
93
+ onPress={() =>
94
+ navigation.navigate('ConversationFilters', {
95
+ chat_group_graph_id,
96
+ group_source_app_name,
97
+ })
98
+ }
99
+ active={active === FilterTypes.More}
100
+ iconNameRight="general.threeReducingHorizontalBars"
101
+ accessibilityLabel={showAppFilters ? 'View all filters' : 'View more filters'}
102
+ />
103
+ </View>
104
+ <ChatGroupBadge />
105
+ </View>
106
+ )
107
+ }
108
+
109
+ const useStyles = () => {
110
+ const theme = useTheme()
111
+ return StyleSheet.create({
112
+ listHeader: {
113
+ borderBottomWidth: 1,
114
+ borderBottomColor: theme.colors.fillColorNeutral050Base,
115
+ paddingHorizontal: 16,
116
+ paddingBottom: 16,
117
+ gap: 12,
118
+ },
119
+ titleRow: {
120
+ flexDirection: 'row',
121
+ justifyContent: 'space-between',
122
+ paddingTop: 8,
123
+ },
124
+ filterRow: {
125
+ flexDirection: 'row',
126
+ justifyContent: 'flex-start',
127
+ gap: 8,
128
+ },
129
+ })
130
+ }
@@ -0,0 +1,43 @@
1
+ import { StaticScreenProps, useNavigation } from '@react-navigation/native'
2
+ import React from 'react'
3
+ import { StyleSheet, View } from 'react-native'
4
+ import { Conversations } from '../../components'
5
+ import { ActionButton } from '../../components/display/action_button'
6
+ import { ConversationsContextProvider } from '../../contexts/conversations_context'
7
+ import { useCanCreateConversations } from '../../hooks'
8
+ import { GraphId } from '../../types/resources/group_resource'
9
+ import { ListHeaderComponent } from './components/list_header_component'
10
+
11
+ export type ConversationScreenProps = StaticScreenProps<{
12
+ title?: string
13
+ chat_group_graph_id?: GraphId
14
+ group_source_app_name?: string
15
+ }>
16
+
17
+ export function ConversationsScreen({ route }: ConversationScreenProps) {
18
+ const navigation = useNavigation()
19
+ const canCreateConversations = useCanCreateConversations()
20
+ const styles = useStyles()
21
+
22
+ return (
23
+ <View style={styles.container}>
24
+ <ConversationsContextProvider args={route.params}>
25
+ <Conversations ListHeaderComponent={ListHeaderComponent} />
26
+ </ConversationsContextProvider>
27
+ <ActionButton
28
+ visible={canCreateConversations}
29
+ title="New conversation"
30
+ onPress={() => navigation.navigate('New')}
31
+ />
32
+ </View>
33
+ )
34
+ }
35
+
36
+ const useStyles = () => {
37
+ return StyleSheet.create({
38
+ container: {
39
+ flex: 1,
40
+ justifyContent: 'center',
41
+ },
42
+ })
43
+ }
@@ -9,6 +9,7 @@ import {
9
9
  Banner,
10
10
  BannerCollapsible,
11
11
  Button,
12
+ ToggleButton,
12
13
  Heading,
13
14
  Icon,
14
15
  IconButton,
@@ -253,6 +254,7 @@ function HeadingTextSection({ isLast }: SectionProps) {
253
254
 
254
255
  function PressablesSection({ isLast }: SectionProps) {
255
256
  const styles = useStyles()
257
+ const [filterSelected, setFilterSelected] = useState('Groups')
256
258
 
257
259
  return (
258
260
  <CollapsableSection title="Pressables" isLast={isLast}>
@@ -402,6 +404,32 @@ function PressablesSection({ isLast }: SectionProps) {
402
404
  />
403
405
  </Row>
404
406
  </Group>
407
+ <Group
408
+ title="ToggleButton"
409
+ description="Button with active and deactive states. Supports right & left icons, along with standard pressable props."
410
+ >
411
+ <Row>
412
+ <ToggleButton
413
+ onPress={() => setFilterSelected('Groups')}
414
+ title="Groups"
415
+ active={filterSelected === 'Groups'}
416
+ accessibilityLabel="Filter to group conversations"
417
+ />
418
+ <ToggleButton
419
+ onPress={() => setFilterSelected('Teams')}
420
+ title="Teams"
421
+ active={filterSelected === 'Teams'}
422
+ accessibilityLabel="Filter to team conversations"
423
+ />
424
+ <ToggleButton
425
+ onPress={() => setFilterSelected('More')}
426
+ title="More"
427
+ active={filterSelected === 'More'}
428
+ iconNameRight="general.threeReducingHorizontalBars"
429
+ accessibilityLabel="View more filters"
430
+ />
431
+ </Row>
432
+ </Group>
405
433
  <Group
406
434
  title="IconButton"
407
435
  description="Supports different appearances, sizes, along with loading & disabled states. Use `iconStyle` for custom colors and font sizes. Requires `accessibilityLabel` as icon's don't provide context to screen readers."
@@ -700,6 +728,7 @@ function ImageIconsSection({ isLast }: SectionProps) {
700
728
  description="Displays any icon from @planningcenter/icons. Missing icons will fallback to a grey circle. Styling with `fontSize` will allow it to scale with the device's text a11y size."
701
729
  >
702
730
  <Row>
731
+ {/* @ts-expect-error - Icon name is not a string */}
703
732
  <Icon name="missingIcon" size={20} />
704
733
  <Icon name="general.textMessage" size={20} />
705
734
  <Icon name="general.bell" size={20} color={colors.needsDesignPass} />
@@ -22,12 +22,12 @@ export const MessageActionsScreenOptions: NativeStackNavigationOptions = {
22
22
  sheetGrabberVisible: true,
23
23
  }
24
24
 
25
- export type ReactionScreenProps = StaticScreenProps<{
25
+ export type MessageActionsScreenProps = StaticScreenProps<{
26
26
  message_id: string
27
27
  conversation_id: number
28
28
  }>
29
29
 
30
- export function MessageActionsScreen({ route }: ReactionScreenProps) {
30
+ export function MessageActionsScreen({ route }: MessageActionsScreenProps) {
31
31
  const navigation = useNavigation()
32
32
  const { conversation_id, message_id } = route.params
33
33
 
@@ -68,7 +68,7 @@ export function MessageActionsScreen({ route }: ReactionScreenProps) {
68
68
  Object.entries(requestParams.data.fields).map(([k, v]) => [k, v.join(',')])
69
69
  )
70
70
 
71
- return apiClient.chat.post({
71
+ return apiClient.chat.post<ApiResource<MessageResource>>({
72
72
  url,
73
73
  data: {
74
74
  ...requestParams.data,
@@ -91,7 +91,7 @@ export function MessageActionsScreen({ route }: ReactionScreenProps) {
91
91
 
92
92
  const { mutate: handleReaction, isPending } = useMutation({
93
93
  mutationFn: handleReactionPress,
94
- onSuccess: (result: ApiResource<MessageResource>) => {
94
+ onSuccess: result => {
95
95
  const updatedMessage = result.data
96
96
  type QueryData = InfiniteData<ApiCollection<MessageResource>>
97
97
 
@@ -0,0 +1,155 @@
1
+ import { StackActions, StaticScreenProps, useNavigation } from '@react-navigation/native'
2
+ import { NativeStackNavigationOptions } from '@react-navigation/native-stack'
3
+ import React from 'react'
4
+ import { Image as NativeImage, StyleSheet, useWindowDimensions, View } from 'react-native'
5
+ import { useSafeAreaInsets } from 'react-native-safe-area-context'
6
+ import { useTheme } from '../hooks'
7
+ import { useGiphy } from '../hooks/use_giphy'
8
+ import { useMessageCreate } from '../hooks/use_message_create'
9
+ import { Button, IconButton } from '../components'
10
+ import { MAX_FONT_SIZE_MULTIPLIER } from '../utils'
11
+ import { DefaultLoading } from '../components/page/loading'
12
+
13
+ export const SendGiphyScreenOptions: NativeStackNavigationOptions = {
14
+ presentation: 'formSheet',
15
+ headerShown: false,
16
+ sheetAllowedDetents: [0.75],
17
+ sheetGrabberVisible: true,
18
+ }
19
+
20
+ export type SendGiphyScreenProps = StaticScreenProps<{
21
+ conversation_id: number
22
+ search_term: string
23
+ }>
24
+
25
+ export function SendGiphyScreen({ route }: SendGiphyScreenProps) {
26
+ const { conversation_id, search_term } = route.params
27
+ const styles = useStyles()
28
+ const navigation = useNavigation()
29
+
30
+ const { isPending, mutate } = useMessageCreate({ conversationId: conversation_id })
31
+ const { isSearching, result, nextResult, prevResult } = useGiphy(search_term)
32
+ const disabled = isPending || isSearching
33
+
34
+ const { width } = useWindowDimensions()
35
+ const size = width - 24
36
+
37
+ if (!result) return null
38
+
39
+ const gif = result.giphy.fixed_width
40
+ const { url } = gif
41
+
42
+ function goBack({ clearInput = false }) {
43
+ if (clearInput) {
44
+ const routes = navigation.getState()?.routes || []
45
+ const conversationParams = routes.find(r => r.name === 'Conversation')?.params || {}
46
+
47
+ navigation.dispatch(
48
+ StackActions.popTo('Conversation', {
49
+ ...conversationParams,
50
+ conversation_id,
51
+ clear_input: true,
52
+ })
53
+ )
54
+ } else {
55
+ navigation.goBack()
56
+ }
57
+ }
58
+
59
+ function sendGiphy() {
60
+ if (disabled) return
61
+
62
+ mutate({ text: '', attachments: [result] })
63
+ goBack({ clearInput: true })
64
+ }
65
+
66
+ return (
67
+ <View style={styles.container}>
68
+ <NativeImage
69
+ alt="Powered by Giphy"
70
+ style={styles.powered_by_giphy}
71
+ source={require('../../assets/images/powered_by_giphy.png')}
72
+ />
73
+ <View style={styles.control_stack}>
74
+ <View style={styles.button_group}>
75
+ <IconButton
76
+ name="general.leftArrow"
77
+ accessibilityLabel={'Previous GIF'}
78
+ size="md"
79
+ appearance="neutral"
80
+ onPress={prevResult}
81
+ disabled={disabled}
82
+ />
83
+ <IconButton
84
+ name="general.rightArrow"
85
+ accessibilityLabel={'Next GIF'}
86
+ size="md"
87
+ appearance="neutral"
88
+ onPress={nextResult}
89
+ disabled={disabled}
90
+ />
91
+ </View>
92
+ <View style={styles.button_group}>
93
+ <Button
94
+ onPress={() => goBack({ clearInput: false })}
95
+ title="Cancel"
96
+ variant="outline"
97
+ size="sm"
98
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
99
+ />
100
+ <Button
101
+ onPress={sendGiphy}
102
+ title="Send"
103
+ size="sm"
104
+ disabled={disabled}
105
+ maxFontSizeMultiplier={MAX_FONT_SIZE_MULTIPLIER}
106
+ />
107
+ </View>
108
+ </View>
109
+ {isSearching ? (
110
+ <DefaultLoading />
111
+ ) : (
112
+ <NativeImage
113
+ source={{ uri: url }}
114
+ alt={result.title}
115
+ style={[styles.image, { width: size, height: size }]}
116
+ />
117
+ )}
118
+ </View>
119
+ )
120
+ }
121
+
122
+ const useStyles = () => {
123
+ const theme = useTheme()
124
+ const { height } = useWindowDimensions()
125
+ const { bottom } = useSafeAreaInsets()
126
+
127
+ return StyleSheet.create({
128
+ container: {
129
+ justifyContent: 'flex-start',
130
+ paddingTop: 24,
131
+ paddingHorizontal: 12,
132
+ paddingBottom: bottom,
133
+ width: '100%',
134
+ backgroundColor: theme.colors.fillColorNeutral100Inverted,
135
+ height,
136
+ gap: 12,
137
+ },
138
+ powered_by_giphy: {
139
+ width: 200,
140
+ height: 22,
141
+ },
142
+ control_stack: {
143
+ flexDirection: 'row',
144
+ justifyContent: 'space-between',
145
+ alignItems: 'center',
146
+ },
147
+ button_group: {
148
+ flexDirection: 'row',
149
+ gap: 12,
150
+ },
151
+ image: {
152
+ borderRadius: 8,
153
+ },
154
+ })
155
+ }
@@ -1,7 +1,7 @@
1
1
  import { ResourceObject } from '../../api_primitives'
2
2
 
3
3
  export interface GroupsGroupResource extends ResourceObject {
4
- id: string
4
+ id: number
5
5
  type: 'Group'
6
6
  headerImage: {
7
7
  thumbnail: string
@@ -0,0 +1,13 @@
1
+ export interface GroupsGroupMemberResource {
2
+ type: 'Member'
3
+ id: number
4
+ role?: string
5
+ person: {
6
+ firstName: string
7
+ lastName: string
8
+ avatarUrl: string
9
+ child: boolean
10
+ id: number
11
+ type: 'Person'
12
+ }
13
+ }
@@ -8,17 +8,6 @@ export interface MemberResource {
8
8
  role?: string
9
9
  }
10
10
 
11
- export interface MemberResourceWithPerson extends MemberResource {
12
- person: {
13
- firstName: string
14
- lastName: string
15
- avatarUrl: string
16
- child: boolean
17
- id: string
18
- type: 'Person'
19
- }
20
- }
21
-
22
11
  export interface MemberBadge {
23
12
  title: string
24
13
  }
@@ -73,6 +73,28 @@ export function updateOrCreateRecordInPagesData<T extends ResourceObject>({
73
73
  return { ...data, pages: newPages }
74
74
  }
75
75
 
76
+ /**
77
+ * updateOrCreateRecordInPagesData
78
+ * Updates record if found in the cache, otherwise inserts.
79
+ */
80
+ export function updateAllRecordsInPagesData<T extends ResourceObject>({
81
+ data,
82
+ processRecord = r => r,
83
+ }: {
84
+ data?: { pages: ApiCollection<T>[]; pageParams: any }
85
+ processRecord?: (_next: T) => T
86
+ }) {
87
+ if (!data) return data
88
+
89
+ const newPages = data.pages.map(page => {
90
+ const newData = page.data.map(processRecord)
91
+
92
+ return { ...page, data: newData }
93
+ })
94
+
95
+ return { ...data, pages: newPages }
96
+ }
97
+
76
98
  export function addRecordInPagesData<T extends ResourceObject>({
77
99
  data,
78
100
  record,
@@ -54,7 +54,7 @@ export class Client {
54
54
  data: d = { fields: {} },
55
55
  acc = { data: [], included: [], meta: {}, links: {} },
56
56
  ...options
57
- }: WalkRequest) => {
57
+ }: WalkRequest): Promise<ApiCollection | ApiResource> => {
58
58
  return makeRequest({
59
59
  action: 'GET',
60
60
  data: d,
@@ -73,27 +73,35 @@ export class Client {
73
73
  })
74
74
  }
75
75
 
76
- const handler = isWalking ? walkRequest : makeRequest
76
+ const handler = isWalking
77
+ ? (a: MakeRequestArgs | WalkRequest) => walkRequest(a as WalkRequest)
78
+ : (a: MakeRequestArgs | WalkRequest) => makeRequest(a as MakeRequestArgs)
77
79
 
78
- return throwErrorIfFieldsMissing(handler, requestArgs).catch(this.handleNotOk)
80
+ return throwErrorIfFieldsMissing(handler, requestArgs)
81
+ .then(response => response as T)
82
+ .catch(this.handleNotOk)
79
83
  }
80
84
 
81
- async patch(args: PatchRequest) {
85
+ async patch<T extends ApiCollection | ApiResource>(args: PatchRequest): Promise<T> {
82
86
  const headers = { ...this.headers, ...args.headers }
83
87
  const url = this.uri.appUrl(args.url)
84
88
 
85
89
  const requestArgs: MakeRequestArgs = { data: args.data, url, action: 'PATCH', headers }
86
90
 
87
- return ensureNoQueryParamsInDev(makeRequest, requestArgs).catch(this.handleNotOk)
91
+ return ensureNoQueryParamsInDev(makeRequest, requestArgs)
92
+ .then(response => response as T)
93
+ .catch(this.handleNotOk)
88
94
  }
89
95
 
90
- async post(args: PostRequest) {
96
+ async post<T extends ApiCollection | ApiResource>(args: PostRequest): Promise<T> {
91
97
  const headers = { ...this.headers, ...args.headers }
92
98
  const url = this.uri.appUrl(args.url)
93
99
 
94
100
  const requestArgs: MakeRequestArgs = { ...args, data: args.data, url, action: 'POST', headers }
95
101
 
96
- return ensureNoQueryParamsInDev(makeRequest, requestArgs).catch(this.handleNotOk)
102
+ return ensureNoQueryParamsInDev(makeRequest, requestArgs)
103
+ .then(response => response as T)
104
+ .catch(this.handleNotOk)
97
105
  }
98
106
 
99
107
  async delete(args: DeleteRequest) {
@@ -2,7 +2,7 @@ import _ from 'lodash'
2
2
  import URI from 'urijs'
3
3
  import { transformRequestData } from './transform_request_data'
4
4
  import transformResponse from './transform_response'
5
- import { Accumulator, GetRequest, PostRequest, RequestData } from './types'
5
+ import { Accumulator, GetRequest, PostRequest, RequestData, WalkRequest } from './types'
6
6
 
7
7
  export type MakeRequestArgs = {
8
8
  action: 'GET' | 'POST' | 'PATCH' | 'DELETE'
@@ -21,6 +21,7 @@ export const makeRequest = ({ action = 'GET', url, data = {}, headers = {} }: Ma
21
21
  const combinedQuery = Object.entries({ ...query, ...urlQuery })
22
22
  .sort()
23
23
  .reduce((obj, [key, value]) => {
24
+ // @ts-ignore
24
25
  obj[key] = value
25
26
  return obj
26
27
  }, {})
@@ -64,7 +65,14 @@ export const concatRecords = (records: Accumulator, moreRecords: Accumulator) =>
64
65
  meta: _.pick(moreRecords.meta, STANDARD_META_ATTRIBUTES),
65
66
  })
66
67
 
67
- export const throwErrorIfFieldsMissing = async (walk, args) => {
68
+ type Walk = (args: MakeRequestArgs | WalkRequest) => Promise<any>
69
+ type WalkArgs = MakeRequestArgs & {
70
+ data?: {
71
+ fields?: Record<string, any>
72
+ }
73
+ }
74
+
75
+ export const throwErrorIfFieldsMissing = async (walk: Walk, args: WalkArgs) => {
68
76
  const fields = args?.data?.fields
69
77
 
70
78
  if (!fields) {
@@ -89,23 +97,24 @@ export const throwErrorIfFieldsMissing = async (walk, args) => {
89
97
  return transformResponse(response)
90
98
  }
91
99
 
92
- export const friendlyErrors = (walk, args) =>
100
+ export const friendlyErrors = (walk: Walk, args: WalkArgs) =>
93
101
  throwErrorIfQueryParams(args.url)
94
102
  .then(() => throwErrorIfFieldsMissing(walk, args))
95
103
  .then(transformResponse)
96
104
 
97
- export const noQueryParamsFriendlyErrors = (request, args) =>
105
+ export const noQueryParamsFriendlyErrors = (request: typeof makeRequest, args: WalkArgs) =>
98
106
  throwErrorIfQueryParams(args.url)
99
107
  .then(() => request(args))
100
108
  .then(transformResponse)
101
109
 
102
- const passthrough = async (walk, args) => Promise.resolve(transformResponse(await walk(args)))
110
+ const passthrough = async <T, R>(walk: (args: T) => Promise<R>, args: T) =>
111
+ Promise.resolve(transformResponse(await walk(args)))
103
112
 
104
113
  export const ensureFieldsInDev = __DEV__ ? friendlyErrors : passthrough
105
114
 
106
115
  export const ensureNoQueryParamsInDev = __DEV__ ? noQueryParamsFriendlyErrors : passthrough
107
116
 
108
- export const throwErrorIfQueryParams = url => {
117
+ export const throwErrorIfQueryParams = (url: string) => {
109
118
  if (new URI(url).search().length) {
110
119
  throw new Error('Must pass query params as data arg')
111
120
  }