@rapidmx/web-client 0.14.1 → 0.16.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 (314) hide show
  1. package/README.md +373 -373
  2. package/apps/admin/branding/index.tsx +39 -39
  3. package/apps/admin/data-requests/index.tsx +482 -480
  4. package/apps/admin/domains/[uid].tsx +164 -163
  5. package/apps/admin/escrow-scopes/[uid].tsx +348 -348
  6. package/apps/admin/index.tsx +127 -124
  7. package/apps/admin/mailboxes/[uid].tsx +269 -224
  8. package/apps/admin/mailboxes/new/index.tsx +28 -28
  9. package/apps/admin/plugins/index.tsx +15 -15
  10. package/apps/admin/retention-policy/index.tsx +39 -39
  11. package/apps/admin/signing-certificates/index.tsx +343 -343
  12. package/apps/escrow/audit-log/index.tsx +196 -196
  13. package/apps/escrow/matters/[uid].tsx +621 -621
  14. package/apps/shared/appearance/AppearanceForm.tsx +9 -1
  15. package/apps/shared/auth/adminAccess.ts +99 -99
  16. package/apps/shared/calendar/bookingPlugin.ts +100 -0
  17. package/apps/shared/calendar/calendarLiveUpdates.ts +27 -0
  18. package/apps/shared/components/admin/layout/AdminShell.tsx +378 -346
  19. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -0
  20. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
  21. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -0
  22. package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
  23. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
  24. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +53 -4
  25. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
  26. package/apps/shared/components/admin/settings/PluginsManager.tsx +64 -10
  27. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
  28. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
  29. package/apps/shared/components/admin/setup/SetupWizard.tsx +444 -444
  30. package/apps/shared/components/admin/usePagedList.tsx +129 -129
  31. package/apps/shared/components/calendar/AppointmentQuickForm.tsx +327 -0
  32. package/apps/shared/components/calendar/DescriptionEditor.tsx +274 -0
  33. package/apps/shared/components/calendar/EventDescriptionView.tsx +70 -0
  34. package/apps/shared/components/calendar/EventDetails.tsx +401 -0
  35. package/apps/shared/components/calendar/EventEditor.tsx +635 -0
  36. package/apps/shared/components/calendar/EventExpandedForm.tsx +210 -0
  37. package/apps/shared/components/calendar/EventFormParts.tsx +591 -0
  38. package/apps/shared/components/calendar/EventModal.tsx +206 -946
  39. package/apps/shared/components/calendar/EventQuickForm.tsx +116 -0
  40. package/apps/shared/components/calendar/EventShell.tsx +202 -0
  41. package/apps/shared/components/calendar/FindATime.tsx +379 -0
  42. package/apps/shared/components/calendar/GuestInput.tsx +100 -0
  43. package/apps/shared/components/calendar/LazyDescriptionEditor.tsx +70 -0
  44. package/apps/shared/components/calendar/MonthView.tsx +185 -173
  45. package/apps/shared/components/calendar/QuickCreateFaces.tsx +87 -0
  46. package/apps/shared/components/calendar/QuickCreateTabs.tsx +81 -0
  47. package/apps/shared/components/calendar/QuickFaceFrame.tsx +81 -0
  48. package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -222
  49. package/apps/shared/components/calendar/RequestChangeForm.tsx +240 -0
  50. package/apps/shared/components/calendar/SplitDayView.tsx +144 -143
  51. package/apps/shared/components/calendar/TaskQuickForm.tsx +289 -0
  52. package/apps/shared/components/calendar/TimeGridView.tsx +246 -244
  53. package/apps/shared/components/calendar/allDay.ts +124 -124
  54. package/apps/shared/components/calendar/eventDialogFields.ts +86 -0
  55. package/apps/shared/components/calendar/eventForm.ts +108 -0
  56. package/apps/shared/components/calendar/eventFormat.ts +210 -0
  57. package/apps/shared/components/calendar/findTimeGrid.ts +90 -0
  58. package/apps/shared/components/calendar/layout/CalendarShell.tsx +201 -200
  59. package/apps/shared/components/calendar/swipeNavigation.ts +14 -0
  60. package/apps/shared/components/contacts/ContactForm.tsx +383 -383
  61. package/apps/shared/components/contacts/ContactsSidebar.tsx +1 -1
  62. package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -98
  63. package/apps/shared/components/contacts/layout/ContactsShell.tsx +217 -216
  64. package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
  65. package/apps/shared/components/layout/AppShell.tsx +480 -480
  66. package/apps/shared/components/layout/FloatingActionButton.tsx +31 -0
  67. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
  68. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
  69. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
  70. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
  71. package/apps/shared/components/layout/UserMenu.tsx +439 -372
  72. package/apps/shared/components/mail/ConversationList.tsx +323 -271
  73. package/apps/shared/components/mail/ConversationThreadPane.tsx +130 -5
  74. package/apps/shared/components/mail/InviteCard.tsx +387 -0
  75. package/apps/shared/components/mail/MailSelectionBar.tsx +236 -227
  76. package/apps/shared/components/mail/MessageDetailPane.tsx +1559 -1537
  77. package/apps/shared/components/mail/SwipeRow.tsx +120 -0
  78. package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
  79. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
  80. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1673
  81. package/apps/shared/components/mail/compose/RecipientInput.tsx +54 -11
  82. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
  83. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
  84. package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
  85. package/apps/shared/components/mail/invite/InviteRowChip.tsx +104 -0
  86. package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +271 -0
  87. package/apps/shared/components/mail/invite/InviteTimeline.tsx +200 -0
  88. package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +109 -0
  89. package/apps/shared/components/mail/invite/inviteFormat.ts +110 -0
  90. package/apps/shared/components/mail/invite/inviteStore.ts +114 -0
  91. package/apps/shared/components/mail/layout/FolderBadgeChip.tsx +21 -0
  92. package/apps/shared/components/mail/layout/MailShell.tsx +546 -490
  93. package/apps/shared/components/mail/layout/SidebarSection.tsx +66 -0
  94. package/apps/shared/components/mail/reading/PendingMessageCard.tsx +68 -0
  95. package/apps/shared/components/mail/verificationSeals.ts +125 -125
  96. package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
  97. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
  98. package/apps/shared/components/settings/layout/SettingsShell.tsx +255 -253
  99. package/apps/shared/components/tasks/TasksSidebar.tsx +1 -1
  100. package/apps/shared/components/tasks/layout/TasksShell.tsx +218 -217
  101. package/apps/shared/gestures/useEnterSlide.ts +54 -0
  102. package/apps/shared/gestures/useSwipe.ts +114 -0
  103. package/apps/shared/gestures/useSwipeSlide.ts +113 -0
  104. package/apps/shared/gestures/useWheelPaging.ts +107 -0
  105. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
  106. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
  107. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
  108. package/apps/shared/keyboard/dispatch.ts +124 -124
  109. package/apps/shared/keyboard/format.ts +89 -89
  110. package/apps/shared/keyboard/keymap.ts +114 -114
  111. package/apps/shared/keyboard/registry.ts +65 -65
  112. package/apps/shared/keyboard/targets.ts +79 -79
  113. package/apps/shared/mail/folderCounts.ts +17 -0
  114. package/apps/shared/mail/folderTree.ts +143 -143
  115. package/apps/shared/mail/listAllPages.ts +39 -39
  116. package/apps/shared/mail/newMailNotifications.ts +3 -15
  117. package/apps/shared/mail/outbox/outgoingReplies.ts +192 -0
  118. package/apps/shared/mail/outbox/sendJob.ts +19 -1
  119. package/apps/shared/mail/outbox/sendOutcomes.ts +13 -4
  120. package/apps/shared/mail/primaryMailbox.ts +71 -0
  121. package/apps/shared/mail/useCollapsedSections.ts +146 -0
  122. package/apps/shared/mail/useMailConnection.ts +205 -203
  123. package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
  124. package/apps/shared/mail/useMarkMessageRead.ts +47 -47
  125. package/apps/shared/mail/useNewMailNotifications.ts +2 -2
  126. package/apps/shared/navigation/AppRouter.tsx +300 -300
  127. package/apps/shared/navigation/routerContext.tsx +83 -83
  128. package/apps/shared/notifications/preferences.ts +36 -0
  129. package/apps/shared/notifications/store.ts +9 -0
  130. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
  131. package/apps/shared/search/crossMailboxSearch.ts +169 -0
  132. package/apps/shared/search/localIndexBuilder.ts +481 -481
  133. package/apps/shared/signing/enrollmentStorage.ts +33 -33
  134. package/apps/shared/signing/enrollmentTracker.ts +385 -385
  135. package/apps/shared/signing/enrollmentView.ts +251 -251
  136. package/apps/shared/signing/useNow.ts +19 -19
  137. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
  138. package/apps/shared/styles/app.css +396 -386
  139. package/apps/www/_routes.ts +1 -0
  140. package/apps/www/calendar/index.tsx +578 -469
  141. package/apps/www/contacts/[uid].tsx +109 -109
  142. package/apps/www/contacts/index.tsx +6 -0
  143. package/apps/www/index.tsx +2847 -2332
  144. package/apps/www/messages/[uid].tsx +135 -108
  145. package/apps/www/settings/auto-reply/index.tsx +133 -133
  146. package/apps/www/settings/encryption/index.tsx +1287 -1287
  147. package/apps/www/settings/filters/[uid].tsx +176 -176
  148. package/apps/www/settings/filters/index.tsx +102 -102
  149. package/apps/www/settings/filters/new/index.tsx +140 -140
  150. package/apps/www/settings/labels/index.tsx +204 -204
  151. package/apps/www/settings/privacy/index.tsx +492 -492
  152. package/apps/www/settings/profile/index.tsx +248 -0
  153. package/apps/www/settings/read-receipts/index.tsx +147 -147
  154. package/apps/www/settings/sharing/index.tsx +256 -256
  155. package/apps/www/settings/signatures/[uid].tsx +172 -172
  156. package/apps/www/settings/signatures/index.tsx +88 -88
  157. package/apps/www/settings/signatures/new/index.tsx +135 -135
  158. package/apps/www/tasks/index.tsx +649 -649
  159. package/dist/apps/admin/data-requests/index.js +1 -1
  160. package/dist/apps/admin/domains/[uid].js +4 -2
  161. package/dist/apps/admin/index.js +2 -1
  162. package/dist/apps/admin/mailboxes/[uid].js +12 -2
  163. package/dist/apps/shared/appearance/AppearanceForm.js +9 -1
  164. package/dist/apps/shared/calendar/bookingPlugin.d.ts +50 -0
  165. package/dist/apps/shared/calendar/bookingPlugin.js +57 -0
  166. package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +11 -0
  167. package/dist/apps/shared/calendar/calendarLiveUpdates.js +23 -0
  168. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
  169. package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -3
  170. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +35 -0
  171. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +115 -0
  172. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.d.ts +16 -0
  173. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +92 -0
  174. package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
  175. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +28 -4
  176. package/dist/apps/shared/components/admin/settings/PluginsManager.js +40 -6
  177. package/dist/apps/shared/components/calendar/AppointmentQuickForm.d.ts +47 -0
  178. package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +135 -0
  179. package/dist/apps/shared/components/calendar/DescriptionEditor.d.ts +26 -0
  180. package/dist/apps/shared/components/calendar/DescriptionEditor.js +192 -0
  181. package/dist/apps/shared/components/calendar/EventDescriptionView.d.ts +14 -0
  182. package/dist/apps/shared/components/calendar/EventDescriptionView.js +39 -0
  183. package/dist/apps/shared/components/calendar/EventDetails.d.ts +33 -0
  184. package/dist/apps/shared/components/calendar/EventDetails.js +137 -0
  185. package/dist/apps/shared/components/calendar/EventEditor.d.ts +59 -0
  186. package/dist/apps/shared/components/calendar/EventEditor.js +544 -0
  187. package/dist/apps/shared/components/calendar/EventExpandedForm.d.ts +14 -0
  188. package/dist/apps/shared/components/calendar/EventExpandedForm.js +44 -0
  189. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +70 -0
  190. package/dist/apps/shared/components/calendar/EventFormParts.js +191 -0
  191. package/dist/apps/shared/components/calendar/EventModal.d.ts +26 -13
  192. package/dist/apps/shared/components/calendar/EventModal.js +57 -459
  193. package/dist/apps/shared/components/calendar/EventQuickForm.d.ts +18 -0
  194. package/dist/apps/shared/components/calendar/EventQuickForm.js +25 -0
  195. package/dist/apps/shared/components/calendar/EventShell.d.ts +64 -0
  196. package/dist/apps/shared/components/calendar/EventShell.js +134 -0
  197. package/dist/apps/shared/components/calendar/FindATime.d.ts +18 -0
  198. package/dist/apps/shared/components/calendar/FindATime.js +190 -0
  199. package/dist/apps/shared/components/calendar/GuestInput.d.ts +45 -0
  200. package/dist/apps/shared/components/calendar/GuestInput.js +30 -0
  201. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.d.ts +8 -0
  202. package/dist/apps/shared/components/calendar/LazyDescriptionEditor.js +44 -0
  203. package/dist/apps/shared/components/calendar/MonthView.d.ts +5 -1
  204. package/dist/apps/shared/components/calendar/MonthView.js +11 -5
  205. package/dist/apps/shared/components/calendar/QuickCreateFaces.d.ts +30 -0
  206. package/dist/apps/shared/components/calendar/QuickCreateFaces.js +44 -0
  207. package/dist/apps/shared/components/calendar/QuickCreateTabs.d.ts +24 -0
  208. package/dist/apps/shared/components/calendar/QuickCreateTabs.js +46 -0
  209. package/dist/apps/shared/components/calendar/QuickFaceFrame.d.ts +25 -0
  210. package/dist/apps/shared/components/calendar/QuickFaceFrame.js +19 -0
  211. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +4 -1
  212. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +2 -2
  213. package/dist/apps/shared/components/calendar/RequestChangeForm.d.ts +36 -0
  214. package/dist/apps/shared/components/calendar/RequestChangeForm.js +127 -0
  215. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +3 -2
  216. package/dist/apps/shared/components/calendar/SplitDayView.js +3 -2
  217. package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +40 -0
  218. package/dist/apps/shared/components/calendar/TaskQuickForm.js +101 -0
  219. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +4 -2
  220. package/dist/apps/shared/components/calendar/TimeGridView.js +3 -2
  221. package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +28 -0
  222. package/dist/apps/shared/components/calendar/eventDialogFields.js +59 -0
  223. package/dist/apps/shared/components/calendar/eventForm.d.ts +98 -0
  224. package/dist/apps/shared/components/calendar/eventForm.js +1 -0
  225. package/dist/apps/shared/components/calendar/eventFormat.d.ts +80 -0
  226. package/dist/apps/shared/components/calendar/eventFormat.js +190 -0
  227. package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +30 -0
  228. package/dist/apps/shared/components/calendar/findTimeGrid.js +83 -0
  229. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +3 -2
  230. package/dist/apps/shared/components/calendar/swipeNavigation.d.ts +9 -0
  231. package/dist/apps/shared/components/calendar/swipeNavigation.js +8 -0
  232. package/dist/apps/shared/components/contacts/ContactsSidebar.js +1 -1
  233. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  234. package/dist/apps/shared/components/contacts/ContactsToolbar.js +4 -2
  235. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +4 -3
  236. package/dist/apps/shared/components/layout/FloatingActionButton.d.ts +13 -0
  237. package/dist/apps/shared/components/layout/FloatingActionButton.js +9 -0
  238. package/dist/apps/shared/components/layout/UserMenu.d.ts +14 -9
  239. package/dist/apps/shared/components/layout/UserMenu.js +74 -26
  240. package/dist/apps/shared/components/mail/ConversationList.d.ts +12 -1
  241. package/dist/apps/shared/components/mail/ConversationList.js +21 -4
  242. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +4 -1
  243. package/dist/apps/shared/components/mail/ConversationThreadPane.js +127 -22
  244. package/dist/apps/shared/components/mail/InviteCard.d.ts +20 -0
  245. package/dist/apps/shared/components/mail/InviteCard.js +150 -0
  246. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +6 -1
  247. package/dist/apps/shared/components/mail/MailSelectionBar.js +3 -3
  248. package/dist/apps/shared/components/mail/MessageDetailPane.js +13 -2
  249. package/dist/apps/shared/components/mail/SwipeRow.d.ts +22 -0
  250. package/dist/apps/shared/components/mail/SwipeRow.js +71 -0
  251. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +16 -7
  252. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +21 -1
  253. package/dist/apps/shared/components/mail/compose/RecipientInput.js +18 -10
  254. package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +23 -0
  255. package/dist/apps/shared/components/mail/invite/InviteRowChip.js +46 -0
  256. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +20 -0
  257. package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +141 -0
  258. package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +27 -0
  259. package/dist/apps/shared/components/mail/invite/InviteTimeline.js +120 -0
  260. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +17 -0
  261. package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +45 -0
  262. package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +28 -0
  263. package/dist/apps/shared/components/mail/invite/inviteFormat.js +94 -0
  264. package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +28 -0
  265. package/dist/apps/shared/components/mail/invite/inviteStore.js +95 -0
  266. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.d.ts +6 -0
  267. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.js +9 -0
  268. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +10 -0
  269. package/dist/apps/shared/components/mail/layout/MailShell.js +76 -46
  270. package/dist/apps/shared/components/mail/layout/SidebarSection.d.ts +23 -0
  271. package/dist/apps/shared/components/mail/layout/SidebarSection.js +16 -0
  272. package/dist/apps/shared/components/mail/reading/PendingMessageCard.d.ts +14 -0
  273. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +16 -0
  274. package/dist/apps/shared/components/settings/layout/SettingsShell.js +7 -5
  275. package/dist/apps/shared/components/tasks/TasksSidebar.js +1 -1
  276. package/dist/apps/shared/components/tasks/layout/TasksShell.js +4 -3
  277. package/dist/apps/shared/gestures/useEnterSlide.d.ts +14 -0
  278. package/dist/apps/shared/gestures/useEnterSlide.js +47 -0
  279. package/dist/apps/shared/gestures/useSwipe.d.ts +45 -0
  280. package/dist/apps/shared/gestures/useSwipe.js +90 -0
  281. package/dist/apps/shared/gestures/useSwipeSlide.d.ts +40 -0
  282. package/dist/apps/shared/gestures/useSwipeSlide.js +95 -0
  283. package/dist/apps/shared/gestures/useWheelPaging.d.ts +32 -0
  284. package/dist/apps/shared/gestures/useWheelPaging.js +85 -0
  285. package/dist/apps/shared/mail/folderCounts.d.ts +10 -0
  286. package/dist/apps/shared/mail/folderCounts.js +12 -0
  287. package/dist/apps/shared/mail/newMailNotifications.d.ts +3 -8
  288. package/dist/apps/shared/mail/newMailNotifications.js +3 -12
  289. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +80 -0
  290. package/dist/apps/shared/mail/outbox/outgoingReplies.js +131 -0
  291. package/dist/apps/shared/mail/outbox/sendJob.d.ts +5 -1
  292. package/dist/apps/shared/mail/outbox/sendJob.js +14 -1
  293. package/dist/apps/shared/mail/outbox/sendOutcomes.js +13 -4
  294. package/dist/apps/shared/mail/primaryMailbox.d.ts +29 -0
  295. package/dist/apps/shared/mail/primaryMailbox.js +61 -0
  296. package/dist/apps/shared/mail/useCollapsedSections.d.ts +32 -0
  297. package/dist/apps/shared/mail/useCollapsedSections.js +110 -0
  298. package/dist/apps/shared/mail/useMailConnection.js +3 -1
  299. package/dist/apps/shared/mail/useNewMailNotifications.js +3 -2
  300. package/dist/apps/shared/notifications/preferences.d.ts +13 -0
  301. package/dist/apps/shared/notifications/preferences.js +36 -0
  302. package/dist/apps/shared/notifications/store.d.ts +1 -0
  303. package/dist/apps/shared/notifications/store.js +7 -23
  304. package/dist/apps/shared/search/crossMailboxSearch.d.ts +72 -0
  305. package/dist/apps/shared/search/crossMailboxSearch.js +136 -0
  306. package/dist/apps/shared/styles/app.css +396 -386
  307. package/dist/apps/www/_routes.js +1 -0
  308. package/dist/apps/www/calendar/index.js +78 -7
  309. package/dist/apps/www/contacts/index.js +3 -1
  310. package/dist/apps/www/index.js +548 -210
  311. package/dist/apps/www/messages/[uid].js +13 -5
  312. package/dist/apps/www/settings/profile/index.d.ts +4 -0
  313. package/dist/apps/www/settings/profile/index.js +124 -0
  314. package/package.json +2 -2
@@ -0,0 +1,401 @@
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import React, { ReactNode, useEffect, useState } from "react";
6
+ import {
7
+ HiOutlineBars3BottomLeft,
8
+ HiOutlineBell,
9
+ HiOutlineBriefcase,
10
+ HiOutlineCheck,
11
+ HiOutlineClock,
12
+ HiOutlineMapPin,
13
+ HiOutlineUser,
14
+ HiOutlineUserGroup,
15
+ HiOutlineVideoCamera,
16
+ HiOutlineXMark,
17
+ } from "react-icons/hi2";
18
+ import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
19
+ import { AttendeeResponseInput, guestPermissionsOf, respondToEvent, visibilityOf } from "@rapidmx/react-shared/calendar/calendarApi.js";
20
+ import { htmlToPlainText } from "@rapidmx/react-shared/calendar/eventDescription.js";
21
+ import { deleteEventOccurrence, deleteEventSeries } from "@rapidmx/react-shared/calendar/calendarMutations.js";
22
+ import { CalendarOccurrence, describeRecurrence } from "@rapidmx/react-shared/calendar/recurrence.js";
23
+ import { getVideoMeeting } from "@rapidmx/react-shared/videoconf/videoMeetingsApi.js";
24
+ import { deviceTimeZone } from "@rapidmx/react-shared/util/timeZone.js";
25
+ import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
26
+ import Button from "@rapidmx/react-shared/components/buttons/Button.js";
27
+ import { joinMeetingUrl } from "../../calendar/calendarReminders.js";
28
+ import EventDescriptionView from "./EventDescriptionView.js";
29
+ import RequestChangeForm from "./RequestChangeForm.js";
30
+ import { BUSY_STATUS_LABEL, RESPONSE_STATUS_LABEL, VISIBILITY_LABEL, describeGuestPermissions, describeReminder, formatStoredWhen } from "./eventFormat.js";
31
+
32
+ const ROLE_LABEL = { required: "", optional: "Optional", resource: "Room/equipment" } as const;
33
+
34
+ function DetailRow({ icon, children }: { icon: ReactNode; children: ReactNode }) {
35
+ return (
36
+ <div className="flex items-start gap-3">
37
+ <span aria-hidden="true" className="shrink-0 text-text-muted mt-0.5">
38
+ {icon}
39
+ </span>
40
+ <div className="flex-1 min-w-0 break-words">{children}</div>
41
+ </div>
42
+ );
43
+ }
44
+
45
+ export interface EventDetailsProps {
46
+ occurrence: CalendarOccurrence;
47
+ /** Whether this mailbox is invited to the event rather than organizing it: only the organizer can change an event, so there is no
48
+ * Modify, and the mailbox may answer instead. */
49
+ isInvited: boolean;
50
+ /** Set only when this mailbox is an invited attendee (one of the attendees, and not the organizer): the answer it has given so far, which
51
+ * also switches on the Accept / Tentative / Decline block. */
52
+ myResponse?: AttendeeResponseInput | "needsAction";
53
+ /** Whether an address is one of this mailbox's own (its primary address or an alias): tells the reader's own entry from the other guests when the organizer
54
+ * has hidden the guest list. */
55
+ isOwnAddress?: (address: string) => boolean;
56
+ calendarName?: string;
57
+ calendarColor?: string;
58
+ onClose: () => void;
59
+ /** Modify: switch to the edit form. */
60
+ onModify: () => void;
61
+ onSaved: () => void;
62
+ onDeleted: () => void;
63
+ }
64
+
65
+ /**
66
+ * What clicking an existing event shows first: everything the event says, read-only. The reader who organized it (or whose event has no
67
+ * other organizer) can Modify or Delete it; one who was invited can answer (Accept, Tentative, Decline) or remove it from their own
68
+ * calendar, but not change it - the organizer's next update would overwrite that anyway. When the organizer allows guests to ask for changes (or for
69
+ * guests to be added) the invited reader can "Request a change" / "Add guests": the request goes to the organizer (`RequestChangeForm`) and nothing here
70
+ * changes until their update arrives. When the organizer hides the guest list the reader sees only themselves and is told so.
71
+ *
72
+ * An event this reader may only see as a busy block (`occurrence.redacted`: a private or confidential event on a shared calendar) is drawn as just that -
73
+ * its time and that it is busy - with nothing to change, delete or answer.
74
+ */
75
+ export default function EventDetails({
76
+ occurrence,
77
+ isInvited,
78
+ myResponse,
79
+ isOwnAddress,
80
+ calendarName,
81
+ calendarColor,
82
+ onClose,
83
+ onModify,
84
+ onSaved,
85
+ onDeleted,
86
+ }: EventDetailsProps) {
87
+ const [error, setError] = useState<string | null>(null);
88
+ const [busy, setBusy] = useState(false);
89
+ const [confirmingDelete, setConfirmingDelete] = useState(false);
90
+ const [requesting, setRequesting] = useState(false);
91
+ // The organizer's own join link for the event's video meeting: `undefined` while it is fetched, `null` once known to be none.
92
+ const [organizerJoinUrl, setOrganizerJoinUrl] = useState<string | null | undefined>(undefined);
93
+ const videoMeetingUid = occurrence.videoMeetingUid;
94
+
95
+ // The link lives on the meeting, not on the event, so it is fetched once here. A failure and a meeting with no link at all are the
96
+ // same thing to this view - there is nothing to open either way - so both settle on `null`.
97
+ useEffect(() => {
98
+ if (!videoMeetingUid) {
99
+ return;
100
+ }
101
+ let cancelled = false;
102
+ void getVideoMeeting(videoMeetingUid)
103
+ .then((meeting) => meeting.organizerJoinUrl ?? null)
104
+ .catch(() => null)
105
+ .then((url) => {
106
+ if (!cancelled) {
107
+ setOrganizerJoinUrl(url);
108
+ }
109
+ });
110
+ return () => {
111
+ cancelled = true;
112
+ };
113
+ }, [videoMeetingUid]);
114
+ // The same scheme allow-list a reminder's own location gets: a hostile or malformed join link never reaches `window.open()`.
115
+ const joinUrl = joinMeetingUrl(organizerJoinUrl);
116
+
117
+ async function handleDelete(scope: "occurrence" | "series") {
118
+ setError(null);
119
+ setBusy(true);
120
+ try {
121
+ if (occurrence.isRecurringOccurrence && scope === "occurrence") {
122
+ await deleteEventOccurrence(occurrence);
123
+ } else {
124
+ await deleteEventSeries(occurrence);
125
+ }
126
+ onDeleted();
127
+ } catch (err) {
128
+ setError(err instanceof ApiRequestError ? err.message : "Could not delete this event.");
129
+ setBusy(false);
130
+ }
131
+ }
132
+
133
+ // `@rapidmx/restapi`'s `respond()` route has no occurrence-vs-series scope of its own (see `calendarApi.ts`'s `respondToEvent` doc
134
+ // comment) - it always acts on `occurrence.uid` as a single event document.
135
+ async function handleRespond(responseStatus: AttendeeResponseInput) {
136
+ setError(null);
137
+ setBusy(true);
138
+ try {
139
+ await respondToEvent(occurrence.uid, responseStatus);
140
+ // A decline soft-deletes the mailbox's own copy server-side - treat it the same as a
141
+ // delete rather than a save so the calendar view drops it immediately.
142
+ if (responseStatus === "declined") {
143
+ onDeleted();
144
+ } else {
145
+ onSaved();
146
+ }
147
+ } catch (err) {
148
+ setError(err instanceof ApiRequestError ? err.message : "Could not send your response.");
149
+ setBusy(false);
150
+ }
151
+ }
152
+
153
+ if (occurrence.redacted) {
154
+ return (
155
+ <div className="flex flex-col">
156
+ <div className="flex items-start gap-3 px-5 pt-4">
157
+ <span aria-hidden="true" className="w-3.5 h-3.5 rounded-full shrink-0 mt-2" style={{ backgroundColor: calendarColor }} />
158
+ <h2 className="flex-1 min-w-0 text-xl font-semibold break-words">Busy</h2>
159
+ <button
160
+ type="button"
161
+ aria-label="Close details"
162
+ onClick={onClose}
163
+ className="w-8 h-8 shrink-0 flex items-center justify-center rounded-full text-text-muted hover:bg-surface-alt hover:text-text"
164
+ >
165
+ <HiOutlineXMark size={20} aria-hidden="true" />
166
+ </button>
167
+ </div>
168
+ <div className="flex flex-col gap-3 px-5 pt-3 pb-4 text-sm">
169
+ <DetailRow icon={<HiOutlineClock size={18} />}>
170
+ <div>{formatStoredWhen(occurrence.startDate, occurrence.endDate, occurrence.allDay)}</div>
171
+ {occurrence.recurrenceRule && <div className="text-text-muted">Repeats {describeRecurrence(occurrence.recurrenceRule)}</div>}
172
+ </DetailRow>
173
+ <p className="text-xs text-text-muted">This time is busy. The event&rsquo;s details are private, so only its time is shown.</p>
174
+ </div>
175
+ <div className="flex px-5 pb-4">
176
+ <Button type="button" variant="secondary" className="!w-auto ml-auto" onClick={onClose}>
177
+ Close
178
+ </Button>
179
+ </div>
180
+ </div>
181
+ );
182
+ }
183
+
184
+ const permissions = guestPermissionsOf(occurrence);
185
+ // The organizer hid the guest list: this mailbox's own copy lists only itself (the server sends nothing more), and that is all that is shown.
186
+ const hiddenList = isInvited && !permissions.guestsCanSeeGuestList;
187
+ const allGuests = occurrence.attendees.filter((a) => !a.isOrganizer);
188
+ const guests = hiddenList ? allGuests.filter((a) => !!isOwnAddress?.(a.address)) : allGuests;
189
+ const hasDescription = htmlToPlainText(occurrence.descriptionHtml) !== "" || !!occurrence.description?.trim();
190
+ // An invited reader may ask the organizer for what the organizer allows.
191
+ const askable = isInvited && myResponse !== undefined;
192
+ const canChange = askable && permissions.guestsCanModify;
193
+ const canInvite = askable && permissions.guestsCanInviteOthers;
194
+ const organizerName = occurrence.organizer.displayName;
195
+ const eventZone = occurrence.timezone;
196
+ const answers: { response: AttendeeResponseInput; label: string }[] = [
197
+ { response: "accepted", label: "Accept" },
198
+ { response: "tentative", label: "Tentative" },
199
+ { response: "declined", label: "Decline" },
200
+ ];
201
+
202
+ return (
203
+ <div className="flex flex-col">
204
+ <div className="flex items-start gap-3 px-5 pt-4">
205
+ <span aria-hidden="true" className="w-3.5 h-3.5 rounded-full shrink-0 mt-2" style={{ backgroundColor: calendarColor }} />
206
+ <h2 className="flex-1 min-w-0 text-xl font-semibold break-words">{occurrence.title || "(no title)"}</h2>
207
+ <button
208
+ type="button"
209
+ aria-label="Close details"
210
+ onClick={onClose}
211
+ className="w-8 h-8 shrink-0 flex items-center justify-center rounded-full text-text-muted hover:bg-surface-alt hover:text-text"
212
+ >
213
+ <HiOutlineXMark size={20} aria-hidden="true" />
214
+ </button>
215
+ </div>
216
+
217
+ <div className="flex flex-col gap-3 px-5 pt-3 pb-4 text-sm">
218
+ {error && <Alert>{error}</Alert>}
219
+
220
+ <DetailRow icon={<HiOutlineClock size={18} />}>
221
+ <div>{formatStoredWhen(occurrence.startDate, occurrence.endDate, occurrence.allDay)}</div>
222
+ {occurrence.recurrenceRule && <div className="text-text-muted">Repeats {describeRecurrence(occurrence.recurrenceRule)}</div>}
223
+ {!occurrence.allDay && eventZone && eventZone !== deviceTimeZone() && (
224
+ <div className="text-text-muted">Event time zone: {eventZone.replace(/_/g, " ")}</div>
225
+ )}
226
+ </DetailRow>
227
+
228
+ {occurrence.location && (
229
+ <DetailRow icon={<HiOutlineMapPin size={18} />}>
230
+ <div>{occurrence.location}</div>
231
+ </DetailRow>
232
+ )}
233
+
234
+ {hasDescription && (
235
+ <DetailRow icon={<HiOutlineBars3BottomLeft size={18} />}>
236
+ <EventDescriptionView html={occurrence.descriptionHtml} text={occurrence.description} />
237
+ </DetailRow>
238
+ )}
239
+
240
+ {videoMeetingUid && (
241
+ <DetailRow icon={<HiOutlineVideoCamera size={18} />}>
242
+ <div className="flex items-center gap-3 flex-wrap">
243
+ <Button
244
+ type="button"
245
+ variant="secondary"
246
+ className="!w-auto"
247
+ disabled={!joinUrl}
248
+ onClick={() => window.open(joinUrl, "_blank", "noopener,noreferrer")}
249
+ >
250
+ Join video call
251
+ </Button>
252
+ {!joinUrl && (
253
+ <span className="text-xs text-text-muted">
254
+ {organizerJoinUrl === undefined ? "Loading the join link…" : "This meeting’s join link isn’t available."}
255
+ </span>
256
+ )}
257
+ </div>
258
+ </DetailRow>
259
+ )}
260
+
261
+ <DetailRow icon={<HiOutlineUser size={18} />}>
262
+ <div>{organizerName || occurrence.organizer.address}</div>
263
+ <div className="text-text-muted">
264
+ {organizerName ? `${occurrence.organizer.address} · ` : ""}Organizer
265
+ </div>
266
+ </DetailRow>
267
+
268
+ {(guests.length > 0 || hiddenList) && (
269
+ <DetailRow icon={<HiOutlineUserGroup size={18} />}>
270
+ <div className="font-medium mb-1">
271
+ {hiddenList ? "The organizer has hidden the guest list" : guests.length === 1 ? "1 guest" : `${guests.length} guests`}
272
+ </div>
273
+ <ul className="flex flex-col gap-1">
274
+ {guests.map((guest, i) => (
275
+ <li key={i} className="flex items-baseline justify-between gap-3">
276
+ <span className="min-w-0 truncate">
277
+ {guest.displayName || guest.address}
278
+ {ROLE_LABEL[guest.role] && <span className="text-text-muted"> ({ROLE_LABEL[guest.role]})</span>}
279
+ </span>
280
+ <span className="shrink-0 text-xs text-text-muted">{RESPONSE_STATUS_LABEL[guest.responseStatus]}</span>
281
+ </li>
282
+ ))}
283
+ </ul>
284
+ {!isInvited && <div className="text-xs text-text-muted mt-1">{describeGuestPermissions(permissions)}</div>}
285
+ </DetailRow>
286
+ )}
287
+
288
+ <DetailRow icon={<HiOutlineBriefcase size={18} />}>
289
+ <div>{BUSY_STATUS_LABEL[occurrence.busyStatus]}</div>
290
+ <div className="text-text-muted">{VISIBILITY_LABEL[visibilityOf(occurrence)]}</div>
291
+ {occurrence.autoReplyEnabled && (
292
+ <div className="text-text-muted">Sends an automatic reply while this event is happening</div>
293
+ )}
294
+ </DetailRow>
295
+
296
+ <DetailRow icon={<HiOutlineBell size={18} />}>
297
+ <div>{describeReminder(occurrence.reminderMinutesBeforeStart)}</div>
298
+ </DetailRow>
299
+
300
+ {calendarName && (
301
+ <div className="flex items-center gap-3 text-text-muted">
302
+ <span aria-hidden="true" className="w-3 h-3 ml-[3px] rounded-full shrink-0" style={{ backgroundColor: calendarColor }} />
303
+ <span className="truncate">{calendarName}</span>
304
+ </div>
305
+ )}
306
+
307
+ {isInvited && (
308
+ <p className="text-xs text-text-muted">
309
+ You were invited to this event. Only the organizer can change its details
310
+ {canChange || canInvite ? ", but you can ask them to." : "."}
311
+ </p>
312
+ )}
313
+ </div>
314
+
315
+ {requesting && (
316
+ <div className="mx-5 mb-3 p-3 rounded-md bg-surface-alt">
317
+ <RequestChangeForm
318
+ subject={{
319
+ uid: occurrence.uid,
320
+ title: occurrence.title,
321
+ location: occurrence.location,
322
+ startDate: occurrence.startDate,
323
+ endDate: occurrence.endDate,
324
+ allDay: occurrence.allDay,
325
+ recurring: occurrence.isRecurringOccurrence,
326
+ description: occurrence.description,
327
+ descriptionHtml: occurrence.descriptionHtml,
328
+ guestAddresses: occurrence.attendees.map((a) => a.address),
329
+ }}
330
+ canChange={canChange}
331
+ canInvite={canInvite}
332
+ onSent={() => setRequesting(false)}
333
+ onCancel={() => setRequesting(false)}
334
+ />
335
+ </div>
336
+ )}
337
+
338
+ {myResponse !== undefined && (
339
+ <div className="flex flex-col gap-2 mx-5 mb-3 p-3 rounded-md bg-surface-alt">
340
+ <div className="flex items-center justify-between gap-3 flex-wrap">
341
+ <span className="text-sm font-medium">Your response</span>
342
+ <div className="flex gap-2">
343
+ {answers.map(({ response, label }) => {
344
+ const current = myResponse === response;
345
+ return (
346
+ <Button
347
+ key={response}
348
+ type="button"
349
+ variant="secondary"
350
+ className={["!w-auto", response === "declined" ? "text-danger" : "", current ? "!bg-primary/10 !border-primary" : ""].join(" ")}
351
+ aria-pressed={current}
352
+ disabled={busy}
353
+ onClick={() => void handleRespond(response)}
354
+ >
355
+ {current && <HiOutlineCheck size={14} aria-hidden="true" />}
356
+ {label}
357
+ </Button>
358
+ );
359
+ })}
360
+ </div>
361
+ </div>
362
+ <p className="text-xs text-text-muted">Other attendees&rsquo; responses may take a few minutes to update.</p>
363
+ </div>
364
+ )}
365
+
366
+ <div className="flex flex-wrap items-center gap-3 px-5 pb-4">
367
+ {!isInvited && (
368
+ <Button type="button" className="!w-auto" disabled={busy} onClick={onModify}>
369
+ Modify
370
+ </Button>
371
+ )}
372
+ {(canChange || canInvite) && !requesting && (
373
+ <Button type="button" variant="secondary" className="!w-auto" disabled={busy} onClick={() => setRequesting(true)}>
374
+ {canChange ? "Request a change" : "Add guests"}
375
+ </Button>
376
+ )}
377
+ {!occurrence.isRecurringOccurrence ? (
378
+ <Button type="button" variant="secondary" className="!w-auto text-danger" disabled={busy} onClick={() => void handleDelete("series")}>
379
+ Delete
380
+ </Button>
381
+ ) : !confirmingDelete ? (
382
+ <Button type="button" variant="secondary" className="!w-auto text-danger" disabled={busy} onClick={() => setConfirmingDelete(true)}>
383
+ Delete
384
+ </Button>
385
+ ) : (
386
+ <div className="flex gap-2">
387
+ <Button type="button" variant="secondary" className="!w-auto text-danger" disabled={busy} onClick={() => void handleDelete("occurrence")}>
388
+ Delete this event
389
+ </Button>
390
+ <Button type="button" variant="secondary" className="!w-auto text-danger" disabled={busy} onClick={() => void handleDelete("series")}>
391
+ Delete series
392
+ </Button>
393
+ </div>
394
+ )}
395
+ <Button type="button" variant="secondary" className="!w-auto ml-auto" onClick={onClose}>
396
+ Close
397
+ </Button>
398
+ </div>
399
+ </div>
400
+ );
401
+ }