@rapidmx/web-client 0.4.0 → 0.6.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 (320) hide show
  1. package/README.md +88 -0
  2. package/apps/admin/audit-log/index.tsx +35 -8
  3. package/apps/admin/data-requests/index.tsx +480 -485
  4. package/apps/admin/distribution-lists/[uid].tsx +19 -1
  5. package/apps/admin/escrow-scopes/[uid].tsx +348 -237
  6. package/apps/admin/escrow-scopes/new/index.tsx +8 -2
  7. package/apps/admin/index.tsx +19 -1
  8. package/apps/admin/ingest-queue/index.tsx +44 -5
  9. package/apps/admin/mailboxes/[uid].tsx +211 -184
  10. package/apps/admin/quarantine/index.tsx +46 -14
  11. package/apps/admin/transport-rules/[uid].tsx +30 -1
  12. package/apps/admin/transport-rules/_transportRuleConfig.tsx +38 -2
  13. package/apps/admin/transport-rules/index.tsx +24 -6
  14. package/apps/admin/transport-rules/new/index.tsx +30 -1
  15. package/apps/escrow/_layout.tsx +2 -3
  16. package/apps/escrow/audit-log/index.tsx +196 -168
  17. package/apps/escrow/matters/[uid].tsx +621 -521
  18. package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +22 -1
  19. package/apps/shared/components/admin/layout/AdminShell.tsx +28 -9
  20. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -0
  21. package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
  22. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +55 -11
  23. package/apps/shared/components/admin/settings/BrandingForm.tsx +15 -4
  24. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +18 -7
  25. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +10 -2
  26. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +6 -0
  27. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +45 -12
  28. package/apps/shared/components/admin/settings/PluginsManager.tsx +1235 -595
  29. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +174 -98
  30. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +49 -13
  31. package/apps/shared/components/admin/setup/SetupWizard.tsx +150 -34
  32. package/apps/shared/components/admin/signOut.ts +79 -0
  33. package/apps/shared/components/admin/usePagedList.tsx +129 -0
  34. package/apps/shared/components/calendar/EventModal.tsx +717 -549
  35. package/apps/shared/components/calendar/MonthView.tsx +173 -139
  36. package/apps/shared/components/calendar/RecurrenceEditor.tsx +222 -180
  37. package/apps/shared/components/calendar/SplitDayView.tsx +143 -137
  38. package/apps/shared/components/calendar/TimeGridView.tsx +244 -198
  39. package/apps/shared/components/calendar/allDay.ts +124 -0
  40. package/apps/shared/components/calendar/layout/CalendarShell.tsx +194 -192
  41. package/apps/shared/components/contacts/ContactDetailPane.tsx +100 -21
  42. package/apps/shared/components/contacts/ContactForm.tsx +377 -348
  43. package/apps/shared/components/contacts/ContactsSidebar.tsx +6 -2
  44. package/apps/shared/components/contacts/KeyChangeReview.tsx +192 -0
  45. package/apps/shared/components/contacts/contactKeys.ts +78 -0
  46. package/apps/shared/components/contacts/layout/ContactsShell.tsx +199 -197
  47. package/apps/shared/components/escrow/layout/EscrowShell.tsx +148 -134
  48. package/apps/shared/components/layout/AppShell.tsx +123 -33
  49. package/apps/shared/components/layout/BrandingChrome.tsx +48 -10
  50. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +389 -298
  51. package/apps/shared/components/layout/MailboxProvisioning.tsx +19 -3
  52. package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +350 -0
  53. package/apps/shared/components/layout/UnlockPromptProvider.tsx +257 -128
  54. package/apps/shared/components/mail/ConversationThreadPane.tsx +216 -181
  55. package/apps/shared/components/mail/MessageDetailPane.tsx +1318 -630
  56. package/apps/shared/components/mail/compose/ComposeContext.tsx +20 -15
  57. package/apps/shared/components/mail/compose/ComposeWindow.tsx +854 -132
  58. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -0
  59. package/apps/shared/components/mail/layout/MailShell.tsx +420 -408
  60. package/apps/shared/components/mail/pinnedSigners.ts +124 -0
  61. package/apps/shared/components/mail/verificationSeals.ts +125 -0
  62. package/apps/shared/components/mail/writableMailboxes.ts +101 -0
  63. package/apps/shared/components/rules/RuleBuilder.tsx +311 -276
  64. package/apps/shared/components/settings/layout/SettingsShell.tsx +23 -9
  65. package/apps/shared/components/tasks/layout/TasksShell.tsx +201 -199
  66. package/apps/shared/mail/listAllPages.ts +39 -0
  67. package/apps/shared/plugins/pluginNav.ts +73 -0
  68. package/apps/shared/search/LocalIndexLifecycle.tsx +64 -55
  69. package/apps/shared/search/localIndexBuilder.ts +481 -179
  70. package/apps/shared/search/localIndexRpcClient.ts +231 -29
  71. package/apps/shared/search/localIndexSchema.ts +15 -6
  72. package/apps/shared/search/localIndexStorage.ts +98 -0
  73. package/apps/shared/search/localIndexVFS.ts +32 -1
  74. package/apps/shared/search/localIndexWorker.ts +648 -186
  75. package/apps/www/calendar/index.tsx +438 -417
  76. package/apps/www/contacts/[uid].tsx +21 -2
  77. package/apps/www/contacts/index.tsx +116 -12
  78. package/apps/www/index.tsx +1314 -1041
  79. package/apps/www/messages/[uid].tsx +18 -6
  80. package/apps/www/settings/auto-reply/index.tsx +134 -129
  81. package/apps/www/settings/encryption/index.tsx +739 -216
  82. package/apps/www/settings/filters/[uid].tsx +171 -155
  83. package/apps/www/settings/filters/new/index.tsx +8 -1
  84. package/apps/www/settings/focused-inbox/index.tsx +150 -148
  85. package/apps/www/settings/privacy/index.tsx +494 -436
  86. package/apps/www/settings/read-receipts/index.tsx +148 -125
  87. package/apps/www/settings/sharing/index.tsx +17 -14
  88. package/apps/www/tasks/index.tsx +638 -579
  89. package/dist/apps/admin/_404.d.ts +2 -0
  90. package/dist/apps/admin/_500.d.ts +2 -0
  91. package/dist/apps/admin/_layout.d.ts +8 -0
  92. package/dist/apps/admin/audit-log/index.d.ts +11 -0
  93. package/dist/apps/admin/audit-log/index.js +38 -8
  94. package/dist/apps/admin/branding/index.d.ts +3 -0
  95. package/dist/apps/admin/data-requests/index.d.ts +3 -0
  96. package/dist/apps/admin/data-requests/index.js +52 -72
  97. package/dist/apps/admin/distribution-lists/[uid].d.ts +7 -0
  98. package/dist/apps/admin/distribution-lists/[uid].js +1 -1
  99. package/dist/apps/admin/distribution-lists/index.d.ts +3 -0
  100. package/dist/apps/admin/distribution-lists/new/index.d.ts +3 -0
  101. package/dist/apps/admin/domains/[uid].d.ts +7 -0
  102. package/dist/apps/admin/domains/index.d.ts +3 -0
  103. package/dist/apps/admin/domains/new/index.d.ts +3 -0
  104. package/dist/apps/admin/encryption-policy/index.d.ts +3 -0
  105. package/dist/apps/admin/escrow-scopes/[uid].d.ts +21 -0
  106. package/dist/apps/admin/escrow-scopes/[uid].js +91 -12
  107. package/dist/apps/admin/escrow-scopes/index.d.ts +3 -0
  108. package/dist/apps/admin/escrow-scopes/new/index.d.ts +3 -0
  109. package/dist/apps/admin/escrow-scopes/new/index.js +8 -3
  110. package/dist/apps/admin/index.d.ts +3 -0
  111. package/dist/apps/admin/index.js +4 -1
  112. package/dist/apps/admin/ingest-queue/index.d.ts +4 -0
  113. package/dist/apps/admin/ingest-queue/index.js +24 -6
  114. package/dist/apps/admin/mailbox-policy/index.d.ts +3 -0
  115. package/dist/apps/admin/mailboxes/[uid].d.ts +7 -0
  116. package/dist/apps/admin/mailboxes/[uid].js +20 -4
  117. package/dist/apps/admin/mailboxes/new/index.d.ts +3 -0
  118. package/dist/apps/admin/plugins/index.d.ts +3 -0
  119. package/dist/apps/admin/quarantine/index.d.ts +6 -0
  120. package/dist/apps/admin/quarantine/index.js +20 -11
  121. package/dist/apps/admin/retention-policy/index.d.ts +3 -0
  122. package/dist/apps/admin/setup/index.d.ts +3 -0
  123. package/dist/apps/admin/transport-rules/[uid].d.ts +7 -0
  124. package/dist/apps/admin/transport-rules/[uid].js +18 -2
  125. package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +21 -0
  126. package/dist/apps/admin/transport-rules/_transportRuleConfig.js +19 -0
  127. package/dist/apps/admin/transport-rules/index.d.ts +3 -0
  128. package/dist/apps/admin/transport-rules/index.js +22 -6
  129. package/dist/apps/admin/transport-rules/new/index.d.ts +3 -0
  130. package/dist/apps/admin/transport-rules/new/index.js +18 -2
  131. package/dist/apps/escrow/_layout.d.ts +10 -0
  132. package/dist/apps/escrow/_layout.js +3 -3
  133. package/dist/apps/escrow/audit-log/index.d.ts +9 -0
  134. package/dist/apps/escrow/audit-log/index.js +26 -1
  135. package/dist/apps/escrow/index.d.ts +3 -0
  136. package/dist/apps/escrow/matters/[uid].d.ts +7 -0
  137. package/dist/apps/escrow/matters/[uid].js +77 -42
  138. package/dist/apps/escrow/matters/new/index.d.ts +3 -0
  139. package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +17 -0
  140. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +32 -0
  141. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +11 -2
  142. package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +32 -0
  143. package/dist/apps/shared/components/admin/layout/AdminShell.js +15 -6
  144. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +12 -0
  145. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +72 -0
  146. package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +6 -0
  147. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +19 -0
  148. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
  149. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +12 -0
  150. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +22 -4
  151. package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +9 -0
  152. package/dist/apps/shared/components/admin/settings/BrandingForm.js +15 -4
  153. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +12 -0
  154. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +13 -7
  155. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +12 -0
  156. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +7 -2
  157. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.d.ts +9 -0
  158. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +19 -0
  159. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +6 -0
  160. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +10 -0
  161. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +34 -12
  162. package/dist/apps/shared/components/admin/settings/PluginsManager.d.ts +4 -0
  163. package/dist/apps/shared/components/admin/settings/PluginsManager.js +390 -78
  164. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +9 -0
  165. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +40 -11
  166. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.d.ts +14 -0
  167. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +29 -13
  168. package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +36 -0
  169. package/dist/apps/shared/components/admin/setup/SetupWizard.js +87 -21
  170. package/dist/apps/shared/components/admin/signOut.d.ts +23 -0
  171. package/dist/apps/shared/components/admin/signOut.js +75 -0
  172. package/dist/apps/shared/components/admin/usePagedList.d.ts +39 -0
  173. package/dist/apps/shared/components/admin/usePagedList.js +99 -0
  174. package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +26 -0
  175. package/dist/apps/shared/components/calendar/EventModal.d.ts +46 -0
  176. package/dist/apps/shared/components/calendar/EventModal.js +142 -21
  177. package/dist/apps/shared/components/calendar/MonthView.d.ts +15 -0
  178. package/dist/apps/shared/components/calendar/MonthView.js +12 -5
  179. package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +20 -0
  180. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +40 -5
  181. package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +19 -0
  182. package/dist/apps/shared/components/calendar/SplitDayView.d.ts +28 -0
  183. package/dist/apps/shared/components/calendar/SplitDayView.js +10 -4
  184. package/dist/apps/shared/components/calendar/TimeGridView.d.ts +17 -0
  185. package/dist/apps/shared/components/calendar/TimeGridView.js +23 -7
  186. package/dist/apps/shared/components/calendar/allDay.d.ts +51 -0
  187. package/dist/apps/shared/components/calendar/allDay.js +111 -0
  188. package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +40 -0
  189. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +3 -3
  190. package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +23 -0
  191. package/dist/apps/shared/components/contacts/ContactDetailPane.js +43 -5
  192. package/dist/apps/shared/components/contacts/ContactForm.d.ts +20 -0
  193. package/dist/apps/shared/components/contacts/ContactForm.js +32 -10
  194. package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +40 -0
  195. package/dist/apps/shared/components/contacts/ContactsSidebar.js +2 -2
  196. package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +25 -0
  197. package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +40 -0
  198. package/dist/apps/shared/components/contacts/KeyChangeReview.js +63 -0
  199. package/dist/apps/shared/components/contacts/contactKeys.d.ts +29 -0
  200. package/dist/apps/shared/components/contacts/contactKeys.js +64 -0
  201. package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +21 -0
  202. package/dist/apps/shared/components/contacts/layout/ContactsShell.js +2 -2
  203. package/dist/apps/shared/components/escrow/layout/EscrowShell.d.ts +25 -0
  204. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +24 -5
  205. package/dist/apps/shared/components/forms/StringListField.d.ts +22 -0
  206. package/dist/apps/shared/components/layout/AppShell.d.ts +49 -0
  207. package/dist/apps/shared/components/layout/AppShell.js +97 -26
  208. package/dist/apps/shared/components/layout/BrandingChrome.d.ts +18 -0
  209. package/dist/apps/shared/components/layout/BrandingChrome.js +45 -10
  210. package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +51 -0
  211. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +49 -12
  212. package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +13 -0
  213. package/dist/apps/shared/components/layout/MailboxProvisioning.js +10 -2
  214. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +66 -0
  215. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +174 -0
  216. package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +45 -0
  217. package/dist/apps/shared/components/layout/UnlockPromptProvider.js +73 -14
  218. package/dist/apps/shared/components/layout/UserMenu.d.ts +23 -0
  219. package/dist/apps/shared/components/mail/ConversationList.d.ts +11 -0
  220. package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +23 -0
  221. package/dist/apps/shared/components/mail/ConversationThreadPane.js +50 -12
  222. package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +93 -0
  223. package/dist/apps/shared/components/mail/MessageDetailPane.js +441 -36
  224. package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +58 -0
  225. package/dist/apps/shared/components/mail/compose/ComposeContext.js +9 -6
  226. package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +15 -0
  227. package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +37 -0
  228. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +699 -128
  229. package/dist/apps/shared/components/mail/compose/EmojiPicker.d.ts +14 -0
  230. package/dist/apps/shared/components/mail/compose/GifPicker.d.ts +13 -0
  231. package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +34 -0
  232. package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.d.ts +16 -0
  233. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +27 -0
  234. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +50 -0
  235. package/dist/apps/shared/components/mail/layout/MailShell.d.ts +57 -0
  236. package/dist/apps/shared/components/mail/layout/MailShell.js +13 -4
  237. package/dist/apps/shared/components/mail/pinnedSigners.d.ts +33 -0
  238. package/dist/apps/shared/components/mail/pinnedSigners.js +98 -0
  239. package/dist/apps/shared/components/mail/verificationSeals.d.ts +22 -0
  240. package/dist/apps/shared/components/mail/verificationSeals.js +112 -0
  241. package/dist/apps/shared/components/mail/writableMailboxes.d.ts +15 -0
  242. package/dist/apps/shared/components/mail/writableMailboxes.js +87 -0
  243. package/dist/apps/shared/components/rules/RuleBuilder.d.ts +70 -0
  244. package/dist/apps/shared/components/rules/RuleBuilder.js +34 -6
  245. package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +41 -0
  246. package/dist/apps/shared/components/settings/layout/SettingsShell.js +19 -9
  247. package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +41 -0
  248. package/dist/apps/shared/components/tasks/TasksToolbar.d.ts +14 -0
  249. package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +24 -0
  250. package/dist/apps/shared/components/tasks/layout/TasksShell.js +2 -2
  251. package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -0
  252. package/dist/apps/shared/mail/listAllPages.d.ts +17 -0
  253. package/dist/apps/shared/mail/listAllPages.js +25 -0
  254. package/dist/apps/shared/plugins/pluginNav.d.ts +39 -0
  255. package/dist/apps/shared/plugins/pluginNav.js +33 -0
  256. package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +13 -0
  257. package/dist/apps/shared/search/LocalIndexLifecycle.js +58 -54
  258. package/dist/apps/shared/search/localIndexBlockCipher.d.ts +36 -0
  259. package/dist/apps/shared/search/localIndexBuilder.d.ts +85 -0
  260. package/dist/apps/shared/search/localIndexBuilder.js +292 -37
  261. package/dist/apps/shared/search/localIndexKey.d.ts +4 -0
  262. package/dist/apps/shared/search/localIndexRpcClient.d.ts +71 -0
  263. package/dist/apps/shared/search/localIndexRpcClient.js +191 -26
  264. package/dist/apps/shared/search/localIndexSchema.d.ts +111 -0
  265. package/dist/apps/shared/search/localIndexSchema.js +12 -6
  266. package/dist/apps/shared/search/localIndexSizePreference.d.ts +27 -0
  267. package/dist/apps/shared/search/localIndexStorage.d.ts +28 -0
  268. package/dist/apps/shared/search/localIndexStorage.js +86 -0
  269. package/dist/apps/shared/search/localIndexVFS.d.ts +101 -0
  270. package/dist/apps/shared/search/localIndexVFS.js +68 -40
  271. package/dist/apps/shared/search/localIndexWorker.d.ts +145 -0
  272. package/dist/apps/shared/search/localIndexWorker.js +519 -173
  273. package/dist/apps/shared/search/searchTier2.d.ts +30 -0
  274. package/dist/apps/www/_404.d.ts +2 -0
  275. package/dist/apps/www/_500.d.ts +2 -0
  276. package/dist/apps/www/_layout.d.ts +14 -0
  277. package/dist/apps/www/calendar/index.d.ts +3 -0
  278. package/dist/apps/www/calendar/index.js +28 -10
  279. package/dist/apps/www/contacts/[uid].d.ts +13 -0
  280. package/dist/apps/www/contacts/[uid].js +13 -2
  281. package/dist/apps/www/contacts/index.d.ts +3 -0
  282. package/dist/apps/www/contacts/index.js +80 -10
  283. package/dist/apps/www/index.d.ts +3 -0
  284. package/dist/apps/www/index.js +339 -108
  285. package/dist/apps/www/messages/[uid].d.ts +11 -0
  286. package/dist/apps/www/messages/[uid].js +18 -6
  287. package/dist/apps/www/settings/auto-reply/index.d.ts +4 -0
  288. package/dist/apps/www/settings/auto-reply/index.js +9 -4
  289. package/dist/apps/www/settings/encryption/index.d.ts +7 -0
  290. package/dist/apps/www/settings/encryption/index.js +514 -97
  291. package/dist/apps/www/settings/filters/[uid].d.ts +8 -0
  292. package/dist/apps/www/settings/filters/[uid].js +22 -7
  293. package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +11 -0
  294. package/dist/apps/www/settings/filters/index.d.ts +4 -0
  295. package/dist/apps/www/settings/filters/new/index.d.ts +4 -0
  296. package/dist/apps/www/settings/filters/new/index.js +8 -2
  297. package/dist/apps/www/settings/focused-inbox/index.d.ts +4 -0
  298. package/dist/apps/www/settings/focused-inbox/index.js +3 -1
  299. package/dist/apps/www/settings/labels/index.d.ts +4 -0
  300. package/dist/apps/www/settings/privacy/index.d.ts +4 -0
  301. package/dist/apps/www/settings/privacy/index.js +57 -22
  302. package/dist/apps/www/settings/read-receipts/index.d.ts +4 -0
  303. package/dist/apps/www/settings/read-receipts/index.js +10 -3
  304. package/dist/apps/www/settings/sharing/index.d.ts +4 -0
  305. package/dist/apps/www/settings/sharing/index.js +7 -11
  306. package/dist/apps/www/settings/signatures/[uid].d.ts +8 -0
  307. package/dist/apps/www/settings/signatures/index.d.ts +4 -0
  308. package/dist/apps/www/settings/signatures/new/index.d.ts +4 -0
  309. package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +10 -0
  310. package/dist/apps/www/tasks/index.d.ts +3 -0
  311. package/dist/apps/www/tasks/index.js +50 -10
  312. package/package.json +3 -3
  313. package/apps/shared/components/booking/AvailabilityEditor.tsx +0 -118
  314. package/apps/www/settings/booking-types/[uid].tsx +0 -300
  315. package/apps/www/settings/booking-types/index.tsx +0 -98
  316. package/apps/www/settings/booking-types/new/index.tsx +0 -212
  317. package/dist/apps/shared/components/booking/AvailabilityEditor.js +0 -45
  318. package/dist/apps/www/settings/booking-types/[uid].js +0 -129
  319. package/dist/apps/www/settings/booking-types/index.js +0 -29
  320. package/dist/apps/www/settings/booking-types/new/index.js +0 -86
@@ -1,98 +0,0 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import React, { useEffect, useState } from "react";
6
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
7
- import { BookingType, listBookingTypes } from "@rapidmx/react-shared/booking/bookingApi.js";
8
- import SettingsShell, { SettingsShellProps, useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
9
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
10
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
11
-
12
- export type SettingsBookingTypesPageProps = Omit<SettingsShellProps, "active">;
13
-
14
- export default function SettingsBookingTypesPage(props: SettingsBookingTypesPageProps) {
15
- return (
16
- <SettingsShell {...props} active="booking-types">
17
- <BookingTypesContent />
18
- </SettingsShell>
19
- );
20
- }
21
-
22
- function BookingTypesContent() {
23
- const { mailboxUid } = useSettingsShell();
24
- const [bookingTypes, setBookingTypes] = useState<BookingType[]>([]);
25
- const [loading, setLoading] = useState(true);
26
- const [error, setError] = useState<string | null>(null);
27
-
28
- // `SettingsShell` only ever renders its children once `mailboxUid` has resolved — same established
29
- // non-null pattern as `apps/www/settings/filters/index.tsx`.
30
- useEffect(() => {
31
- listBookingTypes(mailboxUid!)
32
- .then(setBookingTypes)
33
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load your booking links."))
34
- .finally(() => setLoading(false));
35
- }, [mailboxUid]);
36
-
37
- return (
38
- <div className="flex-1 min-w-0 overflow-y-auto p-6">
39
- <div className="max-w-3xl">
40
- <div className="flex items-center justify-between mb-5">
41
- <h1 className="text-lg font-bold tracking-tight">Booking Links</h1>
42
- <a href={`/settings/booking-types/new?mailboxUid=${encodeURIComponent(mailboxUid!)}`}>
43
- <Button type="button" className="!w-auto">
44
- + New booking link
45
- </Button>
46
- </a>
47
- </div>
48
- <p className="text-sm text-text-muted mb-4">
49
- Share a link and let anyone pick a real open slot on your calendar — no account needed on
50
- their end.
51
- </p>
52
-
53
- {error && <Alert>{error}</Alert>}
54
-
55
- {loading ? (
56
- <p className="text-sm text-text-muted">Loading&hellip;</p>
57
- ) : bookingTypes.length === 0 ? (
58
- <p className="text-sm text-text-muted">No booking links yet.</p>
59
- ) : (
60
- <div className="overflow-x-auto">
61
- <table className="w-full text-sm border-collapse">
62
- <thead>
63
- <tr>
64
- {["Name", "Link", "Duration", "Enabled", ""].map((h) => (
65
- <th
66
- key={h}
67
- className="text-left text-xs uppercase tracking-wide text-text-muted py-2 px-2.5 border-b border-border"
68
- >
69
- {h}
70
- </th>
71
- ))}
72
- </tr>
73
- </thead>
74
- <tbody>
75
- {bookingTypes.map((bookingType) => (
76
- <tr key={bookingType.uid}>
77
- <td className="py-2.5 px-2.5 border-b border-border">{bookingType.name}</td>
78
- <td className="py-2.5 px-2.5 border-b border-border">/book/{bookingType.slug}</td>
79
- <td className="py-2.5 px-2.5 border-b border-border">{bookingType.durationMinutes} min</td>
80
- <td className="py-2.5 px-2.5 border-b border-border">{bookingType.enabled ? "Yes" : "No"}</td>
81
- <td className="py-2.5 px-2.5 border-b border-border text-right">
82
- <a
83
- href={`/settings/booking-types/${encodeURIComponent(bookingType.uid)}?mailboxUid=${encodeURIComponent(mailboxUid!)}`}
84
- className="text-primary-dark hover:underline font-medium"
85
- >
86
- View
87
- </a>
88
- </td>
89
- </tr>
90
- ))}
91
- </tbody>
92
- </table>
93
- </div>
94
- )}
95
- </div>
96
- </div>
97
- );
98
- }
@@ -1,212 +0,0 @@
1
- ///////////////////////////////////////////////////////////////////////////////
2
- // Copyright (C) 2026 Jean-Philippe Steinmetz
3
- // SPDX-License-Identifier: MPL-2.0
4
- ///////////////////////////////////////////////////////////////////////////////
5
- import React, { FormEvent, useEffect, useState } from "react";
6
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
7
- import { Folder, listFolders } from "@rapidmx/react-shared/mail/mailApi.js";
8
- import { BookingAvailabilityWindow, createBookingType } from "@rapidmx/react-shared/booking/bookingApi.js";
9
- import SettingsShell, { SettingsShellProps, useSettingsShell } from "../../../../shared/components/settings/layout/SettingsShell.js";
10
- import AvailabilityEditor from "../../../../shared/components/booking/AvailabilityEditor.js";
11
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
12
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
13
- import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
14
-
15
- const INPUT_CLASS =
16
- "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
17
-
18
- export type NewBookingTypePageProps = Omit<SettingsShellProps, "active">;
19
-
20
- export default function NewBookingTypePage(props: NewBookingTypePageProps) {
21
- return (
22
- <SettingsShell {...props} active="booking-types">
23
- <NewBookingTypeForm />
24
- </SettingsShell>
25
- );
26
- }
27
-
28
- function NewBookingTypeForm() {
29
- const { mailboxUid, mailboxes } = useSettingsShell();
30
- // Same established non-null pattern as `apps/www/settings/filters/new/index.tsx`.
31
- const mailbox = mailboxes.find((mb) => mb.uid === mailboxUid)!;
32
-
33
- const [calendarFolderUid, setCalendarFolderUid] = useState<string | null>(null);
34
- const [folderError, setFolderError] = useState<string | null>(null);
35
- const [slug, setSlug] = useState("");
36
- const [name, setName] = useState("");
37
- const [description, setDescription] = useState("");
38
- const [hostDisplayName, setHostDisplayName] = useState(mailbox.displayName);
39
- const [durationMinutes, setDurationMinutes] = useState(30);
40
- const [timezone, setTimezone] = useState(mailbox.timezone);
41
- const [availability, setAvailability] = useState<BookingAvailabilityWindow[]>([]);
42
- const [minimumNoticeMinutes, setMinimumNoticeMinutes] = useState(60);
43
- const [bookingWindowDays, setBookingWindowDays] = useState(30);
44
- const [requiresApproval, setRequiresApproval] = useState(false);
45
- const [error, setError] = useState<string | null>(null);
46
- const [saving, setSaving] = useState(false);
47
-
48
- useEffect(() => {
49
- listFolders(mailboxUid!)
50
- .then((folders) => {
51
- const calendar = folders.find((f: Folder) => f.type === "calendar");
52
- if (!calendar) {
53
- setFolderError("This mailbox has no Calendar folder yet.");
54
- return;
55
- }
56
- setCalendarFolderUid(calendar.uid);
57
- })
58
- .catch((err) => setFolderError(err instanceof ApiRequestError ? err.message : "Could not load this mailbox's folders."));
59
- }, [mailboxUid]);
60
-
61
- async function handleSubmit(e: FormEvent) {
62
- e.preventDefault();
63
- setError(null);
64
-
65
- if (!slug.trim() || !name.trim() || !hostDisplayName.trim()) {
66
- setError("Slug, name, and host name are all required.");
67
- return;
68
- }
69
- if (!calendarFolderUid) {
70
- setError("This mailbox has no Calendar folder yet.");
71
- return;
72
- }
73
-
74
- setSaving(true);
75
- try {
76
- const created = await createBookingType({
77
- mailboxUid: mailboxUid!,
78
- calendarFolderUid,
79
- slug: slug.trim(),
80
- name: name.trim(),
81
- description: description.trim() || undefined,
82
- hostDisplayName: hostDisplayName.trim(),
83
- durationMinutes,
84
- timezone,
85
- availability,
86
- minimumNoticeMinutes,
87
- bookingWindowDays,
88
- requiresApproval,
89
- });
90
- window.location.href = `/settings/booking-types/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid!)}`;
91
- } catch (err) {
92
- setError(err instanceof ApiRequestError ? err.message : "Could not create this booking link.");
93
- } finally {
94
- setSaving(false);
95
- }
96
- }
97
-
98
- return (
99
- <div className="flex-1 min-w-0 overflow-y-auto p-6">
100
- <div className="max-w-2xl">
101
- <h1 className="text-lg font-bold tracking-tight mb-1">New booking link</h1>
102
- <p className="text-sm text-text-muted mb-5">
103
- Anyone with the link can pick an open slot from your live availability below — no account
104
- needed on their end.
105
- </p>
106
-
107
- {error && <Alert>{error}</Alert>}
108
- {folderError && <Alert>{folderError}</Alert>}
109
-
110
- <form onSubmit={handleSubmit} className="flex flex-col gap-1">
111
- <FormField label="Name" htmlFor="name">
112
- <input
113
- id="name"
114
- type="text"
115
- className={INPUT_CLASS}
116
- value={name}
117
- onChange={(e) => setName(e.target.value)}
118
- placeholder="30 Minute Intro Call"
119
- />
120
- </FormField>
121
- <FormField label="Slug (used in the public link)" htmlFor="slug">
122
- <input
123
- id="slug"
124
- type="text"
125
- className={INPUT_CLASS}
126
- value={slug}
127
- onChange={(e) => setSlug(e.target.value)}
128
- placeholder="intro-call"
129
- />
130
- </FormField>
131
- <FormField label="Description (optional)" htmlFor="description">
132
- <textarea
133
- id="description"
134
- className={INPUT_CLASS}
135
- rows={2}
136
- value={description}
137
- onChange={(e) => setDescription(e.target.value)}
138
- />
139
- </FormField>
140
- <FormField label="Host name shown to visitors" htmlFor="hostDisplayName">
141
- <input
142
- id="hostDisplayName"
143
- type="text"
144
- className={INPUT_CLASS}
145
- value={hostDisplayName}
146
- onChange={(e) => setHostDisplayName(e.target.value)}
147
- />
148
- </FormField>
149
- <div className="grid grid-cols-2 gap-3">
150
- <FormField label="Duration (minutes)" htmlFor="durationMinutes">
151
- <input
152
- id="durationMinutes"
153
- type="number"
154
- min={1}
155
- className={INPUT_CLASS}
156
- value={durationMinutes}
157
- onChange={(e) => setDurationMinutes(Number(e.target.value))}
158
- />
159
- </FormField>
160
- <FormField label="Timezone" htmlFor="timezone">
161
- <input
162
- id="timezone"
163
- type="text"
164
- className={INPUT_CLASS}
165
- value={timezone}
166
- onChange={(e) => setTimezone(e.target.value)}
167
- placeholder="America/New_York"
168
- />
169
- </FormField>
170
- </div>
171
- <div className="grid grid-cols-2 gap-3">
172
- <FormField label="Minimum notice (minutes)" htmlFor="minimumNoticeMinutes">
173
- <input
174
- id="minimumNoticeMinutes"
175
- type="number"
176
- min={0}
177
- className={INPUT_CLASS}
178
- value={minimumNoticeMinutes}
179
- onChange={(e) => setMinimumNoticeMinutes(Number(e.target.value))}
180
- />
181
- </FormField>
182
- <FormField label="Booking window (days ahead)" htmlFor="bookingWindowDays">
183
- <input
184
- id="bookingWindowDays"
185
- type="number"
186
- min={1}
187
- className={INPUT_CLASS}
188
- value={bookingWindowDays}
189
- onChange={(e) => setBookingWindowDays(Number(e.target.value))}
190
- />
191
- </FormField>
192
- </div>
193
- <label className="flex items-center gap-2 text-sm my-3">
194
- <input type="checkbox" checked={requiresApproval} onChange={(e) => setRequiresApproval(e.target.checked)} />
195
- Require my approval before confirming a booking
196
- </label>
197
-
198
- <div className="mb-4">
199
- <span className="block text-sm font-semibold mb-1.5 text-text">Weekly availability</span>
200
- <AvailabilityEditor value={availability} onChange={setAvailability} />
201
- </div>
202
-
203
- <div>
204
- <Button type="submit" loading={saving} disabled={saving} className="!w-auto">
205
- Create
206
- </Button>
207
- </div>
208
- </form>
209
- </div>
210
- </div>
211
- );
212
- }
@@ -1,45 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- ///////////////////////////////////////////////////////////////////////////////
3
- // Copyright (C) 2026 Jean-Philippe Steinmetz
4
- // SPDX-License-Identifier: MPL-2.0
5
- ///////////////////////////////////////////////////////////////////////////////
6
- import { useState } from "react";
7
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
8
- const DAY_LABELS = ["Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"];
9
- const INPUT_CLASS = "text-sm py-2 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
10
- function minutesToTimeValue(minutes) {
11
- const h = Math.floor(minutes / 60)
12
- .toString()
13
- .padStart(2, "0");
14
- const m = (minutes % 60).toString().padStart(2, "0");
15
- return `${h}:${m}`;
16
- }
17
- function timeValueToMinutes(value) {
18
- const [h, m] = value.split(":").map(Number);
19
- return h * 60 + m;
20
- }
21
- /**
22
- * Adds/removes `BookingType.availability` weekly windows — deliberately does not cover `dateOverrides`
23
- * (per-date blackouts/exceptions), a separate, less commonly needed escape hatch left for a future pass;
24
- * `BookingUtils.generateCandidateSlots()` already handles an empty `dateOverrides` array gracefully.
25
- */
26
- export default function AvailabilityEditor({ value, onChange }) {
27
- const [dayOfWeek, setDayOfWeek] = useState(1);
28
- const [startTime, setStartTime] = useState("09:00");
29
- const [endTime, setEndTime] = useState("17:00");
30
- const [error, setError] = useState(null);
31
- function handleAdd() {
32
- const startMinute = timeValueToMinutes(startTime);
33
- const endMinute = timeValueToMinutes(endTime);
34
- if (startMinute >= endMinute) {
35
- setError("Start time must be before end time.");
36
- return;
37
- }
38
- setError(null);
39
- onChange([...value, { dayOfWeek, startMinute, endMinute }]);
40
- }
41
- function handleRemove(index) {
42
- onChange(value.filter((_, i) => i !== index));
43
- }
44
- return (_jsxs("div", { className: "flex flex-col gap-3", children: [error && _jsx("p", { className: "text-sm text-danger", children: error }), value.length === 0 ? (_jsx("p", { className: "text-sm text-text-muted", children: "No availability windows yet \u2014 add one below." })) : (_jsx("ul", { className: "flex flex-col gap-2", children: value.map((window, index) => (_jsxs("li", { className: "flex items-center justify-between gap-3 py-2 px-3 border border-border rounded-sm text-sm", children: [_jsxs("span", { children: [DAY_LABELS[window.dayOfWeek], " ", minutesToTimeValue(window.startMinute), "\u2013", minutesToTimeValue(window.endMinute)] }), _jsx("button", { type: "button", onClick: () => handleRemove(index), className: "text-sm text-danger hover:underline", children: "Remove" })] }, index))) })), _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("select", { "aria-label": "Day of week", value: dayOfWeek, onChange: (e) => setDayOfWeek(Number(e.target.value)), className: INPUT_CLASS, children: DAY_LABELS.map((label, i) => (_jsx("option", { value: i, children: label }, label))) }), _jsx("input", { type: "time", "aria-label": "Start time", value: startTime, onChange: (e) => setStartTime(e.target.value), className: INPUT_CLASS }), _jsx("span", { className: "text-sm text-text-muted", children: "to" }), _jsx("input", { type: "time", "aria-label": "End time", value: endTime, onChange: (e) => setEndTime(e.target.value), className: INPUT_CLASS }), _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", onClick: handleAdd, children: "Add window" })] })] }));
45
- }
@@ -1,129 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- ///////////////////////////////////////////////////////////////////////////////
3
- // Copyright (C) 2026 Jean-Philippe Steinmetz
4
- // SPDX-License-Identifier: MPL-2.0
5
- ///////////////////////////////////////////////////////////////////////////////
6
- import { useEffect, useState } from "react";
7
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
- import { deleteBookingType, getBookingType, updateBookingType, } from "@rapidmx/react-shared/booking/bookingApi.js";
9
- import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
10
- import AvailabilityEditor from "../../../shared/components/booking/AvailabilityEditor.js";
11
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
12
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
13
- import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
14
- import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
15
- const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
16
- export default function BookingTypeDetailPage(props) {
17
- return (_jsx(SettingsShell, { ...props, active: "booking-types", children: _jsx(BookingTypeDetailContent, { uid: props.params.uid }) }));
18
- }
19
- function BookingTypeDetailContent({ uid }) {
20
- const { mailboxUid } = useSettingsShell();
21
- const [bookingType, setBookingType] = useState(null);
22
- const [name, setName] = useState("");
23
- const [description, setDescription] = useState("");
24
- const [hostDisplayName, setHostDisplayName] = useState("");
25
- const [durationMinutes, setDurationMinutes] = useState(30);
26
- const [timezone, setTimezone] = useState("");
27
- const [availability, setAvailability] = useState([]);
28
- const [minimumNoticeMinutes, setMinimumNoticeMinutes] = useState(60);
29
- const [bookingWindowDays, setBookingWindowDays] = useState(30);
30
- const [requiresApproval, setRequiresApproval] = useState(false);
31
- const [enabled, setEnabled] = useState(true);
32
- const [loading, setLoading] = useState(true);
33
- const [error, setError] = useState(null);
34
- const [saving, setSaving] = useState(false);
35
- const [saved, setSaved] = useState(false);
36
- const [copied, setCopied] = useState(false);
37
- const [confirmingDelete, setConfirmingDelete] = useState(false);
38
- const [deleting, setDeleting] = useState(false);
39
- const [deleteError, setDeleteError] = useState(null);
40
- useEffect(() => {
41
- setLoading(true);
42
- setError(null);
43
- getBookingType(uid)
44
- .then((bt) => {
45
- setBookingType(bt);
46
- setName(bt.name);
47
- setDescription(bt.description ?? "");
48
- setHostDisplayName(bt.hostDisplayName);
49
- setDurationMinutes(bt.durationMinutes);
50
- setTimezone(bt.timezone);
51
- setAvailability(bt.availability);
52
- setMinimumNoticeMinutes(bt.minimumNoticeMinutes);
53
- setBookingWindowDays(bt.bookingWindowDays);
54
- setRequiresApproval(bt.requiresApproval);
55
- setEnabled(bt.enabled);
56
- })
57
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load this booking link."))
58
- .finally(() => setLoading(false));
59
- }, [uid]);
60
- async function handleSubmit(e) {
61
- e.preventDefault();
62
- setError(null);
63
- setSaved(false);
64
- setSaving(true);
65
- try {
66
- const updated = await updateBookingType({
67
- uid: bookingType.uid,
68
- version: bookingType.version,
69
- name,
70
- description: description.trim() || undefined,
71
- hostDisplayName,
72
- durationMinutes,
73
- timezone,
74
- availability,
75
- minimumNoticeMinutes,
76
- bookingWindowDays,
77
- requiresApproval,
78
- enabled,
79
- });
80
- setBookingType(updated);
81
- setSaved(true);
82
- }
83
- catch (err) {
84
- setError(err instanceof ApiRequestError ? err.message : "Could not save this booking link.");
85
- }
86
- finally {
87
- setSaving(false);
88
- }
89
- }
90
- async function handleCopy(value) {
91
- try {
92
- await navigator.clipboard.writeText(value);
93
- setCopied(true);
94
- setTimeout(() => setCopied(false), 2000);
95
- }
96
- catch {
97
- // Clipboard access can be denied by the browser — the value is still selectable/copyable by hand.
98
- }
99
- }
100
- async function handleDelete() {
101
- setDeleting(true);
102
- setDeleteError(null);
103
- try {
104
- await deleteBookingType(bookingType.uid, bookingType.version);
105
- window.location.href = `/settings/booking-types?mailboxUid=${encodeURIComponent(mailboxUid)}`;
106
- }
107
- catch (err) {
108
- setDeleteError(err instanceof ApiRequestError ? err.message : "Could not delete this booking link.");
109
- setDeleting(false);
110
- }
111
- }
112
- if (loading) {
113
- return _jsx("p", { className: "p-6 text-sm text-text-muted", children: "Loading\u2026" });
114
- }
115
- if (error || !bookingType) {
116
- // `error` is always set whenever `bookingType` is falsy here: the load effect above destructures
117
- // every field off the resolved value directly (`bt.name`, `bt.hostDisplayName`, ...), so a
118
- // successful-but-empty response throws into `.catch()` — which sets `error` — before this
119
- // component ever renders past the `loading` guard above. `!bookingType` alone (with `error` still
120
- // `null`) is therefore unreachable, unlike e.g. `messages/[uid].tsx`'s identical-looking check,
121
- // which stores its fetched value whole rather than destructuring it.
122
- return (_jsx("div", { className: "p-6", children: _jsx(Alert, { children: error }) }));
123
- }
124
- // `bookingType` only ever becomes non-null via the client-only fetch above, so by the time this line
125
- // runs `window` is always defined — the `!bookingType` early return just above covers every real SSR
126
- // pass, where `bookingType` is still `null`.
127
- const publicUrl = `${window.location.origin}/book/${encodeURIComponent(bookingType.slug)}`;
128
- return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-2xl", children: [_jsxs("div", { className: "flex items-start justify-between gap-4 mb-1", children: [_jsxs("div", { children: [_jsx("a", { href: `/settings/booking-types?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-sm text-primary-dark hover:underline", children: "\u2190 All booking links" }), _jsx("h1", { className: "text-xl font-bold tracking-tight mt-1", children: bookingType.name })] }), _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto shrink-0 !border-danger !text-danger hover:!border-danger hover:!text-danger", onClick: () => setConfirmingDelete(true), children: "Delete" })] }), _jsxs("div", { className: "flex items-center gap-2 mb-5", children: [_jsx("code", { className: "flex-1 text-xs bg-surface-alt border border-border rounded-sm py-2 px-3 overflow-x-auto whitespace-nowrap", children: publicUrl }), _jsx(Button, { type: "button", variant: "secondary", className: "!w-auto shrink-0", onClick: () => handleCopy(publicUrl), children: copied ? "Copied" : "Copy" })] }), saved && !error && _jsx("div", { className: "mb-4 text-sm text-success font-medium", children: "Saved." }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-1", children: [_jsxs("label", { className: "flex items-center gap-2 text-sm mb-3", children: [_jsx("input", { type: "checkbox", checked: enabled, onChange: (e) => setEnabled(e.target.checked) }), "Enabled (publicly bookable)"] }), _jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value) }) }), _jsx(FormField, { label: "Description (optional)", htmlFor: "description", children: _jsx("textarea", { id: "description", className: INPUT_CLASS, rows: 2, value: description, onChange: (e) => setDescription(e.target.value) }) }), _jsx(FormField, { label: "Host name shown to visitors", htmlFor: "hostDisplayName", children: _jsx("input", { id: "hostDisplayName", type: "text", className: INPUT_CLASS, value: hostDisplayName, onChange: (e) => setHostDisplayName(e.target.value) }) }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsx(FormField, { label: "Duration (minutes)", htmlFor: "durationMinutes", children: _jsx("input", { id: "durationMinutes", type: "number", min: 1, className: INPUT_CLASS, value: durationMinutes, onChange: (e) => setDurationMinutes(Number(e.target.value)) }) }), _jsx(FormField, { label: "Timezone", htmlFor: "timezone", children: _jsx("input", { id: "timezone", type: "text", className: INPUT_CLASS, value: timezone, onChange: (e) => setTimezone(e.target.value) }) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsx(FormField, { label: "Minimum notice (minutes)", htmlFor: "minimumNoticeMinutes", children: _jsx("input", { id: "minimumNoticeMinutes", type: "number", min: 0, className: INPUT_CLASS, value: minimumNoticeMinutes, onChange: (e) => setMinimumNoticeMinutes(Number(e.target.value)) }) }), _jsx(FormField, { label: "Booking window (days ahead)", htmlFor: "bookingWindowDays", children: _jsx("input", { id: "bookingWindowDays", type: "number", min: 1, className: INPUT_CLASS, value: bookingWindowDays, onChange: (e) => setBookingWindowDays(Number(e.target.value)) }) })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm my-3", children: [_jsx("input", { type: "checkbox", checked: requiresApproval, onChange: (e) => setRequiresApproval(e.target.checked) }), "Require my approval before confirming a booking"] }), _jsxs("div", { className: "mb-4", children: [_jsx("span", { className: "block text-sm font-semibold mb-1.5 text-text", children: "Weekly availability" }), _jsx(AvailabilityEditor, { value: availability, onChange: setAvailability })] }), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Save" }) })] }), _jsxs(Modal, { open: confirmingDelete, onClose: () => setConfirmingDelete(false), title: "Delete booking link", children: [_jsxs("p", { className: "text-sm mb-5", children: ["Are you sure you want to delete ", _jsx("strong", { children: bookingType.name }), "? Its public link will stop working immediately. This cannot be undone."] }), deleteError && _jsx(Alert, { children: deleteError }), _jsxs("div", { className: "flex gap-3 justify-end mt-5", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", disabled: deleting, onClick: () => setConfirmingDelete(false), children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger", loading: deleting, disabled: deleting, onClick: handleDelete, children: "Delete" })] })] })] }) }));
129
- }
@@ -1,29 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- ///////////////////////////////////////////////////////////////////////////////
3
- // Copyright (C) 2026 Jean-Philippe Steinmetz
4
- // SPDX-License-Identifier: MPL-2.0
5
- ///////////////////////////////////////////////////////////////////////////////
6
- import { useEffect, useState } from "react";
7
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
- import { listBookingTypes } from "@rapidmx/react-shared/booking/bookingApi.js";
9
- import SettingsShell, { useSettingsShell } from "../../../shared/components/settings/layout/SettingsShell.js";
10
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
11
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
12
- export default function SettingsBookingTypesPage(props) {
13
- return (_jsx(SettingsShell, { ...props, active: "booking-types", children: _jsx(BookingTypesContent, {}) }));
14
- }
15
- function BookingTypesContent() {
16
- const { mailboxUid } = useSettingsShell();
17
- const [bookingTypes, setBookingTypes] = useState([]);
18
- const [loading, setLoading] = useState(true);
19
- const [error, setError] = useState(null);
20
- // `SettingsShell` only ever renders its children once `mailboxUid` has resolved — same established
21
- // non-null pattern as `apps/www/settings/filters/index.tsx`.
22
- useEffect(() => {
23
- listBookingTypes(mailboxUid)
24
- .then(setBookingTypes)
25
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load your booking links."))
26
- .finally(() => setLoading(false));
27
- }, [mailboxUid]);
28
- return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-3xl", children: [_jsxs("div", { className: "flex items-center justify-between mb-5", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight", children: "Booking Links" }), _jsx("a", { href: `/settings/booking-types/new?mailboxUid=${encodeURIComponent(mailboxUid)}`, children: _jsx(Button, { type: "button", className: "!w-auto", children: "+ New booking link" }) })] }), _jsx("p", { className: "text-sm text-text-muted mb-4", children: "Share a link and let anyone pick a real open slot on your calendar \u2014 no account needed on their end." }), error && _jsx(Alert, { children: error }), loading ? (_jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" })) : bookingTypes.length === 0 ? (_jsx("p", { className: "text-sm text-text-muted", children: "No booking links yet." })) : (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm border-collapse", children: [_jsx("thead", { children: _jsx("tr", { children: ["Name", "Link", "Duration", "Enabled", ""].map((h) => (_jsx("th", { className: "text-left text-xs uppercase tracking-wide text-text-muted py-2 px-2.5 border-b border-border", children: h }, h))) }) }), _jsx("tbody", { children: bookingTypes.map((bookingType) => (_jsxs("tr", { children: [_jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: bookingType.name }), _jsxs("td", { className: "py-2.5 px-2.5 border-b border-border", children: ["/book/", bookingType.slug] }), _jsxs("td", { className: "py-2.5 px-2.5 border-b border-border", children: [bookingType.durationMinutes, " min"] }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border", children: bookingType.enabled ? "Yes" : "No" }), _jsx("td", { className: "py-2.5 px-2.5 border-b border-border text-right", children: _jsx("a", { href: `/settings/booking-types/${encodeURIComponent(bookingType.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`, className: "text-primary-dark hover:underline font-medium", children: "View" }) })] }, bookingType.uid))) })] }) }))] }) }));
29
- }
@@ -1,86 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- ///////////////////////////////////////////////////////////////////////////////
3
- // Copyright (C) 2026 Jean-Philippe Steinmetz
4
- // SPDX-License-Identifier: MPL-2.0
5
- ///////////////////////////////////////////////////////////////////////////////
6
- import { useEffect, useState } from "react";
7
- import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
8
- import { listFolders } from "@rapidmx/react-shared/mail/mailApi.js";
9
- import { createBookingType } from "@rapidmx/react-shared/booking/bookingApi.js";
10
- import SettingsShell, { useSettingsShell } from "../../../../shared/components/settings/layout/SettingsShell.js";
11
- import AvailabilityEditor from "../../../../shared/components/booking/AvailabilityEditor.js";
12
- import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
13
- import Button from "@rapidmx/react-shared/components/buttons/Button.js";
14
- import FormField from "@rapidmx/react-shared/components/forms/FormField.js";
15
- const INPUT_CLASS = "w-full text-sm py-2.5 px-3 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
16
- export default function NewBookingTypePage(props) {
17
- return (_jsx(SettingsShell, { ...props, active: "booking-types", children: _jsx(NewBookingTypeForm, {}) }));
18
- }
19
- function NewBookingTypeForm() {
20
- const { mailboxUid, mailboxes } = useSettingsShell();
21
- // Same established non-null pattern as `apps/www/settings/filters/new/index.tsx`.
22
- const mailbox = mailboxes.find((mb) => mb.uid === mailboxUid);
23
- const [calendarFolderUid, setCalendarFolderUid] = useState(null);
24
- const [folderError, setFolderError] = useState(null);
25
- const [slug, setSlug] = useState("");
26
- const [name, setName] = useState("");
27
- const [description, setDescription] = useState("");
28
- const [hostDisplayName, setHostDisplayName] = useState(mailbox.displayName);
29
- const [durationMinutes, setDurationMinutes] = useState(30);
30
- const [timezone, setTimezone] = useState(mailbox.timezone);
31
- const [availability, setAvailability] = useState([]);
32
- const [minimumNoticeMinutes, setMinimumNoticeMinutes] = useState(60);
33
- const [bookingWindowDays, setBookingWindowDays] = useState(30);
34
- const [requiresApproval, setRequiresApproval] = useState(false);
35
- const [error, setError] = useState(null);
36
- const [saving, setSaving] = useState(false);
37
- useEffect(() => {
38
- listFolders(mailboxUid)
39
- .then((folders) => {
40
- const calendar = folders.find((f) => f.type === "calendar");
41
- if (!calendar) {
42
- setFolderError("This mailbox has no Calendar folder yet.");
43
- return;
44
- }
45
- setCalendarFolderUid(calendar.uid);
46
- })
47
- .catch((err) => setFolderError(err instanceof ApiRequestError ? err.message : "Could not load this mailbox's folders."));
48
- }, [mailboxUid]);
49
- async function handleSubmit(e) {
50
- e.preventDefault();
51
- setError(null);
52
- if (!slug.trim() || !name.trim() || !hostDisplayName.trim()) {
53
- setError("Slug, name, and host name are all required.");
54
- return;
55
- }
56
- if (!calendarFolderUid) {
57
- setError("This mailbox has no Calendar folder yet.");
58
- return;
59
- }
60
- setSaving(true);
61
- try {
62
- const created = await createBookingType({
63
- mailboxUid: mailboxUid,
64
- calendarFolderUid,
65
- slug: slug.trim(),
66
- name: name.trim(),
67
- description: description.trim() || undefined,
68
- hostDisplayName: hostDisplayName.trim(),
69
- durationMinutes,
70
- timezone,
71
- availability,
72
- minimumNoticeMinutes,
73
- bookingWindowDays,
74
- requiresApproval,
75
- });
76
- window.location.href = `/settings/booking-types/${encodeURIComponent(created.uid)}?mailboxUid=${encodeURIComponent(mailboxUid)}`;
77
- }
78
- catch (err) {
79
- setError(err instanceof ApiRequestError ? err.message : "Could not create this booking link.");
80
- }
81
- finally {
82
- setSaving(false);
83
- }
84
- }
85
- return (_jsx("div", { className: "flex-1 min-w-0 overflow-y-auto p-6", children: _jsxs("div", { className: "max-w-2xl", children: [_jsx("h1", { className: "text-lg font-bold tracking-tight mb-1", children: "New booking link" }), _jsx("p", { className: "text-sm text-text-muted mb-5", children: "Anyone with the link can pick an open slot from your live availability below \u2014 no account needed on their end." }), error && _jsx(Alert, { children: error }), folderError && _jsx(Alert, { children: folderError }), _jsxs("form", { onSubmit: handleSubmit, className: "flex flex-col gap-1", children: [_jsx(FormField, { label: "Name", htmlFor: "name", children: _jsx("input", { id: "name", type: "text", className: INPUT_CLASS, value: name, onChange: (e) => setName(e.target.value), placeholder: "30 Minute Intro Call" }) }), _jsx(FormField, { label: "Slug (used in the public link)", htmlFor: "slug", children: _jsx("input", { id: "slug", type: "text", className: INPUT_CLASS, value: slug, onChange: (e) => setSlug(e.target.value), placeholder: "intro-call" }) }), _jsx(FormField, { label: "Description (optional)", htmlFor: "description", children: _jsx("textarea", { id: "description", className: INPUT_CLASS, rows: 2, value: description, onChange: (e) => setDescription(e.target.value) }) }), _jsx(FormField, { label: "Host name shown to visitors", htmlFor: "hostDisplayName", children: _jsx("input", { id: "hostDisplayName", type: "text", className: INPUT_CLASS, value: hostDisplayName, onChange: (e) => setHostDisplayName(e.target.value) }) }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsx(FormField, { label: "Duration (minutes)", htmlFor: "durationMinutes", children: _jsx("input", { id: "durationMinutes", type: "number", min: 1, className: INPUT_CLASS, value: durationMinutes, onChange: (e) => setDurationMinutes(Number(e.target.value)) }) }), _jsx(FormField, { label: "Timezone", htmlFor: "timezone", children: _jsx("input", { id: "timezone", type: "text", className: INPUT_CLASS, value: timezone, onChange: (e) => setTimezone(e.target.value), placeholder: "America/New_York" }) })] }), _jsxs("div", { className: "grid grid-cols-2 gap-3", children: [_jsx(FormField, { label: "Minimum notice (minutes)", htmlFor: "minimumNoticeMinutes", children: _jsx("input", { id: "minimumNoticeMinutes", type: "number", min: 0, className: INPUT_CLASS, value: minimumNoticeMinutes, onChange: (e) => setMinimumNoticeMinutes(Number(e.target.value)) }) }), _jsx(FormField, { label: "Booking window (days ahead)", htmlFor: "bookingWindowDays", children: _jsx("input", { id: "bookingWindowDays", type: "number", min: 1, className: INPUT_CLASS, value: bookingWindowDays, onChange: (e) => setBookingWindowDays(Number(e.target.value)) }) })] }), _jsxs("label", { className: "flex items-center gap-2 text-sm my-3", children: [_jsx("input", { type: "checkbox", checked: requiresApproval, onChange: (e) => setRequiresApproval(e.target.checked) }), "Require my approval before confirming a booking"] }), _jsxs("div", { className: "mb-4", children: [_jsx("span", { className: "block text-sm font-semibold mb-1.5 text-text", children: "Weekly availability" }), _jsx(AvailabilityEditor, { value: availability, onChange: setAvailability })] }), _jsx("div", { children: _jsx(Button, { type: "submit", loading: saving, disabled: saving, className: "!w-auto", children: "Create" }) })] })] }) }));
86
- }