@rapidmx/web-client 0.15.1 → 0.17.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 (318) hide show
  1. package/README.md +381 -373
  2. package/apps/admin/branding/index.tsx +39 -39
  3. package/apps/admin/data-requests/index.tsx +482 -480
  4. package/apps/admin/distribution-lists/new/index.tsx +3 -1
  5. package/apps/admin/domains/[uid].tsx +166 -164
  6. package/apps/admin/domains/new/index.tsx +3 -1
  7. package/apps/admin/escrow-scopes/[uid].tsx +350 -348
  8. package/apps/admin/escrow-scopes/new/index.tsx +3 -1
  9. package/apps/admin/index.tsx +129 -124
  10. package/apps/admin/mailboxes/[uid].tsx +271 -224
  11. package/apps/admin/mailboxes/new/index.tsx +30 -28
  12. package/apps/admin/plugins/index.tsx +15 -15
  13. package/apps/admin/retention-policy/index.tsx +39 -39
  14. package/apps/admin/signing-certificates/index.tsx +343 -343
  15. package/apps/admin/transport-rules/new/index.tsx +3 -1
  16. package/apps/escrow/audit-log/index.tsx +196 -196
  17. package/apps/escrow/matters/[uid].tsx +621 -621
  18. package/apps/escrow/matters/new/index.tsx +3 -1
  19. package/apps/shared/auth/adminAccess.ts +99 -99
  20. package/apps/shared/components/admin/layout/AdminShell.tsx +381 -378
  21. package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -0
  22. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
  23. package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -0
  24. package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
  25. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
  26. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +50 -3
  27. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
  28. package/apps/shared/components/admin/settings/PluginsManager.tsx +1545 -1545
  29. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
  30. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
  31. package/apps/shared/components/admin/setup/SetupWizard.tsx +446 -444
  32. package/apps/shared/components/admin/usePagedList.tsx +129 -129
  33. package/apps/shared/components/calendar/EventEditor.tsx +5 -10
  34. package/apps/shared/components/calendar/EventFormParts.tsx +16 -47
  35. package/apps/shared/components/calendar/EventModal.tsx +206 -206
  36. package/apps/shared/components/calendar/GuestInput.tsx +100 -0
  37. package/apps/shared/components/calendar/MonthView.tsx +185 -185
  38. package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -227
  39. package/apps/shared/components/calendar/RequestChangeForm.tsx +23 -54
  40. package/apps/shared/components/calendar/SplitDayView.tsx +144 -144
  41. package/apps/shared/components/calendar/TimeGridView.tsx +246 -246
  42. package/apps/shared/components/calendar/allDay.ts +124 -124
  43. package/apps/shared/components/calendar/eventForm.ts +2 -2
  44. package/apps/shared/components/calendar/eventFormat.ts +49 -22
  45. package/apps/shared/components/calendar/layout/CalendarShell.tsx +201 -200
  46. package/apps/shared/components/contacts/ContactForm.tsx +383 -383
  47. package/apps/shared/components/contacts/ContactsSidebar.tsx +1 -1
  48. package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -98
  49. package/apps/shared/components/contacts/layout/ContactsShell.tsx +218 -216
  50. package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
  51. package/apps/shared/components/layout/AppShell.tsx +461 -480
  52. package/apps/shared/components/layout/FloatingActionButton.tsx +31 -0
  53. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
  54. package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
  55. package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
  56. package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
  57. package/apps/shared/components/layout/UserMenu.tsx +439 -424
  58. package/apps/shared/components/mail/ConversationList.tsx +323 -323
  59. package/apps/shared/components/mail/ConversationThreadPane.tsx +613 -491
  60. package/apps/shared/components/mail/EmptyFolderBar.tsx +41 -0
  61. package/apps/shared/components/mail/MailSelectionBar.tsx +240 -227
  62. package/apps/shared/components/mail/MenuButton.tsx +31 -11
  63. package/apps/shared/components/mail/MessageDetailPane.tsx +1757 -1559
  64. package/apps/shared/components/mail/PermanentDeleteDialog.tsx +47 -0
  65. package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
  66. package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
  67. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1677
  68. package/apps/shared/components/mail/compose/RecipientInput.tsx +54 -11
  69. package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
  70. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
  71. package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
  72. package/apps/shared/components/mail/layout/FolderBadgeChip.tsx +21 -0
  73. package/apps/shared/components/mail/layout/MailShell.tsx +161 -134
  74. package/apps/shared/components/mail/layout/SidebarSection.tsx +66 -0
  75. package/apps/shared/components/mail/reading/MessageMoreMenu.tsx +258 -0
  76. package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +79 -0
  77. package/apps/shared/components/mail/reading/PendingMessageCard.tsx +68 -0
  78. package/apps/shared/components/mail/reading/messageExport.ts +59 -0
  79. package/apps/shared/components/mail/reading/printMessage.ts +99 -0
  80. package/apps/shared/components/mail/reading/useMessageActions.ts +443 -0
  81. package/apps/shared/components/mail/verificationSeals.ts +125 -125
  82. package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
  83. package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
  84. package/apps/shared/components/settings/layout/SettingsShell.tsx +257 -254
  85. package/apps/shared/components/tasks/TasksSidebar.tsx +1 -1
  86. package/apps/shared/components/tasks/layout/TasksShell.tsx +219 -217
  87. package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
  88. package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
  89. package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
  90. package/apps/shared/keyboard/dispatch.ts +124 -124
  91. package/apps/shared/keyboard/format.ts +89 -89
  92. package/apps/shared/keyboard/keymap.ts +114 -114
  93. package/apps/shared/keyboard/registry.ts +65 -65
  94. package/apps/shared/keyboard/targets.ts +79 -79
  95. package/apps/shared/mail/folderCounts.ts +17 -0
  96. package/apps/shared/mail/folderOfType.ts +49 -0
  97. package/apps/shared/mail/folderTree.ts +143 -143
  98. package/apps/shared/mail/listAllPages.ts +39 -39
  99. package/apps/shared/mail/newMailNotifications.ts +171 -171
  100. package/apps/shared/mail/outbox/outgoingReplies.ts +192 -0
  101. package/apps/shared/mail/outbox/sendJob.ts +19 -1
  102. package/apps/shared/mail/outbox/sendOutcomes.ts +13 -4
  103. package/apps/shared/mail/permanentDelete.ts +160 -0
  104. package/apps/shared/mail/primaryMailbox.ts +71 -0
  105. package/apps/shared/mail/reportNotices.ts +66 -0
  106. package/apps/shared/mail/senderBlocking.ts +141 -0
  107. package/apps/shared/mail/useCollapsedSections.ts +146 -0
  108. package/apps/shared/mail/useMailConnection.ts +205 -203
  109. package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
  110. package/apps/shared/mail/useMailboxUpdateAccess.ts +60 -0
  111. package/apps/shared/mail/useMarkMessageRead.ts +47 -47
  112. package/apps/shared/mail/useNewMailNotifications.ts +178 -178
  113. package/apps/shared/mail/usePermanentDelete.tsx +160 -0
  114. package/apps/shared/navigation/frameContext.tsx +1 -1
  115. package/apps/shared/navigation/index.ts +43 -0
  116. package/apps/shared/navigation/pageTitle.ts +19 -0
  117. package/apps/shared/notifications/store.ts +560 -560
  118. package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
  119. package/apps/shared/search/crossMailboxSearch.ts +169 -0
  120. package/apps/shared/search/localIndexBuilder.ts +481 -481
  121. package/apps/shared/signing/enrollmentStorage.ts +33 -33
  122. package/apps/shared/signing/enrollmentTracker.ts +385 -385
  123. package/apps/shared/signing/enrollmentView.ts +251 -251
  124. package/apps/shared/signing/useNow.ts +19 -19
  125. package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
  126. package/apps/shared/styles/app.css +396 -386
  127. package/apps/www/_shell.tsx +82 -0
  128. package/apps/www/calendar/index.tsx +581 -571
  129. package/apps/www/contacts/[uid].tsx +112 -109
  130. package/apps/www/contacts/index.tsx +14 -3
  131. package/apps/www/index.tsx +2962 -2479
  132. package/apps/www/messages/[uid].tsx +139 -135
  133. package/apps/www/settings/appearance/index.tsx +5 -2
  134. package/apps/www/settings/auto-reply/index.tsx +136 -133
  135. package/apps/www/settings/blocked-senders/index.tsx +303 -0
  136. package/apps/www/settings/encryption/index.tsx +1290 -1287
  137. package/apps/www/settings/filters/[uid].tsx +179 -176
  138. package/apps/www/settings/filters/index.tsx +105 -102
  139. package/apps/www/settings/filters/new/index.tsx +165 -140
  140. package/apps/www/settings/labels/index.tsx +207 -204
  141. package/apps/www/settings/privacy/index.tsx +495 -492
  142. package/apps/www/settings/profile/index.tsx +251 -248
  143. package/apps/www/settings/read-receipts/index.tsx +150 -147
  144. package/apps/www/settings/sharing/index.tsx +259 -256
  145. package/apps/www/settings/signatures/[uid].tsx +175 -172
  146. package/apps/www/settings/signatures/index.tsx +91 -88
  147. package/apps/www/settings/signatures/new/index.tsx +138 -135
  148. package/apps/www/tasks/index.tsx +654 -649
  149. package/dist/apps/admin/data-requests/index.js +1 -1
  150. package/dist/apps/admin/distribution-lists/new/index.js +3 -1
  151. package/dist/apps/admin/domains/[uid].js +3 -1
  152. package/dist/apps/admin/domains/new/index.js +3 -1
  153. package/dist/apps/admin/escrow-scopes/[uid].js +3 -1
  154. package/dist/apps/admin/escrow-scopes/new/index.js +3 -1
  155. package/dist/apps/admin/index.js +5 -2
  156. package/dist/apps/admin/mailboxes/[uid].js +15 -3
  157. package/dist/apps/admin/mailboxes/new/index.js +3 -1
  158. package/dist/apps/admin/transport-rules/new/index.js +3 -1
  159. package/dist/apps/escrow/matters/new/index.js +3 -1
  160. package/dist/apps/shared/components/admin/layout/AdminShell.js +6 -3
  161. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +35 -0
  162. package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +115 -0
  163. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.d.ts +16 -0
  164. package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +92 -0
  165. package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
  166. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +25 -3
  167. package/dist/apps/shared/components/admin/setup/SetupWizard.js +3 -1
  168. package/dist/apps/shared/components/calendar/EventEditor.js +5 -10
  169. package/dist/apps/shared/components/calendar/EventFormParts.d.ts +3 -2
  170. package/dist/apps/shared/components/calendar/EventFormParts.js +5 -16
  171. package/dist/apps/shared/components/calendar/GuestInput.d.ts +45 -0
  172. package/dist/apps/shared/components/calendar/GuestInput.js +30 -0
  173. package/dist/apps/shared/components/calendar/RequestChangeForm.js +11 -22
  174. package/dist/apps/shared/components/calendar/eventForm.d.ts +2 -2
  175. package/dist/apps/shared/components/calendar/eventFormat.d.ts +21 -8
  176. package/dist/apps/shared/components/calendar/eventFormat.js +50 -23
  177. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +5 -4
  178. package/dist/apps/shared/components/contacts/ContactsSidebar.js +1 -1
  179. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
  180. package/dist/apps/shared/components/contacts/ContactsToolbar.js +4 -2
  181. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +7 -5
  182. package/dist/apps/shared/components/layout/AppShell.d.ts +8 -11
  183. package/dist/apps/shared/components/layout/AppShell.js +24 -33
  184. package/dist/apps/shared/components/layout/FloatingActionButton.d.ts +13 -0
  185. package/dist/apps/shared/components/layout/FloatingActionButton.js +9 -0
  186. package/dist/apps/shared/components/layout/UserMenu.d.ts +4 -1
  187. package/dist/apps/shared/components/layout/UserMenu.js +6 -5
  188. package/dist/apps/shared/components/mail/ConversationThreadPane.js +127 -22
  189. package/dist/apps/shared/components/mail/EmptyFolderBar.d.ts +18 -0
  190. package/dist/apps/shared/components/mail/EmptyFolderBar.js +10 -0
  191. package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +14 -4
  192. package/dist/apps/shared/components/mail/MailSelectionBar.js +11 -13
  193. package/dist/apps/shared/components/mail/MenuButton.d.ts +9 -2
  194. package/dist/apps/shared/components/mail/MenuButton.js +15 -11
  195. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +5 -0
  196. package/dist/apps/shared/components/mail/MessageDetailPane.js +147 -7
  197. package/dist/apps/shared/components/mail/PermanentDeleteDialog.d.ts +19 -0
  198. package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +11 -0
  199. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +8 -4
  200. package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +21 -1
  201. package/dist/apps/shared/components/mail/compose/RecipientInput.js +18 -10
  202. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.d.ts +6 -0
  203. package/dist/apps/shared/components/mail/layout/FolderBadgeChip.js +9 -0
  204. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +16 -7
  205. package/dist/apps/shared/components/mail/layout/MailShell.js +78 -65
  206. package/dist/apps/shared/components/mail/layout/SidebarSection.d.ts +23 -0
  207. package/dist/apps/shared/components/mail/layout/SidebarSection.js +16 -0
  208. package/dist/apps/shared/components/mail/reading/MessageMoreMenu.d.ts +56 -0
  209. package/dist/apps/shared/components/mail/reading/MessageMoreMenu.js +153 -0
  210. package/dist/apps/shared/components/mail/reading/MessageSourceDialog.d.ts +27 -0
  211. package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +27 -0
  212. package/dist/apps/shared/components/mail/reading/PendingMessageCard.d.ts +14 -0
  213. package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +16 -0
  214. package/dist/apps/shared/components/mail/reading/messageExport.d.ts +19 -0
  215. package/dist/apps/shared/components/mail/reading/messageExport.js +51 -0
  216. package/dist/apps/shared/components/mail/reading/printMessage.d.ts +30 -0
  217. package/dist/apps/shared/components/mail/reading/printMessage.js +70 -0
  218. package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +57 -0
  219. package/dist/apps/shared/components/mail/reading/useMessageActions.js +366 -0
  220. package/dist/apps/shared/components/settings/layout/SettingsShell.js +10 -7
  221. package/dist/apps/shared/components/tasks/TasksSidebar.js +1 -1
  222. package/dist/apps/shared/components/tasks/layout/TasksShell.js +7 -5
  223. package/dist/apps/shared/keyboard/GlobalShortcuts.js +1 -1
  224. package/dist/apps/shared/mail/folderCounts.d.ts +10 -0
  225. package/dist/apps/shared/mail/folderCounts.js +12 -0
  226. package/dist/apps/shared/mail/folderOfType.d.ts +13 -0
  227. package/dist/apps/shared/mail/folderOfType.js +40 -0
  228. package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +80 -0
  229. package/dist/apps/shared/mail/outbox/outgoingReplies.js +131 -0
  230. package/dist/apps/shared/mail/outbox/sendJob.d.ts +5 -1
  231. package/dist/apps/shared/mail/outbox/sendJob.js +14 -1
  232. package/dist/apps/shared/mail/outbox/sendOutcomes.js +13 -4
  233. package/dist/apps/shared/mail/permanentDelete.d.ts +62 -0
  234. package/dist/apps/shared/mail/permanentDelete.js +127 -0
  235. package/dist/apps/shared/mail/primaryMailbox.d.ts +29 -0
  236. package/dist/apps/shared/mail/primaryMailbox.js +61 -0
  237. package/dist/apps/shared/mail/reportNotices.d.ts +21 -0
  238. package/dist/apps/shared/mail/reportNotices.js +47 -0
  239. package/dist/apps/shared/mail/senderBlocking.d.ts +26 -0
  240. package/dist/apps/shared/mail/senderBlocking.js +92 -0
  241. package/dist/apps/shared/mail/useCollapsedSections.d.ts +32 -0
  242. package/dist/apps/shared/mail/useCollapsedSections.js +110 -0
  243. package/dist/apps/shared/mail/useMailConnection.js +3 -1
  244. package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +11 -0
  245. package/dist/apps/shared/mail/useMailboxUpdateAccess.js +52 -0
  246. package/dist/apps/shared/mail/usePermanentDelete.d.ts +35 -0
  247. package/dist/apps/shared/mail/usePermanentDelete.js +96 -0
  248. package/dist/apps/shared/navigation/frameContext.d.ts +1 -1
  249. package/dist/apps/shared/navigation/index.d.ts +16 -0
  250. package/dist/apps/shared/navigation/index.js +34 -0
  251. package/dist/apps/shared/navigation/pageTitle.d.ts +11 -0
  252. package/dist/apps/shared/navigation/pageTitle.js +12 -0
  253. package/dist/apps/shared/search/crossMailboxSearch.d.ts +72 -0
  254. package/dist/apps/shared/search/crossMailboxSearch.js +136 -0
  255. package/dist/apps/shared/styles/app.css +396 -386
  256. package/dist/apps/www/_shell.d.ts +26 -0
  257. package/dist/apps/www/_shell.js +31 -0
  258. package/dist/apps/www/calendar/index.d.ts +7 -2
  259. package/dist/apps/www/calendar/index.js +7 -4
  260. package/dist/apps/www/contacts/[uid].d.ts +14 -3
  261. package/dist/apps/www/contacts/[uid].js +5 -3
  262. package/dist/apps/www/contacts/index.d.ts +7 -2
  263. package/dist/apps/www/contacts/index.js +8 -4
  264. package/dist/apps/www/index.d.ts +7 -2
  265. package/dist/apps/www/index.js +542 -207
  266. package/dist/apps/www/messages/[uid].d.ts +14 -3
  267. package/dist/apps/www/messages/[uid].js +7 -5
  268. package/dist/apps/www/settings/appearance/index.d.ts +8 -2
  269. package/dist/apps/www/settings/appearance/index.js +4 -2
  270. package/dist/apps/www/settings/auto-reply/index.d.ts +7 -2
  271. package/dist/apps/www/settings/auto-reply/index.js +4 -2
  272. package/dist/apps/www/settings/blocked-senders/index.d.ts +9 -0
  273. package/dist/apps/www/settings/blocked-senders/index.js +134 -0
  274. package/dist/apps/www/settings/encryption/index.d.ts +7 -2
  275. package/dist/apps/www/settings/encryption/index.js +4 -2
  276. package/dist/apps/www/settings/filters/[uid].d.ts +7 -2
  277. package/dist/apps/www/settings/filters/[uid].js +4 -2
  278. package/dist/apps/www/settings/filters/index.d.ts +7 -2
  279. package/dist/apps/www/settings/filters/index.js +4 -2
  280. package/dist/apps/www/settings/filters/new/index.d.ts +7 -2
  281. package/dist/apps/www/settings/filters/new/index.js +28 -5
  282. package/dist/apps/www/settings/labels/index.d.ts +7 -2
  283. package/dist/apps/www/settings/labels/index.js +4 -2
  284. package/dist/apps/www/settings/privacy/index.d.ts +7 -2
  285. package/dist/apps/www/settings/privacy/index.js +4 -2
  286. package/dist/apps/www/settings/profile/index.d.ts +7 -2
  287. package/dist/apps/www/settings/profile/index.js +4 -2
  288. package/dist/apps/www/settings/read-receipts/index.d.ts +7 -2
  289. package/dist/apps/www/settings/read-receipts/index.js +4 -2
  290. package/dist/apps/www/settings/sharing/index.d.ts +7 -2
  291. package/dist/apps/www/settings/sharing/index.js +4 -2
  292. package/dist/apps/www/settings/signatures/[uid].d.ts +7 -2
  293. package/dist/apps/www/settings/signatures/[uid].js +4 -2
  294. package/dist/apps/www/settings/signatures/index.d.ts +7 -2
  295. package/dist/apps/www/settings/signatures/index.js +4 -2
  296. package/dist/apps/www/settings/signatures/new/index.d.ts +7 -2
  297. package/dist/apps/www/settings/signatures/new/index.js +5 -3
  298. package/dist/apps/www/tasks/index.d.ts +7 -2
  299. package/dist/apps/www/tasks/index.js +5 -3
  300. package/package.json +4 -2
  301. package/apps/shared/navigation/AppRouter.tsx +0 -300
  302. package/apps/shared/navigation/idle.ts +0 -45
  303. package/apps/shared/navigation/routerContext.tsx +0 -83
  304. package/apps/shared/navigation/routes.ts +0 -72
  305. package/apps/www/_routedPage.tsx +0 -24
  306. package/apps/www/_routes.ts +0 -37
  307. package/dist/apps/shared/navigation/AppRouter.d.ts +0 -52
  308. package/dist/apps/shared/navigation/AppRouter.js +0 -242
  309. package/dist/apps/shared/navigation/idle.d.ts +0 -14
  310. package/dist/apps/shared/navigation/idle.js +0 -43
  311. package/dist/apps/shared/navigation/routerContext.d.ts +0 -37
  312. package/dist/apps/shared/navigation/routerContext.js +0 -56
  313. package/dist/apps/shared/navigation/routes.d.ts +0 -32
  314. package/dist/apps/shared/navigation/routes.js +0 -37
  315. package/dist/apps/www/_routedPage.d.ts +0 -12
  316. package/dist/apps/www/_routedPage.js +0 -19
  317. package/dist/apps/www/_routes.d.ts +0 -11
  318. package/dist/apps/www/_routes.js +0 -31
@@ -1,124 +1,124 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import { format } from "date-fns";
6
- import { WeekdayCode } from "@rapidmx/react-shared/calendar/calendarApi.js";
7
- import { CalendarOccurrence, toEventWallClock } from "@rapidmx/react-shared/calendar/recurrence.js";
8
-
9
- const MS_PER_DAY = 86_400_000;
10
-
11
- /**
12
- * All-day events are stored date-only: `startDate` is UTC midnight of the first day and `endDate` is UTC
13
- * midnight of the day *after* the last day (exclusive, like iCalendar's `DTEND;VALUE=DATE`). That keeps
14
- * an all-day event on the same calendar date for every viewer, whatever their timezone.
15
- *
16
- * Older events were saved as the creator's *local* midnight converted to UTC (e.g. `...T22:00Z` for a
17
- * UTC+2 creator), so reading one rounds the instant to the nearest UTC midnight rather than slicing the
18
- * ISO string — which gives the intended date for both formats.
19
- */
20
- export function allDayDateKey(iso: string): string {
21
- const rounded = Math.round(new Date(iso).getTime() / MS_PER_DAY) * MS_PER_DAY;
22
- return new Date(rounded).toISOString().slice(0, 10);
23
- }
24
-
25
- /** `YYYY-MM-DD` -> the stored UTC-midnight instant for that date. */
26
- export function allDayInstant(dateKey: string): string {
27
- return `${dateKey}T00:00:00.000Z`;
28
- }
29
-
30
- /** Adds `days` to a `YYYY-MM-DD` date key. */
31
- export function addDaysToKey(dateKey: string, days: number): string {
32
- return new Date(new Date(allDayInstant(dateKey)).getTime() + days * MS_PER_DAY).toISOString().slice(0, 10);
33
- }
34
-
35
- /** The local calendar date `day` (a local-midnight `Date` from a grid view) as a `YYYY-MM-DD` key. */
36
- export function localDateKey(day: Date): string {
37
- return format(day, "yyyy-MM-dd");
38
- }
39
-
40
- /**
41
- * A recurrence rule's inclusive "Ends on" date -> its stored `until` instant: the end of that day in the
42
- * frame the series expands in. A timed series expands in its own (normally the viewer's) timezone, so that's
43
- * the end of the local day - `new Date("YYYY-MM-DD")` would be UTC midnight, the previous day west of UTC.
44
- * An all-day series expands in UTC (react-shared's `expandOccurrences`), so it's the end of the UTC day: the
45
- * local end of day is already the next UTC day west of UTC and would add one more occurrence.
46
- */
47
- export function recurrenceUntilInstant(dateKey: string, allDay: boolean): string {
48
- if (allDay) {
49
- return `${dateKey}T23:59:59.999Z`;
50
- }
51
- const [y, m, d] = dateKey.split("-").map(Number);
52
- return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
53
- }
54
-
55
- /** The stored form of an all-day series' "Ends on" date - the last millisecond of that UTC day. */
56
- const ALL_DAY_UNTIL_PATTERN = /^(\d{4}-\d{2}-\d{2})T23:59:59\.999Z$/;
57
- /** A bare UTC midnight - how the oldest editor (and date-only `UNTIL` values) stored the chosen date itself. */
58
- const UTC_MIDNIGHT_PATTERN = /^(\d{4}-\d{2}-\d{2})T00:00:00(?:\.000)?Z$/;
59
-
60
- /**
61
- * Inverse of `recurrenceUntilInstant()`. An all-day series' value is recognized explicitly in its stored
62
- * `T23:59:59.999Z` form (and as a bare UTC midnight, the oldest form). Anything else is a legacy value stored
63
- * as the creator's *local* end of day, which can land anywhere from just before 10:00Z on the chosen date (UTC+14)
64
- * to just before 12:00Z the day after (UTC-12) - a 26-hour spread no UTC-only rounding can resolve (UTC+14 and UTC-10
65
- * creators' values are exactly 24h apart for the same date), so it reads back on the local calendar, the
66
- * frame it was written in.
67
- */
68
- export function recurrenceUntilDateKey(until: string, allDay: boolean): string {
69
- if (allDay) {
70
- const stored = ALL_DAY_UNTIL_PATTERN.exec(until) ?? UTC_MIDNIGHT_PATTERN.exec(until);
71
- if (stored) {
72
- return stored[1];
73
- }
74
- }
75
- return format(new Date(until), "yyyy-MM-dd");
76
- }
77
-
78
- /** `Date#getUTCDay()` index -> RFC 5545 weekday code. */
79
- const JS_WEEKDAY_CODES: WeekdayCode[] = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
80
-
81
- /** The weekday an event starts on, in the frame its series expands in: the UTC date for an all-day event
82
- * (`start`'s date part), the event's own timezone otherwise (`start` being a local `datetime-local` value).
83
- * `undefined` while the start input is empty/invalid. */
84
- export function startWeekdayCode(start: string, allDay: boolean, timezone: string | undefined): WeekdayCode | undefined {
85
- const ms = allDay ? new Date(allDayInstant(start.slice(0, 10))).getTime() : new Date(start).getTime();
86
- if (Number.isNaN(ms)) {
87
- return undefined;
88
- }
89
- return JS_WEEKDAY_CODES[new Date(toEventWallClock(ms, timezone, allDay)).getUTCDay()];
90
- }
91
-
92
- /**
93
- * Whether `occurrence` should be shown on the grid's local calendar day `day`. All-day events cover every
94
- * date from their start date up to (not including) their exclusive end date — at least their start date.
95
- * Timed events cover every local day their [start, end) interval overlaps, so a multi-day event shows on
96
- * each day rather than only on its start day.
97
- */
98
- export function occursOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
99
- if (occurrence.allDay) {
100
- const key = localDateKey(day);
101
- const startKey = allDayDateKey(occurrence.startDate);
102
- const endKey = allDayDateKey(occurrence.endDate);
103
- return key === startKey || (key > startKey && key < endKey);
104
- }
105
- const dayStart = new Date(day.getFullYear(), day.getMonth(), day.getDate());
106
- const dayEnd = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
107
- const start = new Date(occurrence.startDate);
108
- const end = new Date(occurrence.endDate);
109
- if (start.getTime() === end.getTime()) {
110
- return start >= dayStart && start < dayEnd;
111
- }
112
- return start < dayEnd && end > dayStart;
113
- }
114
-
115
- /**
116
- * Whether `day` is the first day `occurrence` covers. Grid views only make that day's chip/block
117
- * draggable — a drag id must be unique, so the continuation copies on later days are display-only.
118
- */
119
- export function startsOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
120
- if (occurrence.allDay) {
121
- return allDayDateKey(occurrence.startDate) === localDateKey(day);
122
- }
123
- return localDateKey(new Date(occurrence.startDate)) === localDateKey(day);
124
- }
1
+ ///////////////////////////////////////////////////////////////////////////////
2
+ // Copyright (C) 2026 Jean-Philippe Steinmetz
3
+ // SPDX-License-Identifier: MPL-2.0
4
+ ///////////////////////////////////////////////////////////////////////////////
5
+ import { format } from "date-fns";
6
+ import { WeekdayCode } from "@rapidmx/react-shared/calendar/calendarApi.js";
7
+ import { CalendarOccurrence, toEventWallClock } from "@rapidmx/react-shared/calendar/recurrence.js";
8
+
9
+ const MS_PER_DAY = 86_400_000;
10
+
11
+ /**
12
+ * All-day events are stored date-only: `startDate` is UTC midnight of the first day and `endDate` is UTC
13
+ * midnight of the day *after* the last day (exclusive, like iCalendar's `DTEND;VALUE=DATE`). That keeps
14
+ * an all-day event on the same calendar date for every viewer, whatever their timezone.
15
+ *
16
+ * Older events were saved as the creator's *local* midnight converted to UTC (e.g. `...T22:00Z` for a
17
+ * UTC+2 creator), so reading one rounds the instant to the nearest UTC midnight rather than slicing the
18
+ * ISO string — which gives the intended date for both formats.
19
+ */
20
+ export function allDayDateKey(iso: string): string {
21
+ const rounded = Math.round(new Date(iso).getTime() / MS_PER_DAY) * MS_PER_DAY;
22
+ return new Date(rounded).toISOString().slice(0, 10);
23
+ }
24
+
25
+ /** `YYYY-MM-DD` -> the stored UTC-midnight instant for that date. */
26
+ export function allDayInstant(dateKey: string): string {
27
+ return `${dateKey}T00:00:00.000Z`;
28
+ }
29
+
30
+ /** Adds `days` to a `YYYY-MM-DD` date key. */
31
+ export function addDaysToKey(dateKey: string, days: number): string {
32
+ return new Date(new Date(allDayInstant(dateKey)).getTime() + days * MS_PER_DAY).toISOString().slice(0, 10);
33
+ }
34
+
35
+ /** The local calendar date `day` (a local-midnight `Date` from a grid view) as a `YYYY-MM-DD` key. */
36
+ export function localDateKey(day: Date): string {
37
+ return format(day, "yyyy-MM-dd");
38
+ }
39
+
40
+ /**
41
+ * A recurrence rule's inclusive "Ends on" date -> its stored `until` instant: the end of that day in the
42
+ * frame the series expands in. A timed series expands in its own (normally the viewer's) timezone, so that's
43
+ * the end of the local day - `new Date("YYYY-MM-DD")` would be UTC midnight, the previous day west of UTC.
44
+ * An all-day series expands in UTC (react-shared's `expandOccurrences`), so it's the end of the UTC day: the
45
+ * local end of day is already the next UTC day west of UTC and would add one more occurrence.
46
+ */
47
+ export function recurrenceUntilInstant(dateKey: string, allDay: boolean): string {
48
+ if (allDay) {
49
+ return `${dateKey}T23:59:59.999Z`;
50
+ }
51
+ const [y, m, d] = dateKey.split("-").map(Number);
52
+ return new Date(y, m - 1, d, 23, 59, 59, 999).toISOString();
53
+ }
54
+
55
+ /** The stored form of an all-day series' "Ends on" date - the last millisecond of that UTC day. */
56
+ const ALL_DAY_UNTIL_PATTERN = /^(\d{4}-\d{2}-\d{2})T23:59:59\.999Z$/;
57
+ /** A bare UTC midnight - how the oldest editor (and date-only `UNTIL` values) stored the chosen date itself. */
58
+ const UTC_MIDNIGHT_PATTERN = /^(\d{4}-\d{2}-\d{2})T00:00:00(?:\.000)?Z$/;
59
+
60
+ /**
61
+ * Inverse of `recurrenceUntilInstant()`. An all-day series' value is recognized explicitly in its stored
62
+ * `T23:59:59.999Z` form (and as a bare UTC midnight, the oldest form). Anything else is a legacy value stored
63
+ * as the creator's *local* end of day, which can land anywhere from just before 10:00Z on the chosen date (UTC+14)
64
+ * to just before 12:00Z the day after (UTC-12) - a 26-hour spread no UTC-only rounding can resolve (UTC+14 and UTC-10
65
+ * creators' values are exactly 24h apart for the same date), so it reads back on the local calendar, the
66
+ * frame it was written in.
67
+ */
68
+ export function recurrenceUntilDateKey(until: string, allDay: boolean): string {
69
+ if (allDay) {
70
+ const stored = ALL_DAY_UNTIL_PATTERN.exec(until) ?? UTC_MIDNIGHT_PATTERN.exec(until);
71
+ if (stored) {
72
+ return stored[1];
73
+ }
74
+ }
75
+ return format(new Date(until), "yyyy-MM-dd");
76
+ }
77
+
78
+ /** `Date#getUTCDay()` index -> RFC 5545 weekday code. */
79
+ const JS_WEEKDAY_CODES: WeekdayCode[] = ["SU", "MO", "TU", "WE", "TH", "FR", "SA"];
80
+
81
+ /** The weekday an event starts on, in the frame its series expands in: the UTC date for an all-day event
82
+ * (`start`'s date part), the event's own timezone otherwise (`start` being a local `datetime-local` value).
83
+ * `undefined` while the start input is empty/invalid. */
84
+ export function startWeekdayCode(start: string, allDay: boolean, timezone: string | undefined): WeekdayCode | undefined {
85
+ const ms = allDay ? new Date(allDayInstant(start.slice(0, 10))).getTime() : new Date(start).getTime();
86
+ if (Number.isNaN(ms)) {
87
+ return undefined;
88
+ }
89
+ return JS_WEEKDAY_CODES[new Date(toEventWallClock(ms, timezone, allDay)).getUTCDay()];
90
+ }
91
+
92
+ /**
93
+ * Whether `occurrence` should be shown on the grid's local calendar day `day`. All-day events cover every
94
+ * date from their start date up to (not including) their exclusive end date — at least their start date.
95
+ * Timed events cover every local day their [start, end) interval overlaps, so a multi-day event shows on
96
+ * each day rather than only on its start day.
97
+ */
98
+ export function occursOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
99
+ if (occurrence.allDay) {
100
+ const key = localDateKey(day);
101
+ const startKey = allDayDateKey(occurrence.startDate);
102
+ const endKey = allDayDateKey(occurrence.endDate);
103
+ return key === startKey || (key > startKey && key < endKey);
104
+ }
105
+ const dayStart = new Date(day.getFullYear(), day.getMonth(), day.getDate());
106
+ const dayEnd = new Date(day.getFullYear(), day.getMonth(), day.getDate() + 1);
107
+ const start = new Date(occurrence.startDate);
108
+ const end = new Date(occurrence.endDate);
109
+ if (start.getTime() === end.getTime()) {
110
+ return start >= dayStart && start < dayEnd;
111
+ }
112
+ return start < dayEnd && end > dayStart;
113
+ }
114
+
115
+ /**
116
+ * Whether `day` is the first day `occurrence` covers. Grid views only make that day's chip/block
117
+ * draggable — a drag id must be unique, so the continuation copies on later days are display-only.
118
+ */
119
+ export function startsOnDay(occurrence: CalendarOccurrence, day: Date): boolean {
120
+ if (occurrence.allDay) {
121
+ return allDayDateKey(occurrence.startDate) === localDateKey(day);
122
+ }
123
+ return localDateKey(new Date(occurrence.startDate)) === localDateKey(day);
124
+ }
@@ -28,6 +28,8 @@ export interface EventFormValues {
28
28
  attendees: Attendee[];
29
29
  /** What has been typed into the guests field but not added yet. */
30
30
  guestDraft: string;
31
+ /** What was committed to the guests field (Enter, a comma, leaving it) but is not an address: kept there, flagged, until it is fixed or removed. */
32
+ guestInvalid: string[];
31
33
  recurrenceRule: RecurrenceRule | null;
32
34
  /** Minutes before the start, as typed; blank means no reminder. */
33
35
  reminderMinutes: string;
@@ -70,8 +72,6 @@ export interface EventFormController {
70
72
  deviceZone: string;
71
73
 
72
74
  // Guests.
73
- /** Adds the addresses in `text`; returns the ones that are not valid addresses. */
74
- addGuests: (text: string) => string[];
75
75
  updateAttendee: (index: number, patch: Partial<Attendee>) => void;
76
76
  removeAttendee: (index: number) => void;
77
77
  addResource: (mailbox: Mailbox) => void;
@@ -6,6 +6,7 @@ import { format } from "date-fns";
6
6
  import { Attendee, AttendeeResponseStatus, BusyStatus, EventVisibility, GuestPermissions } from "@rapidmx/react-shared/calendar/calendarApi.js";
7
7
  import { fromEventWallClock, toEventWallClock } from "@rapidmx/react-shared/calendar/recurrence.js";
8
8
  import { toDatetimeLocal } from "@rapidmx/react-shared/util/dateInput.js";
9
+ import { formatRecipient, isValidRecipientAddress, parseRecipient, splitRecipientList } from "../mail/compose/recipients.js";
9
10
  import { addDaysToKey, allDayDateKey } from "./allDay.js";
10
11
 
11
12
  /** What the event form and the read-only event view both need to say about a busy status / an answer. */
@@ -80,19 +81,53 @@ export function describeReminder(minutes: number | undefined): string {
80
81
  return `Notify ${amount} ${amount === 1 ? unit.singular : unit.unit} before`;
81
82
  }
82
83
 
83
- /** Splits what was typed into the guests field into its addresses: commas, semicolons and white space separate them. */
84
- export function splitGuestInput(text: string): string[] {
85
- return text.split(/[,;\s]+/).filter(Boolean);
84
+ /** An attendee as the guests field adds one. */
85
+ export function newGuest(address: string, displayName?: string): Attendee {
86
+ return { address, ...(displayName ? { displayName } : {}), role: "required", responseStatus: "needsAction", isOrganizer: false };
86
87
  }
87
88
 
88
- /** The loosest address check that is still worth making before an invitation is sent: something, an @, something. */
89
- export function isValidGuestAddress(address: string): boolean {
90
- return /^[^\s@<>,;]+@[^\s@<>,;]+$/.test(address);
89
+ /** A guest as the guests field shows it: `Name <address>`, or the bare address for one without a name (the form compose's recipient fields use). */
90
+ export function guestChip(guest: { address: string; displayName?: string }): string {
91
+ return formatRecipient({ address: guest.address, displayName: guest.displayName });
91
92
  }
92
93
 
93
- /** An attendee as the guests field adds one. */
94
- export function newGuest(address: string): Attendee {
95
- return { address, role: "required", responseStatus: "needsAction", isOrganizer: false };
94
+ /**
95
+ * The guests the guests field's chips name, given the guests `current`ly on the list: a chip for someone already there keeps that guest as
96
+ * they are (their role and answer, whatever the case of the address), a chip for a new address adds a required guest with the chip's name, and
97
+ * an address twice (or one of `skipAddresses` - the organizer's, or the people already invited) is added once. The chips are the field's whole
98
+ * list, so a guest without a chip is removed. What is not an address comes back as `invalid`, to stay in the field flagged; several addresses
99
+ * separated by white space in one chip ("a@x.com b@x.com", as a paste can be) are taken as several.
100
+ */
101
+ export function applyGuestChips(current: Attendee[], chips: string[], skipAddresses: string[] = []): { attendees: Attendee[]; invalid: string[] } {
102
+ const skip = new Set(skipAddresses.map((address) => address.toLowerCase()));
103
+ const attendees: Attendee[] = [];
104
+ const invalid: string[] = [];
105
+ const known = (address: string) => current.find((guest) => guest.address.toLowerCase() === address.toLowerCase());
106
+ const listed = (address: string) => attendees.some((guest) => guest.address.toLowerCase() === address.toLowerCase());
107
+
108
+ function add(address: string, displayName?: string) {
109
+ const existing = known(address);
110
+ if (existing) {
111
+ if (!listed(address)) {
112
+ attendees.push(existing);
113
+ }
114
+ } else if (!skip.has(address.toLowerCase()) && !listed(address)) {
115
+ attendees.push(newGuest(address, displayName));
116
+ }
117
+ }
118
+
119
+ for (const chip of chips) {
120
+ const { address, displayName } = parseRecipient(chip);
121
+ const parts = chip.trim().split(/\s+/);
122
+ if (isValidRecipientAddress(address) || known(address)) {
123
+ add(address, displayName);
124
+ } else if (parts.length > 1 && parts.every(isValidRecipientAddress)) {
125
+ parts.forEach((part) => add(part));
126
+ } else if (!invalid.includes(chip.trim())) {
127
+ invalid.push(chip.trim());
128
+ }
129
+ }
130
+ return { attendees, invalid };
96
131
  }
97
132
 
98
133
  /** The wall-clock string a form input holds ("YYYY-MM-DDTHH:mm") read as `zone`'s clock, as an instant. `deviceZone` is the zone the browser
@@ -152,19 +187,11 @@ export function formatStoredWhen(startDate: string, endDate: string, allDay: boo
152
187
  return formatWhen(new Date(startDate), new Date(endDate), false, now);
153
188
  }
154
189
 
155
- /** Adds the addresses typed into the guests field to `current`: an address already on the list (in any case) is skipped, and what is not an
156
- * address comes back as `invalid` for the field to keep. */
157
- export function mergeGuests(current: Attendee[], text: string): { attendees: Attendee[]; invalid: string[] } {
158
- const attendees = [...current];
159
- const invalid: string[] = [];
160
- for (const token of splitGuestInput(text)) {
161
- if (!isValidGuestAddress(token)) {
162
- invalid.push(token);
163
- } else if (!attendees.some((a) => a.address.toLowerCase() === token.toLowerCase())) {
164
- attendees.push(newGuest(token));
165
- }
166
- }
167
- return { attendees, invalid };
190
+ /** Adds the guests typed or pasted into the guests field to `current` - recipients separated by commas or semicolons, each an address or
191
+ * `Name <address>` (see `applyGuestChips()`, which keeps who is already there): an address already on the list (in any case) or in
192
+ * `skipAddresses` is skipped, and what is not an address comes back as `invalid` for the field to keep. */
193
+ export function mergeGuests(current: Attendee[], text: string, skipAddresses: string[] = []): { attendees: Attendee[]; invalid: string[] } {
194
+ return applyGuestChips(current, [...current.map(guestChip), ...splitRecipientList(text)], skipAddresses);
168
195
  }
169
196
 
170
197
  /** `formatWhen()` for the form's own wall-clock strings (an all-day event's `end` is its inclusive last day); a message while either is empty. */