@planningcenter/chat-react-native 3.2.0-rc.9 → 3.3.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 (362) hide show
  1. package/build/components/conversation/message_form/message_form_attachment_image.d.ts +13 -0
  2. package/build/components/conversation/message_form/message_form_attachment_image.d.ts.map +1 -0
  3. package/build/components/conversation/message_form/message_form_attachment_image.js +78 -0
  4. package/build/components/conversation/message_form/message_form_attachment_image.js.map +1 -0
  5. package/build/components/conversation/message_form.d.ts.map +1 -1
  6. package/build/components/conversation/message_form.js +128 -16
  7. package/build/components/conversation/message_form.js.map +1 -1
  8. package/build/components/conversations/conversation_actions.d.ts +2 -2
  9. package/build/components/conversations/conversation_actions.d.ts.map +1 -1
  10. package/build/components/conversations/conversation_actions.js.map +1 -1
  11. package/build/components/conversations/conversation_preview.d.ts +3 -1
  12. package/build/components/conversations/conversation_preview.d.ts.map +1 -1
  13. package/build/components/conversations/conversation_preview.js +2 -2
  14. package/build/components/conversations/conversation_preview.js.map +1 -1
  15. package/build/components/display/action_button.d.ts +2 -1
  16. package/build/components/display/action_button.d.ts.map +1 -1
  17. package/build/components/display/action_button.js +3 -4
  18. package/build/components/display/action_button.js.map +1 -1
  19. package/build/components/display/banner.d.ts +6 -1
  20. package/build/components/display/banner.d.ts.map +1 -1
  21. package/build/components/display/banner.js +2 -2
  22. package/build/components/display/banner.js.map +1 -1
  23. package/build/components/display/banner_collapsible.d.ts +1 -1
  24. package/build/components/display/banner_collapsible.d.ts.map +1 -1
  25. package/build/components/display/banner_collapsible.js +2 -2
  26. package/build/components/display/banner_collapsible.js.map +1 -1
  27. package/build/components/display/child_notice.d.ts +3 -1
  28. package/build/components/display/child_notice.d.ts.map +1 -1
  29. package/build/components/display/child_notice.js +2 -2
  30. package/build/components/display/child_notice.js.map +1 -1
  31. package/build/components/group_conversation_list.d.ts +19 -0
  32. package/build/components/group_conversation_list.d.ts.map +1 -0
  33. package/build/components/group_conversation_list.js +48 -0
  34. package/build/components/group_conversation_list.js.map +1 -0
  35. package/build/components/index.d.ts +1 -0
  36. package/build/components/index.d.ts.map +1 -1
  37. package/build/components/index.js +1 -0
  38. package/build/components/index.js.map +1 -1
  39. package/build/components/primitive/banner_primitive.d.ts +3 -0
  40. package/build/components/primitive/banner_primitive.d.ts.map +1 -1
  41. package/build/components/primitive/banner_primitive.js +4 -4
  42. package/build/components/primitive/banner_primitive.js.map +1 -1
  43. package/build/contexts/api_provider.d.ts +1 -1
  44. package/build/contexts/api_provider.d.ts.map +1 -1
  45. package/build/contexts/api_provider.js +3 -3
  46. package/build/contexts/api_provider.js.map +1 -1
  47. package/build/contexts/chat_context.d.ts +4 -4
  48. package/build/contexts/chat_context.d.ts.map +1 -1
  49. package/build/contexts/chat_context.js +3 -3
  50. package/build/contexts/chat_context.js.map +1 -1
  51. package/build/contexts/conversations_context.js +1 -1
  52. package/build/contexts/conversations_context.js.map +1 -1
  53. package/build/hooks/attachments/supported_extensions.d.ts +2 -0
  54. package/build/hooks/attachments/supported_extensions.d.ts.map +1 -0
  55. package/build/hooks/attachments/supported_extensions.js +48 -0
  56. package/build/hooks/attachments/supported_extensions.js.map +1 -0
  57. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts +235 -0
  58. package/build/hooks/groups/use_group_members_for_new_conversation.d.ts.map +1 -0
  59. package/build/hooks/groups/use_group_members_for_new_conversation.js +55 -0
  60. package/build/hooks/groups/use_group_members_for_new_conversation.js.map +1 -0
  61. package/build/hooks/groups/use_groups_conversation_create.d.ts +9 -0
  62. package/build/hooks/groups/use_groups_conversation_create.d.ts.map +1 -0
  63. package/build/hooks/groups/use_groups_conversation_create.js +36 -0
  64. package/build/hooks/groups/use_groups_conversation_create.js.map +1 -0
  65. package/build/hooks/index.d.ts +4 -0
  66. package/build/hooks/index.d.ts.map +1 -1
  67. package/build/hooks/index.js +4 -0
  68. package/build/hooks/index.js.map +1 -1
  69. package/build/hooks/use_api.d.ts +43 -43
  70. package/build/hooks/use_api.d.ts.map +1 -1
  71. package/build/hooks/use_api.js +5 -0
  72. package/build/hooks/use_api.js.map +1 -1
  73. package/build/hooks/use_api_client.d.ts.map +1 -1
  74. package/build/hooks/use_api_client.js +5 -3
  75. package/build/hooks/use_api_client.js.map +1 -1
  76. package/build/hooks/use_attachment_uploader.d.ts +26 -0
  77. package/build/hooks/use_attachment_uploader.d.ts.map +1 -0
  78. package/build/hooks/use_attachment_uploader.js +111 -0
  79. package/build/hooks/use_attachment_uploader.js.map +1 -0
  80. package/build/hooks/use_chat_permissions.d.ts +14 -14
  81. package/build/hooks/use_conversation.d.ts.map +1 -1
  82. package/build/hooks/use_conversation.js +1 -0
  83. package/build/hooks/use_conversation.js.map +1 -1
  84. package/build/hooks/use_conversations_actions.d.ts.map +1 -1
  85. package/build/hooks/use_conversations_actions.js +10 -0
  86. package/build/hooks/use_conversations_actions.js.map +1 -1
  87. package/build/hooks/use_conversations_jolt_events.d.ts.map +1 -1
  88. package/build/hooks/use_conversations_jolt_events.js +4 -1
  89. package/build/hooks/use_conversations_jolt_events.js.map +1 -1
  90. package/build/hooks/use_current_person.d.ts +15 -0
  91. package/build/hooks/use_current_person.d.ts.map +1 -1
  92. package/build/hooks/use_current_person.js +26 -9
  93. package/build/hooks/use_current_person.js.map +1 -1
  94. package/build/hooks/use_groups.d.ts +26 -26
  95. package/build/hooks/use_groups_groups.d.ts +26 -26
  96. package/build/hooks/use_jolt.d.ts.map +1 -1
  97. package/build/hooks/use_jolt.js +15 -22
  98. package/build/hooks/use_jolt.js.map +1 -1
  99. package/build/hooks/use_message_create.js +2 -2
  100. package/build/hooks/use_message_create.js.map +1 -1
  101. package/build/hooks/use_suspense_api.d.ts.map +1 -1
  102. package/build/hooks/use_suspense_api.js +5 -0
  103. package/build/hooks/use_suspense_api.js.map +1 -1
  104. package/build/hooks/use_teams.d.ts +26 -26
  105. package/build/hooks/use_upload_client.d.ts +28 -0
  106. package/build/hooks/use_upload_client.d.ts.map +1 -0
  107. package/build/hooks/use_upload_client.js +32 -0
  108. package/build/hooks/use_upload_client.js.map +1 -0
  109. package/build/index.d.ts +3 -2
  110. package/build/index.d.ts.map +1 -1
  111. package/build/index.js +3 -2
  112. package/build/index.js.map +1 -1
  113. package/build/navigation/index.d.ts +52 -34
  114. package/build/navigation/index.d.ts.map +1 -1
  115. package/build/navigation/index.js +16 -2
  116. package/build/navigation/index.js.map +1 -1
  117. package/build/screens/conversation_details_screen.js +2 -2
  118. package/build/screens/conversation_details_screen.js.map +1 -1
  119. package/build/screens/conversation_filter_recipients/components/checkbox_row.d.ts +10 -0
  120. package/build/screens/conversation_filter_recipients/components/checkbox_row.d.ts.map +1 -0
  121. package/build/screens/conversation_filter_recipients/components/checkbox_row.js +74 -0
  122. package/build/screens/conversation_filter_recipients/components/checkbox_row.js.map +1 -0
  123. package/build/screens/conversation_filter_recipients/components/header_row.d.ts +10 -0
  124. package/build/screens/conversation_filter_recipients/components/header_row.d.ts.map +1 -0
  125. package/build/screens/conversation_filter_recipients/components/header_row.js +69 -0
  126. package/build/screens/conversation_filter_recipients/components/header_row.js.map +1 -0
  127. package/build/screens/conversation_filter_recipients/components/navigation_header.d.ts +5 -0
  128. package/build/screens/conversation_filter_recipients/components/navigation_header.d.ts.map +1 -0
  129. package/build/screens/conversation_filter_recipients/components/navigation_header.js +46 -0
  130. package/build/screens/conversation_filter_recipients/components/navigation_header.js.map +1 -0
  131. package/build/screens/conversation_filter_recipients/context/conversation_filter_recipients_context.d.ts +17 -0
  132. package/build/screens/conversation_filter_recipients/context/conversation_filter_recipients_context.d.ts.map +1 -0
  133. package/build/screens/conversation_filter_recipients/context/conversation_filter_recipients_context.js +37 -0
  134. package/build/screens/conversation_filter_recipients/context/conversation_filter_recipients_context.js.map +1 -0
  135. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts +1 -3
  136. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.d.ts.map +1 -1
  137. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js +67 -32
  138. package/build/screens/conversation_filter_recipients/conversation_filter_recipients_screen.js.map +1 -1
  139. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts +10 -0
  140. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.d.ts.map +1 -0
  141. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js +32 -0
  142. package/build/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.js.map +1 -0
  143. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts +8 -0
  144. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.d.ts.map +1 -0
  145. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js +65 -0
  146. package/build/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.js.map +1 -0
  147. package/build/screens/conversation_filter_recipients/types.d.ts +38 -0
  148. package/build/screens/conversation_filter_recipients/types.d.ts.map +1 -0
  149. package/build/screens/conversation_filter_recipients/types.js +6 -0
  150. package/build/screens/conversation_filter_recipients/types.js.map +1 -0
  151. package/build/screens/conversation_filters/components/conversation_filters.js +5 -2
  152. package/build/screens/conversation_filters/components/conversation_filters.js.map +1 -1
  153. package/build/screens/conversation_filters/components/rows.d.ts.map +1 -1
  154. package/build/screens/conversation_filters/components/rows.js +6 -1
  155. package/build/screens/conversation_filters/components/rows.js.map +1 -1
  156. package/build/screens/conversation_filters/group_filters.d.ts.map +1 -1
  157. package/build/screens/conversation_filters/group_filters.js +12 -4
  158. package/build/screens/conversation_filters/group_filters.js.map +1 -1
  159. package/build/screens/conversation_filters/hooks/filters.d.ts +40 -40
  160. package/build/screens/conversation_filters/hooks/filters.js +1 -1
  161. package/build/screens/conversation_filters/hooks/filters.js.map +1 -1
  162. package/build/screens/conversation_filters/team_filters.d.ts.map +1 -1
  163. package/build/screens/conversation_filters/team_filters.js +12 -4
  164. package/build/screens/conversation_filters/team_filters.js.map +1 -1
  165. package/build/screens/conversation_filters_screen.js +1 -0
  166. package/build/screens/conversation_filters_screen.js.map +1 -1
  167. package/build/screens/conversation_new/components/groups_form.d.ts +4 -2
  168. package/build/screens/conversation_new/components/groups_form.d.ts.map +1 -1
  169. package/build/screens/conversation_new/components/groups_form.js +40 -55
  170. package/build/screens/conversation_new/components/groups_form.js.map +1 -1
  171. package/build/screens/conversation_new/components/team_form.d.ts +1 -1
  172. package/build/screens/conversation_new/components/team_form.js.map +1 -1
  173. package/build/screens/conversation_new/conversation_new_screen.d.ts +5 -2
  174. package/build/screens/conversation_new/conversation_new_screen.d.ts.map +1 -1
  175. package/build/screens/conversation_new/conversation_new_screen.js +2 -2
  176. package/build/screens/conversation_new/conversation_new_screen.js.map +1 -1
  177. package/build/screens/conversation_screen.d.ts +7 -0
  178. package/build/screens/conversation_screen.d.ts.map +1 -1
  179. package/build/screens/conversation_screen.js +103 -4
  180. package/build/screens/conversation_screen.js.map +1 -1
  181. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.d.ts +2 -0
  182. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.d.ts.map +1 -0
  183. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.js +17 -0
  184. package/build/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.js.map +1 -0
  185. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts +12 -0
  186. package/build/screens/conversation_select_recipients/components/recipient_link_row.d.ts.map +1 -0
  187. package/build/screens/conversation_select_recipients/components/recipient_link_row.js +61 -0
  188. package/build/screens/conversation_select_recipients/components/recipient_link_row.js.map +1 -0
  189. package/build/screens/conversation_select_recipients/components/view_more_link_row.d.ts +7 -0
  190. package/build/screens/conversation_select_recipients/components/view_more_link_row.d.ts.map +1 -0
  191. package/build/screens/conversation_select_recipients/components/view_more_link_row.js +21 -0
  192. package/build/screens/conversation_select_recipients/components/view_more_link_row.js.map +1 -0
  193. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.d.ts +4 -0
  194. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.d.ts.map +1 -0
  195. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js +48 -0
  196. package/build/screens/conversation_select_recipients/conversation_select_group_recipients_screen.js.map +1 -0
  197. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts +2 -6
  198. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.d.ts.map +1 -1
  199. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js +37 -49
  200. package/build/screens/conversation_select_recipients/conversation_select_recipients_screen.js.map +1 -1
  201. package/build/screens/conversation_select_recipients/types/screen_props.d.ts +9 -0
  202. package/build/screens/conversation_select_recipients/types/screen_props.d.ts.map +1 -0
  203. package/build/screens/conversation_select_recipients/types/screen_props.js +2 -0
  204. package/build/screens/conversation_select_recipients/types/screen_props.js.map +1 -0
  205. package/build/screens/conversations/components/list_header_component.d.ts.map +1 -1
  206. package/build/screens/conversations/components/list_header_component.js +18 -4
  207. package/build/screens/conversations/components/list_header_component.js.map +1 -1
  208. package/build/screens/conversations/conversations_screen.d.ts +2 -1
  209. package/build/screens/conversations/conversations_screen.d.ts.map +1 -1
  210. package/build/screens/conversations/conversations_screen.js +32 -1
  211. package/build/screens/conversations/conversations_screen.js.map +1 -1
  212. package/build/screens/send_giphy_screen.js +29 -1
  213. package/build/screens/send_giphy_screen.js.map +1 -1
  214. package/build/types/resources/groups/groups_group_resource.d.ts +1 -1
  215. package/build/types/resources/groups/groups_group_resource.js.map +1 -1
  216. package/build/types/resources/groups/groups_member_resource_with_person.d.ts +14 -0
  217. package/build/types/resources/groups/groups_member_resource_with_person.d.ts.map +1 -0
  218. package/build/types/resources/groups/groups_member_resource_with_person.js +2 -0
  219. package/build/types/resources/groups/groups_member_resource_with_person.js.map +1 -0
  220. package/build/types/resources/member.d.ts +0 -10
  221. package/build/types/resources/member.d.ts.map +1 -1
  222. package/build/types/resources/member.js.map +1 -1
  223. package/build/types/resources/message.d.ts +2 -0
  224. package/build/types/resources/message.d.ts.map +1 -1
  225. package/build/types/resources/message.js.map +1 -1
  226. package/build/types/resources/oauth_token.d.ts +4 -4
  227. package/build/types/resources/oauth_token.d.ts.map +1 -1
  228. package/build/types/resources/oauth_token.js.map +1 -1
  229. package/build/utils/client/client.d.ts +4 -8
  230. package/build/utils/client/client.d.ts.map +1 -1
  231. package/build/utils/client/client.js +10 -9
  232. package/build/utils/client/client.js.map +1 -1
  233. package/build/utils/date.d.ts +5 -0
  234. package/build/utils/date.d.ts.map +1 -1
  235. package/build/utils/date.js +8 -1
  236. package/build/utils/date.js.map +1 -1
  237. package/build/utils/destructure_chat_group_graph_id.d.ts +10 -0
  238. package/build/utils/destructure_chat_group_graph_id.d.ts.map +1 -0
  239. package/build/utils/destructure_chat_group_graph_id.js +8 -0
  240. package/build/utils/destructure_chat_group_graph_id.js.map +1 -0
  241. package/build/utils/index.d.ts +1 -0
  242. package/build/utils/index.d.ts.map +1 -1
  243. package/build/utils/index.js +1 -0
  244. package/build/utils/index.js.map +1 -1
  245. package/build/utils/native_adapters/configuration.d.ts +4 -1
  246. package/build/utils/native_adapters/configuration.d.ts.map +1 -1
  247. package/build/utils/native_adapters/configuration.js +13 -1
  248. package/build/utils/native_adapters/configuration.js.map +1 -1
  249. package/build/utils/native_adapters/image_picker.d.ts +25 -0
  250. package/build/utils/native_adapters/image_picker.d.ts.map +1 -0
  251. package/build/utils/native_adapters/image_picker.js +9 -0
  252. package/build/utils/native_adapters/image_picker.js.map +1 -0
  253. package/build/utils/native_adapters/index.d.ts +1 -0
  254. package/build/utils/native_adapters/index.d.ts.map +1 -1
  255. package/build/utils/native_adapters/index.js +1 -0
  256. package/build/utils/native_adapters/index.js.map +1 -1
  257. package/build/utils/session.d.ts +6 -2
  258. package/build/utils/session.d.ts.map +1 -1
  259. package/build/utils/session.js +6 -1
  260. package/build/utils/session.js.map +1 -1
  261. package/build/utils/upload_uri.d.ts +23 -0
  262. package/build/utils/upload_uri.d.ts.map +1 -0
  263. package/build/utils/upload_uri.js +60 -0
  264. package/build/utils/upload_uri.js.map +1 -0
  265. package/build/utils/uri.d.ts +10 -2
  266. package/build/utils/uri.d.ts.map +1 -1
  267. package/build/utils/uri.js +24 -6
  268. package/build/utils/uri.js.map +1 -1
  269. package/build/vendor/tapestry/alias_tokens_color_map.d.ts +2 -0
  270. package/build/vendor/tapestry/alias_tokens_color_map.d.ts.map +1 -1
  271. package/build/vendor/tapestry/alias_tokens_color_map.js +2 -0
  272. package/build/vendor/tapestry/alias_tokens_color_map.js.map +1 -1
  273. package/package.json +4 -3
  274. package/src/__tests__/hooks/useTheme.tsx +1 -1
  275. package/src/__tests__/{client.ts → utils/client.ts} +7 -115
  276. package/src/__tests__/{session.ts → utils/session.ts} +4 -4
  277. package/src/__tests__/utils/uri.ts +107 -0
  278. package/src/components/conversation/message_form/message_form_attachment_image.tsx +121 -0
  279. package/src/components/conversation/message_form.tsx +197 -31
  280. package/src/components/conversations/conversation_actions.tsx +2 -2
  281. package/src/components/conversations/conversation_preview.tsx +8 -2
  282. package/src/components/display/action_button.tsx +4 -3
  283. package/src/components/display/banner.tsx +7 -1
  284. package/src/components/display/banner_collapsible.tsx +6 -1
  285. package/src/components/display/child_notice.tsx +9 -3
  286. package/src/components/group_conversation_list.tsx +82 -0
  287. package/src/components/index.tsx +1 -0
  288. package/src/components/primitive/banner_primitive.tsx +12 -5
  289. package/src/contexts/api_provider.tsx +3 -3
  290. package/src/contexts/chat_context.tsx +7 -7
  291. package/src/contexts/conversations_context.tsx +1 -1
  292. package/src/hooks/attachments/supported_extensions.ts +47 -0
  293. package/src/hooks/groups/use_group_members_for_new_conversation.ts +74 -0
  294. package/src/hooks/groups/use_groups_conversation_create.ts +50 -0
  295. package/src/hooks/index.ts +4 -0
  296. package/src/hooks/use_api.ts +13 -7
  297. package/src/hooks/use_api_client.ts +7 -3
  298. package/src/hooks/use_attachment_uploader.ts +179 -0
  299. package/src/hooks/use_conversation.ts +1 -0
  300. package/src/hooks/use_conversations_actions.ts +11 -0
  301. package/src/hooks/use_conversations_jolt_events.ts +5 -1
  302. package/src/hooks/use_current_person.ts +37 -9
  303. package/src/hooks/use_jolt.ts +18 -23
  304. package/src/hooks/use_message_create.ts +2 -2
  305. package/src/hooks/use_suspense_api.ts +6 -0
  306. package/src/hooks/use_upload_client.ts +67 -0
  307. package/src/index.tsx +3 -1
  308. package/src/navigation/index.tsx +23 -2
  309. package/src/screens/conversation_details_screen.tsx +2 -2
  310. package/src/screens/conversation_filter_recipients/components/checkbox_row.tsx +101 -0
  311. package/src/screens/conversation_filter_recipients/components/header_row.tsx +99 -0
  312. package/src/screens/conversation_filter_recipients/components/navigation_header.tsx +68 -0
  313. package/src/screens/conversation_filter_recipients/context/conversation_filter_recipients_context.tsx +53 -0
  314. package/src/screens/conversation_filter_recipients/conversation_filter_recipients_screen.tsx +90 -49
  315. package/src/screens/conversation_filter_recipients/hooks/use_flattened_array_of_service_types_with_teams.tsx +50 -0
  316. package/src/screens/conversation_filter_recipients/hooks/use_service_types_with_teams.ts +90 -0
  317. package/src/screens/conversation_filter_recipients/types.tsx +47 -0
  318. package/src/screens/conversation_filters/components/conversation_filters.tsx +5 -2
  319. package/src/screens/conversation_filters/components/rows.tsx +6 -1
  320. package/src/screens/conversation_filters/group_filters.tsx +23 -14
  321. package/src/screens/conversation_filters/hooks/filters.ts +1 -1
  322. package/src/screens/conversation_filters/team_filters.tsx +23 -14
  323. package/src/screens/conversation_filters_screen.tsx +1 -0
  324. package/src/screens/conversation_new/components/groups_form.tsx +66 -72
  325. package/src/screens/conversation_new/components/team_form.tsx +1 -1
  326. package/src/screens/conversation_new/conversation_new_screen.tsx +11 -4
  327. package/src/screens/conversation_screen.tsx +123 -4
  328. package/src/screens/conversation_select_recipients/components/groups_without_chat_disclaimer_row.tsx +21 -0
  329. package/src/screens/conversation_select_recipients/components/recipient_link_row.tsx +91 -0
  330. package/src/screens/conversation_select_recipients/components/view_more_link_row.tsx +30 -0
  331. package/src/screens/conversation_select_recipients/conversation_select_group_recipients_screen.tsx +79 -0
  332. package/src/screens/conversation_select_recipients/conversation_select_recipients_screen.tsx +57 -65
  333. package/src/screens/conversation_select_recipients/types/screen_props.tsx +11 -0
  334. package/src/screens/conversations/components/list_header_component.tsx +20 -4
  335. package/src/screens/conversations/conversations_screen.tsx +37 -2
  336. package/src/screens/send_giphy_screen.tsx +30 -1
  337. package/src/types/resources/groups/groups_group_resource.ts +1 -1
  338. package/src/types/resources/groups/groups_member_resource_with_person.ts +13 -0
  339. package/src/types/resources/member.ts +0 -11
  340. package/src/types/resources/message.ts +2 -0
  341. package/src/types/resources/oauth_token.ts +4 -4
  342. package/src/utils/client/client.ts +13 -13
  343. package/src/utils/date.ts +11 -1
  344. package/src/utils/destructure_chat_group_graph_id.ts +25 -0
  345. package/src/utils/index.ts +1 -0
  346. package/src/utils/native_adapters/configuration.ts +15 -1
  347. package/src/utils/native_adapters/image_picker.ts +31 -0
  348. package/src/utils/native_adapters/index.ts +1 -0
  349. package/src/utils/session.ts +10 -4
  350. package/src/utils/upload_uri.ts +69 -0
  351. package/src/utils/uri.ts +30 -6
  352. package/src/vendor/tapestry/alias_tokens_color_map.ts +3 -0
  353. package/build/screens/conversation_new/components/member_error_card.d.ts +0 -5
  354. package/build/screens/conversation_new/components/member_error_card.d.ts.map +0 -1
  355. package/build/screens/conversation_new/components/member_error_card.js +0 -17
  356. package/build/screens/conversation_new/components/member_error_card.js.map +0 -1
  357. package/build/screens/conversation_new/utils/fake_member_data.d.ts +0 -3
  358. package/build/screens/conversation_new/utils/fake_member_data.d.ts.map +0 -1
  359. package/build/screens/conversation_new/utils/fake_member_data.js +0 -129
  360. package/build/screens/conversation_new/utils/fake_member_data.js.map +0 -1
  361. package/src/screens/conversation_new/components/member_error_card.tsx +0 -20
  362. package/src/screens/conversation_new/utils/fake_member_data.ts +0 -130
@@ -6,12 +6,12 @@ import { ENV, PartialToken, ResponseError, Session } from '../utils'
6
6
  import { ChatTheme, defaultTheme, DefaultTheme } from '../utils/theme'
7
7
 
8
8
  export type ChatContextValue = {
9
- token?: PartialToken
10
- onUnauthorizedResponse: (_response: ResponseError) => void
11
- theme: ChatTheme
12
9
  env?: ENV
13
- session: Session
14
10
  giphyApiKey?: string
11
+ onUnauthorizedResponse: (_response: ResponseError) => void
12
+ session: Session
13
+ theme: ChatTheme
14
+ token?: PartialToken
15
15
  }
16
16
 
17
17
  export interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'theme' | 'session'> {
@@ -19,12 +19,12 @@ export interface ChatProviderProps extends Omit<ChatContextValue, 'client' | 'th
19
19
  }
20
20
 
21
21
  export const ChatContext = createContext<ChatContextValue>({
22
- theme: defaultTheme('light'),
23
- token: undefined,
24
22
  env: undefined,
23
+ giphyApiKey: undefined,
25
24
  onUnauthorizedResponse: () => {},
26
25
  session: new Session(),
27
- giphyApiKey: undefined,
26
+ theme: defaultTheme('light'),
27
+ token: undefined,
28
28
  })
29
29
 
30
30
  export function ChatProvider({ children, value }: { children: any; value: ChatProviderProps }) {
@@ -36,7 +36,7 @@ const ConversationsContext = createContext<ConversationsContextValue>({
36
36
 
37
37
  export const ConversationsContextProvider = ({
38
38
  children,
39
- args,
39
+ args = {},
40
40
  }: PropsWithChildren<{ args: ConversationFiltersParams }>) => {
41
41
  const [activeConversationId, setActiveConversationId] = useState<number | undefined>()
42
42
  const { chat_group_graph_id, group_source_app_name } = args
@@ -0,0 +1,47 @@
1
+ export const SUPPORTED_EXTENSIONS = [
2
+ '.3ga',
3
+ '.3gp',
4
+ '.aac',
5
+ '.amr',
6
+ '.avi',
7
+ '.bmp',
8
+ '.doc',
9
+ '.docx',
10
+ '.gif',
11
+ '.h263',
12
+ '.h264',
13
+ '.heic',
14
+ '.heif',
15
+ '.jpeg',
16
+ '.jpg',
17
+ '.key',
18
+ '.m4a',
19
+ '.m4b',
20
+ '.m4p',
21
+ '.m4r',
22
+ '.m4v',
23
+ '.mkv',
24
+ '.mov',
25
+ '.mp3',
26
+ '.mp4',
27
+ '.mp4-latm',
28
+ '.mpeg',
29
+ '.mpeg4',
30
+ '.mpg',
31
+ '.numbers',
32
+ '.ogg',
33
+ '.pages',
34
+ '.pdf',
35
+ '.png',
36
+ '.ppt',
37
+ '.pptx',
38
+ '.rtf',
39
+ '.txt',
40
+ '.vcf',
41
+ '.wav',
42
+ '.webm',
43
+ '.webp',
44
+ '.wmv',
45
+ '.xls',
46
+ '.xlsx',
47
+ ]
@@ -0,0 +1,74 @@
1
+ import { MemberBadge, MemberResource, ResourceObject } from '../../types'
2
+ import { GroupsGroupMemberResource } from '../../types/resources/groups/groups_member_resource_with_person'
3
+ import { useApiPaginator } from '../use_api'
4
+ import { useCurrentPerson } from '../use_current_person'
5
+
6
+ type UseApiPaginatorResult<T extends ResourceObject> = ReturnType<typeof useApiPaginator<T>>
7
+
8
+ export type GroupMembersForNewConversationResult = Omit<
9
+ UseApiPaginatorResult<GroupsGroupMemberResource>, // We are passing our own "members" data shape
10
+ 'data'
11
+ > & {
12
+ data: MemberResource[]
13
+ adultMembers: MemberResource[]
14
+ childMembers: MemberResource[]
15
+ }
16
+
17
+ /**
18
+ * This is specifically for the new conversation screen because we assign
19
+ * the "Conversation owner" badge to the current person.
20
+ */
21
+ export function useGroupMembersForNewConversation({ id }: { id: number }) {
22
+ const currentPerson = useCurrentPerson()
23
+ const response = useApiPaginator<GroupsGroupMemberResource>({
24
+ url: `/me/groups/${id}/memberships`,
25
+ data: {
26
+ perPage: 100,
27
+ include: ['person'],
28
+ fields: {
29
+ Membership: ['person, role'],
30
+ Person: ['avatar_url', 'name', 'first_name', 'last_name', 'child'],
31
+ },
32
+ },
33
+ app: 'groups',
34
+ })
35
+
36
+ const { data: memberships = [] } = response
37
+ const members: MemberResource[] = memberships.map(membership => {
38
+ const { person } = membership
39
+ return {
40
+ type: 'Member',
41
+ avatar: person.avatarUrl,
42
+ badges: buildBadges(membership, currentPerson.id),
43
+ child: person.child,
44
+ id: +person.id,
45
+ name: `${person.firstName} ${person.lastName}`,
46
+ source: [],
47
+ role: membership.role,
48
+ }
49
+ })
50
+ const adultMembers = members.filter(member => !member.child)
51
+ const childMembers = members.filter(member => member.child)
52
+
53
+ return {
54
+ ...response,
55
+ data: members,
56
+ adultMembers,
57
+ childMembers,
58
+ }
59
+ }
60
+
61
+ function buildBadges(
62
+ membership: GroupsGroupMemberResource,
63
+ currentPersonId: number
64
+ ): MemberBadge[] {
65
+ const { person } = membership
66
+ const badges = []
67
+ if (membership.role === 'leader') {
68
+ badges.push({ title: 'Leader' })
69
+ }
70
+ if (person.id === currentPersonId) {
71
+ badges.push({ title: 'Conversation owner' })
72
+ }
73
+ return badges
74
+ }
@@ -0,0 +1,50 @@
1
+ import { useMutation } from '@tanstack/react-query'
2
+ import { ApiResource, ConversationResource, ResourceObject } from '../../types'
3
+ import { useApiClient } from '../use_api_client'
4
+
5
+ interface Props {
6
+ groupId: number
7
+ title?: string
8
+ onSuccess: (conversationId: number) => void
9
+ }
10
+
11
+ export function useGroupsConversationCreate({ groupId, title, onSuccess }: Props) {
12
+ const apiClient = useApiClient()
13
+ return useMutation({
14
+ throwOnError: true,
15
+ onSuccess: result => {
16
+ onSuccess && onSuccess(result.data.id)
17
+ },
18
+ mutationFn: () =>
19
+ apiClient.groups
20
+ .post<ApiResource<ChatConversationPayload>>({
21
+ url: `/me/groups/${groupId}/chat_conversation_payload`,
22
+ data: {
23
+ data: {
24
+ type: '',
25
+ attributes: {
26
+ title,
27
+ },
28
+ },
29
+ },
30
+ })
31
+ .then(res => res.data.value)
32
+ .then(payload =>
33
+ apiClient.chat.post<ApiResource<ConversationResource>>({
34
+ url: '/me/conversations',
35
+ data: {
36
+ data: {
37
+ type: 'Conversation',
38
+ attributes: {
39
+ payload,
40
+ },
41
+ },
42
+ },
43
+ })
44
+ ),
45
+ })
46
+ }
47
+
48
+ interface ChatConversationPayload extends ResourceObject {
49
+ value: string
50
+ }
@@ -6,3 +6,7 @@ export * from './use_font_scale'
6
6
  export * from './use_create_android_ripple_color'
7
7
  export * from './use_chat_permissions'
8
8
  export * from './use_api_client'
9
+ export * from './use_groups_groups'
10
+ export * from './use_groups'
11
+ export * from './use_api'
12
+ export * from './use_api_client'
@@ -4,10 +4,10 @@ import {
4
4
  useInfiniteQuery,
5
5
  useQuery,
6
6
  } from '@tanstack/react-query'
7
- import { ApiCollection, ApiResource, ResourceObject } from '../types'
7
+ import { ApiCollection, ApiError, ApiResource, ResourceObject } from '../types'
8
8
  import { GetRequest, RequestData } from '../utils/client/types'
9
9
  import { App, useApiClient } from './use_api_client'
10
- import { getRequestQueryKey } from './use_suspense_api'
10
+ import { getRequestQueryKey, RequestQueryKey } from './use_suspense_api'
11
11
 
12
12
  interface ApiGetOptions extends GetRequest {
13
13
  app?: App
@@ -16,9 +16,15 @@ interface ApiGetOptions extends GetRequest {
16
16
 
17
17
  export const useApiGet = <T extends ResourceObject | ResourceObject[]>(args: ApiGetOptions) => {
18
18
  type Resource = ApiResource<T>
19
+ const apiClient = useApiClient()
19
20
 
20
- const { data, ...query } = useQuery<Resource, Response>({
21
+ const { data, ...query } = useQuery<Resource, ApiError>({
21
22
  queryKey: getRequestQueryKey(args),
23
+ queryFn: ({ queryKey }) => {
24
+ const [url, d, headers, app = 'chat'] = queryKey as RequestQueryKey
25
+
26
+ return apiClient[app].get({ url, data: d, headers }) as Promise<Resource>
27
+ },
22
28
  enabled: args.enabled,
23
29
  })
24
30
 
@@ -30,19 +36,19 @@ type NextMeta = Partial<{
30
36
  idLt: string
31
37
  }>
32
38
 
33
- export type SuspensePaginatorOptions = Omit<
39
+ export type PaginatorOptions = Omit<
34
40
  AnyUseSuspenseInfiniteQueryOptions,
35
41
  'getNextPageParam' | 'initialPageParam' | 'queryFn' | 'queryKey'
36
42
  >
37
43
 
38
44
  export const useApiPaginator = <T extends ResourceObject>(
39
45
  args: ApiGetOptions,
40
- opts?: SuspensePaginatorOptions
46
+ opts?: PaginatorOptions
41
47
  ) => {
42
48
  const apiClient = useApiClient()
43
49
  const query = useInfiniteQuery<
44
50
  ApiCollection<T>,
45
- Response,
51
+ ApiError,
46
52
  InfiniteData<ApiCollection<T>>,
47
53
  any,
48
54
  Partial<RequestData> | undefined
@@ -56,7 +62,7 @@ export const useApiPaginator = <T extends ResourceObject>(
56
62
  const offset = pageParam?.offset || args.data.offset
57
63
  const data = { ...args.data, where, offset }
58
64
 
59
- return apiClient[app].get({
65
+ return apiClient[app].get<ApiCollection<T>>({
60
66
  url: args.url,
61
67
  data,
62
68
  })
@@ -1,6 +1,7 @@
1
1
  import { useContext, useMemo } from 'react'
2
2
  import { ChatContext } from '../contexts/chat_context'
3
3
  import { Client } from '../utils/client'
4
+ import { Uri } from '../utils'
4
5
 
5
6
  export type App = 'chat' | 'groups' | 'services'
6
7
  const apps: App[] = ['chat', 'groups', 'services']
@@ -9,18 +10,21 @@ export type ApiClient = { [_K in App]: Client }
9
10
 
10
11
  export const useApiClient = () => {
11
12
  const { session, onUnauthorizedResponse } = useContext(ChatContext)
13
+
14
+ const uri = useMemo(() => new Uri({ session }), [session])
15
+
12
16
  const api = useMemo(
13
17
  () =>
14
18
  apps.reduce((acc, app) => {
15
19
  acc[app] = new Client({
16
- app,
17
- session,
20
+ root: uri.api(`/${app}/v2`),
21
+ defaultHeaders: uri.headers,
18
22
  version: '2018-11-01',
19
23
  onUnauthorizedResponse,
20
24
  })
21
25
  return acc
22
26
  }, {} as ApiClient),
23
- [session, onUnauthorizedResponse]
27
+ [uri, onUnauthorizedResponse]
24
28
  )
25
29
 
26
30
  return api
@@ -0,0 +1,179 @@
1
+ import { useCallback, useEffect, useMemo, useRef, useState } from 'react'
2
+ import { SUPPORTED_EXTENSIONS } from './attachments/supported_extensions'
3
+ import { FileForUploadClient, useUploadClient } from './use_upload_client'
4
+ import { useApiClient } from './use_api_client'
5
+ import { ApiResource } from '../types'
6
+
7
+ type AttachmentStatus = 'uploading' | 'success' | 'error'
8
+
9
+ interface AttachmentFile extends FileForUploadClient {
10
+ size: number
11
+ width?: number
12
+ height?: number
13
+ }
14
+
15
+ export interface FileAttachment {
16
+ id?: string
17
+ file: AttachmentFile
18
+ status: AttachmentStatus
19
+ }
20
+
21
+ interface UploadState {
22
+ [fileName: string]: {
23
+ status: AttachmentStatus
24
+ id?: string
25
+ }
26
+ }
27
+
28
+ interface FileError {
29
+ file_type?: string[]
30
+ file_size?: boolean
31
+ }
32
+
33
+ const MAX_FILE_SIZE_IN_MB = 50
34
+ const MAX_FILE_SIZE_IN_BYTES = MAX_FILE_SIZE_IN_MB * 1024 * 1024
35
+ const MAX_NUMBER_OF_ATTACHMENTS = 10
36
+
37
+ export function useAttachmentUploader({ conversationId }: { conversationId: number }) {
38
+ const apiClient = useApiClient()
39
+ const uploadApi = useUploadClient()
40
+ const [attachments, setAttachments] = useState<FileAttachment[]>([])
41
+ const uploadState = useRef<UploadState>({})
42
+ const [lastUploadId, setLastUploadId] = useState<string>()
43
+ const numberOfAttachments = attachments.length
44
+ const [errorMessage, setErrorMessage] = useState<string | null>(null)
45
+
46
+ const handleFilesAttached = useCallback(
47
+ (files: AttachmentFile[]) => {
48
+ const fileErrors = {} as FileError
49
+
50
+ const validFiles = files.filter(file => {
51
+ const extension = file.name.split('.').pop() as string
52
+ const isValidExtension = SUPPORTED_EXTENSIONS.includes(`.${extension}`)
53
+ const isValidFileSize = file.size <= MAX_FILE_SIZE_IN_BYTES
54
+
55
+ if (!isValidExtension) {
56
+ fileErrors.file_type ||= []
57
+ fileErrors.file_type.push(extension)
58
+ }
59
+ if (!isValidFileSize) {
60
+ fileErrors.file_size = true
61
+ }
62
+
63
+ return isValidFileSize && isValidExtension
64
+ })
65
+
66
+ const errorMessages: string[] = []
67
+ if (fileErrors.file_type) {
68
+ errorMessages.push(
69
+ `The following file types are not supported: ${fileErrors.file_type.join(', ')}`
70
+ )
71
+ }
72
+ if (fileErrors.file_size) {
73
+ errorMessages.push(`File size exceeds ${MAX_FILE_SIZE_IN_MB} MB`)
74
+ }
75
+ if (numberOfAttachments + validFiles.length > MAX_NUMBER_OF_ATTACHMENTS) {
76
+ errorMessages.push(`You can't attach more than ${MAX_NUMBER_OF_ATTACHMENTS} files at once.`)
77
+ }
78
+ if (errorMessages.length > 0) {
79
+ setErrorMessage(errorMessages.join('\n'))
80
+ return
81
+ }
82
+
83
+ const newAttachments: FileAttachment[] = validFiles.map(file => ({
84
+ file,
85
+ status: 'uploading',
86
+ }))
87
+
88
+ if (newAttachments && newAttachments.length > 0) {
89
+ setAttachments(prevAttachments => [...prevAttachments, ...newAttachments])
90
+
91
+ newAttachments.forEach(attachment => {
92
+ uploadApi
93
+ .uploadFile(attachment.file)
94
+ .then(({ id: uploadedFileId }) =>
95
+ apiClient.chat.post<ApiResource<MessageAttachmentResource>>({
96
+ url: `/me/conversations/${conversationId}/message_attachments`,
97
+ data: {
98
+ data: {
99
+ type: 'MessageAttachment',
100
+ attributes: { uploaded_file_id: uploadedFileId },
101
+ },
102
+ },
103
+ })
104
+ )
105
+ .then(({ data: { id: messageAttachmentId } }) => {
106
+ uploadState.current[attachment.file.name] = {
107
+ status: 'success',
108
+ id: messageAttachmentId,
109
+ }
110
+ setLastUploadId(messageAttachmentId)
111
+ })
112
+ .catch(() => {
113
+ uploadState.current[attachment.file.name] = {
114
+ status: 'error',
115
+ }
116
+ setLastUploadId(attachment.file.name)
117
+ })
118
+ })
119
+ }
120
+ },
121
+ [numberOfAttachments, uploadApi, apiClient.chat, conversationId]
122
+ )
123
+
124
+ useEffect(() => {
125
+ if (!lastUploadId) return
126
+
127
+ setLastUploadId(undefined)
128
+ setAttachments(
129
+ attachments.map(attachment => {
130
+ const state = uploadState.current[attachment.file.name]
131
+ if (state) {
132
+ return { ...attachment, id: state.id, status: state.status }
133
+ }
134
+ return attachment
135
+ })
136
+ )
137
+ }, [attachments, lastUploadId])
138
+
139
+ const removeAttachment = useCallback((attachment: FileAttachment) => {
140
+ setAttachments(prevAttachments =>
141
+ prevAttachments.filter(a => a.file.uri !== attachment.file.uri)
142
+ )
143
+ }, [])
144
+
145
+ const reset = useCallback(() => {
146
+ setAttachments([])
147
+ setErrorMessage(null)
148
+ }, [])
149
+
150
+ const pendingUploads = attachments.filter(a => a.status === 'uploading').length > 0
151
+
152
+ const attachmentIds = useMemo(
153
+ () => attachments.filter(a => a.status === 'success' && a.id).map(a => a.id as string),
154
+ [attachments]
155
+ )
156
+
157
+ return {
158
+ attachments,
159
+ attachmentIds,
160
+ handleFilesAttached,
161
+ removeAttachment,
162
+ reset,
163
+ pendingUploads,
164
+ errorMessage,
165
+ remainingAttachable: MAX_NUMBER_OF_ATTACHMENTS - numberOfAttachments,
166
+ }
167
+ }
168
+
169
+ interface MessageAttachmentResource {
170
+ type: 'MessageAttachment'
171
+ id: string
172
+ uploadedFileId: string
173
+ filename: string
174
+ messageSortKey: string
175
+ metadata: Record<string, unknown>
176
+ checksum: string
177
+ contentType: string
178
+ byteSize: number
179
+ }
@@ -66,6 +66,7 @@ export const useConversationMute = ({ conversation_id }: { conversation_id: numb
66
66
  })
67
67
  },
68
68
  onSuccess: (response: ApiResource<ConversationResource>) => {
69
+ queryClient.invalidateQueries({ queryKey: ['/me/conversations'] })
69
70
  queryClient.setQueryData<ApiResource<ConversationResource>>(queryKey, prev => {
70
71
  if (!prev?.data) return prev
71
72
 
@@ -4,6 +4,7 @@ import { useConversationsContext } from '../contexts/conversations_context'
4
4
  import { ApiResource, ConversationResource } from '../types'
5
5
  import { useApiClient } from './use_api_client'
6
6
  import { useConversationsCache } from './use_conversations_cache'
7
+ import { useCurrentPersonCache } from './use_current_person'
7
8
 
8
9
  export const useConversationsMarkRead = ({
9
10
  conversation,
@@ -12,14 +13,24 @@ export const useConversationsMarkRead = ({
12
13
  }) => {
13
14
  const apiClient = useApiClient()
14
15
  const { args } = useConversationsContext()
16
+ const currentPersonCache = useCurrentPersonCache()
15
17
  const { update, invalidate } = useConversationsCache(args)
16
18
 
19
+ function handlePersonUnreadCount(read: boolean) {
20
+ currentPersonCache.update({}, person => {
21
+ const currentUnread = person.unreadCount
22
+ const updatedUnread = read ? Math.max(currentUnread - 1, 0) : currentUnread + 1
23
+ return { ...person, unreadCount: updatedUnread }
24
+ })
25
+ }
26
+
17
27
  const { mutate: handleMarkRead, ...mutation } = useMutation({
18
28
  onMutate: async (read: boolean) => {
19
29
  update({
20
30
  ...conversation,
21
31
  unreadCount: read ? 0 : 1,
22
32
  })
33
+ handlePersonUnreadCount(read)
23
34
  },
24
35
  mutationKey: ['markRead', conversation.id],
25
36
  mutationFn: async (read: boolean) => {
@@ -1,13 +1,14 @@
1
1
  import { JoltConversationEvent } from '../types/jolt_events'
2
2
  import { ConversationRequestArgs } from '../utils/request/conversation'
3
3
  import { useConversationsCache } from './use_conversations_cache'
4
- import { useCurrentPerson } from './use_current_person'
4
+ import { useCurrentPerson, useCurrentPersonCache } from './use_current_person'
5
5
  import { useJoltChannel, useJoltEvent } from './use_jolt'
6
6
 
7
7
  export function useConversationsJoltEvents(args?: Partial<ConversationRequestArgs>) {
8
8
  const currentPerson = useCurrentPerson()
9
9
  const joltChannel = useJoltChannel(`chat.people.${currentPerson.id}`)
10
10
  const cache = useConversationsCache(args)
11
+ const currentPersonCache = useCurrentPersonCache()
11
12
 
12
13
  useJoltEvent(joltChannel, 'conversation.updated', (e: JoltConversationEvent) =>
13
14
  cache.fetchUpdate({ id: e.data.data.id })
@@ -18,4 +19,7 @@ export function useConversationsJoltEvents(args?: Partial<ConversationRequestArg
18
19
  useJoltEvent(joltChannel, 'conversation.destroyed', (e: JoltConversationEvent) =>
19
20
  cache.destroy({ id: e.data.data.id })
20
21
  )
22
+
23
+ useJoltEvent(joltChannel, 'STREAM_USER_UPDATED', currentPersonCache.invalidate) // Would be nice to have a non-stream chat event
24
+ useJoltEvent(joltChannel, 'conversation.read', currentPersonCache.invalidate)
21
25
  }
@@ -1,15 +1,43 @@
1
+ import { useQueryClient } from '@tanstack/react-query'
1
2
  import { CurrentPersonResource } from '../types'
2
- import { useSuspenseGet } from './use_suspense_api'
3
+ import { getRequestQueryKey, useSuspenseGet } from './use_suspense_api'
4
+ import { ApiResource } from '../types/api_primitives'
3
5
 
4
- export const useCurrentPerson = () => {
5
- const { data: person } = useSuspenseGet<CurrentPersonResource>({
6
- url: '/me',
7
- data: {
8
- fields: {
9
- Person: ['id', 'name', 'avatar', 'can_chat', 'unread_count', 'pco_chat_enabled'],
10
- },
6
+ export const currentPersonRequestArgs = {
7
+ url: '/me',
8
+ data: {
9
+ fields: {
10
+ Person: ['id', 'name', 'avatar', 'can_chat', 'unread_count', 'pco_chat_enabled'],
11
11
  },
12
- })
12
+ },
13
+ }
14
+
15
+ export const currentPersonQueryKey = getRequestQueryKey(currentPersonRequestArgs)
16
+
17
+ export const useCurrentPerson = () => {
18
+ const { data: person } = useSuspenseGet<CurrentPersonResource>(currentPersonRequestArgs)
13
19
 
14
20
  return person
15
21
  }
22
+
23
+ type ProcessRecord<T> = (record: T, update: Partial<T>) => T
24
+
25
+ export const useCurrentPersonCache = () => {
26
+ const queryClient = useQueryClient()
27
+ const handleUpdate = (
28
+ update: Partial<CurrentPersonResource>,
29
+ processRecord: ProcessRecord<CurrentPersonResource> = (r, u) => ({ ...r, ...u })
30
+ ) => {
31
+ queryClient.setQueryData<ApiResource<CurrentPersonResource>>(currentPersonQueryKey, data => {
32
+ if (!data) return data
33
+
34
+ return { ...data, data: processRecord(data.data, update) }
35
+ })
36
+ }
37
+
38
+ const handleInvalidate = () => {
39
+ queryClient.invalidateQueries({ queryKey: currentPersonQueryKey })
40
+ }
41
+
42
+ return { update: handleUpdate, invalidate: handleInvalidate }
43
+ }
@@ -8,10 +8,10 @@ import {
8
8
  JoltSubscription,
9
9
  } from '@planningcenter/jolt-client/dist/types/JoltSubscription'
10
10
  import { useQuery, useQueryClient, useSuspenseQuery } from '@tanstack/react-query'
11
- import { useEffect, useMemo, useState } from 'react'
11
+ import { useCallback, useEffect, useMemo, useState } from 'react'
12
12
  import { useChatContext } from '../contexts/chat_context'
13
13
  import { ApiResource } from '../types'
14
- import { Client } from '../utils'
14
+ import { Client, Uri } from '../utils'
15
15
 
16
16
  interface JoltResponse {
17
17
  type: 'JoltToken'
@@ -22,28 +22,18 @@ interface JoltResponse {
22
22
  export const useJoltClient = (): JoltClient | undefined => {
23
23
  const { session } = useChatContext()
24
24
  const queryClient = useQueryClient()
25
+ const uri = useMemo(() => new Uri({ session }), [session])
25
26
  const apiClient = useMemo(
26
- // Client that does not relay 401 errors
27
- () => new Client({ app: 'chat', session, version: '2018-11-01' }),
28
- [session]
27
+ () =>
28
+ new Client({
29
+ root: uri.api(`/chat/v2`),
30
+ defaultHeaders: uri.headers,
31
+ version: '2018-11-01',
32
+ }),
33
+ [uri]
29
34
  )
30
35
 
31
- const { data: joltToken } = useSuspenseQuery<ApiResource<JoltResponse>>({
32
- queryKey: ['jolt-token'],
33
- queryFn: () => {
34
- return apiClient.post({
35
- url: '/me/jolt_authorize',
36
- data: {
37
- data: {
38
- type: 'JoltToken',
39
- attributes: {},
40
- },
41
- },
42
- })
43
- },
44
- })
45
-
46
- const fetchJoltToken = async () => {
36
+ const fetchJoltToken = useCallback(async () => {
47
37
  return apiClient.post<ApiResource<JoltResponse>>({
48
38
  url: '/me/jolt_authorize',
49
39
  data: {
@@ -53,11 +43,16 @@ export const useJoltClient = (): JoltClient | undefined => {
53
43
  },
54
44
  },
55
45
  })
56
- }
46
+ }, [apiClient])
47
+
48
+ const { data: joltToken } = useSuspenseQuery<ApiResource<JoltResponse>>({
49
+ queryKey: ['jolt-token'],
50
+ queryFn: fetchJoltToken,
51
+ })
57
52
 
58
53
  const fetchAuthTokenFn: FetchAuthToken = () => {
59
54
  return queryClient.fetchQuery({
60
- queryKey: ['jolt-token'],
55
+ queryKey: ['jolt-auth-token'],
61
56
  queryFn: () => fetchJoltToken().then(res => res.data.id),
62
57
  })
63
58
  }