@rapidmx/web-client 0.3.1 → 0.5.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 (202) hide show
  1. package/apps/admin/audit-log/index.tsx +35 -8
  2. package/apps/admin/branding/index.tsx +39 -404
  3. package/apps/admin/data-requests/index.tsx +480 -485
  4. package/apps/admin/distribution-lists/[uid].tsx +19 -1
  5. package/apps/admin/domains/[uid].tsx +92 -259
  6. package/apps/admin/encryption-policy/index.tsx +19 -0
  7. package/apps/admin/escrow-scopes/[uid].tsx +348 -237
  8. package/apps/admin/escrow-scopes/new/index.tsx +8 -2
  9. package/apps/admin/index.tsx +118 -82
  10. package/apps/admin/ingest-queue/index.tsx +44 -5
  11. package/apps/admin/mailbox-policy/index.tsx +19 -0
  12. package/apps/admin/mailboxes/[uid].tsx +211 -184
  13. package/apps/admin/mailboxes/new/index.tsx +28 -291
  14. package/apps/admin/plugins/index.tsx +15 -0
  15. package/apps/admin/quarantine/index.tsx +46 -14
  16. package/apps/admin/retention-policy/index.tsx +39 -132
  17. package/apps/admin/setup/index.tsx +15 -0
  18. package/apps/admin/transport-rules/[uid].tsx +30 -1
  19. package/apps/admin/transport-rules/_transportRuleConfig.tsx +38 -2
  20. package/apps/admin/transport-rules/index.tsx +24 -6
  21. package/apps/admin/transport-rules/new/index.tsx +30 -1
  22. package/apps/escrow/_layout.tsx +2 -3
  23. package/apps/escrow/audit-log/index.tsx +196 -168
  24. package/apps/escrow/matters/[uid].tsx +621 -521
  25. package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +22 -1
  26. package/apps/shared/components/admin/layout/AdminShell.tsx +251 -210
  27. package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -0
  28. package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
  29. package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +55 -11
  30. package/apps/shared/components/admin/settings/BrandingForm.tsx +385 -0
  31. package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +187 -0
  32. package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +112 -0
  33. package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +34 -0
  34. package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +308 -0
  35. package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +152 -0
  36. package/apps/shared/components/admin/settings/PluginsManager.tsx +1235 -0
  37. package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +174 -0
  38. package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +290 -0
  39. package/apps/shared/components/admin/setup/SetupWizard.tsx +416 -0
  40. package/apps/shared/components/admin/signOut.ts +79 -0
  41. package/apps/shared/components/admin/usePagedList.tsx +129 -0
  42. package/apps/shared/components/calendar/CalendarListSidebar.tsx +120 -76
  43. package/apps/shared/components/calendar/EventModal.tsx +717 -513
  44. package/apps/shared/components/calendar/MonthView.tsx +173 -139
  45. package/apps/shared/components/calendar/RecurrenceEditor.tsx +222 -180
  46. package/apps/shared/components/calendar/SplitDayView.tsx +143 -137
  47. package/apps/shared/components/calendar/TimeGridView.tsx +244 -198
  48. package/apps/shared/components/calendar/allDay.ts +124 -0
  49. package/apps/shared/components/calendar/layout/CalendarShell.tsx +80 -99
  50. package/apps/shared/components/contacts/ContactDetailPane.tsx +100 -21
  51. package/apps/shared/components/contacts/ContactForm.tsx +377 -314
  52. package/apps/shared/components/contacts/ContactsSidebar.tsx +6 -2
  53. package/apps/shared/components/contacts/KeyChangeReview.tsx +192 -0
  54. package/apps/shared/components/contacts/contactKeys.ts +78 -0
  55. package/apps/shared/components/escrow/layout/EscrowShell.tsx +148 -134
  56. package/apps/shared/components/layout/AppShell.tsx +270 -169
  57. package/apps/shared/components/layout/BrandingChrome.tsx +48 -10
  58. package/apps/shared/components/layout/KeyEnrollmentGate.tsx +150 -26
  59. package/apps/shared/components/layout/MailboxProvisioning.tsx +19 -3
  60. package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +350 -0
  61. package/apps/shared/components/layout/UnlockPromptProvider.tsx +257 -0
  62. package/apps/shared/components/mail/ConversationThreadPane.tsx +216 -181
  63. package/apps/shared/components/mail/MessageDetailPane.tsx +799 -76
  64. package/apps/shared/components/mail/compose/ComposeContext.tsx +26 -16
  65. package/apps/shared/components/mail/compose/ComposeWindow.tsx +1652 -765
  66. package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -0
  67. package/apps/shared/components/mail/layout/MailShell.tsx +418 -302
  68. package/apps/shared/components/mail/pinnedSigners.ts +124 -0
  69. package/apps/shared/components/mail/verificationSeals.ts +125 -0
  70. package/apps/shared/components/mail/writableMailboxes.ts +101 -0
  71. package/apps/shared/components/rules/RuleBuilder.tsx +311 -276
  72. package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
  73. package/apps/shared/mail/findWellKnownFolderUid.ts +13 -0
  74. package/apps/shared/mail/listAllPages.ts +39 -0
  75. package/apps/shared/search/LocalIndexLifecycle.tsx +98 -0
  76. package/apps/shared/search/localIndexBlockCipher.ts +83 -0
  77. package/apps/shared/search/localIndexBuilder.ts +481 -0
  78. package/apps/shared/search/localIndexKey.ts +27 -0
  79. package/apps/shared/search/localIndexRpcClient.ts +316 -0
  80. package/apps/shared/search/localIndexSchema.ts +236 -0
  81. package/apps/shared/search/localIndexSizePreference.ts +88 -0
  82. package/apps/shared/search/localIndexStorage.ts +98 -0
  83. package/apps/shared/search/localIndexVFS.ts +266 -0
  84. package/apps/shared/search/localIndexWorker.ts +926 -0
  85. package/apps/shared/search/searchTier2.ts +79 -0
  86. package/apps/shared/search/wa-sqlite-shims.d.ts +44 -0
  87. package/apps/www/calendar/index.tsx +438 -407
  88. package/apps/www/contacts/[uid].tsx +21 -2
  89. package/apps/www/contacts/index.tsx +148 -17
  90. package/apps/www/index.tsx +1314 -486
  91. package/apps/www/messages/[uid].tsx +23 -7
  92. package/apps/www/settings/auto-reply/index.tsx +134 -129
  93. package/apps/www/settings/booking-types/[uid].tsx +306 -300
  94. package/apps/www/settings/encryption/index.tsx +800 -215
  95. package/apps/www/settings/filters/[uid].tsx +171 -155
  96. package/apps/www/settings/filters/new/index.tsx +8 -1
  97. package/apps/www/settings/focused-inbox/index.tsx +150 -148
  98. package/apps/www/settings/privacy/index.tsx +494 -436
  99. package/apps/www/settings/read-receipts/index.tsx +148 -125
  100. package/apps/www/settings/sharing/index.tsx +274 -0
  101. package/apps/www/tasks/index.tsx +638 -530
  102. package/dist/apps/admin/audit-log/index.js +38 -8
  103. package/dist/apps/admin/branding/index.js +4 -98
  104. package/dist/apps/admin/data-requests/index.js +52 -72
  105. package/dist/apps/admin/distribution-lists/[uid].js +1 -1
  106. package/dist/apps/admin/domains/[uid].js +5 -68
  107. package/dist/apps/admin/encryption-policy/index.js +8 -0
  108. package/dist/apps/admin/escrow-scopes/[uid].js +91 -12
  109. package/dist/apps/admin/escrow-scopes/new/index.js +8 -3
  110. package/dist/apps/admin/index.js +17 -1
  111. package/dist/apps/admin/ingest-queue/index.js +24 -6
  112. package/dist/apps/admin/mailbox-policy/index.js +8 -0
  113. package/dist/apps/admin/mailboxes/[uid].js +20 -4
  114. package/dist/apps/admin/mailboxes/new/index.js +4 -89
  115. package/dist/apps/admin/plugins/index.js +6 -0
  116. package/dist/apps/admin/quarantine/index.js +20 -11
  117. package/dist/apps/admin/retention-policy/index.js +3 -36
  118. package/dist/apps/admin/setup/index.js +6 -0
  119. package/dist/apps/admin/transport-rules/[uid].js +18 -2
  120. package/dist/apps/admin/transport-rules/_transportRuleConfig.js +19 -0
  121. package/dist/apps/admin/transport-rules/index.js +22 -6
  122. package/dist/apps/admin/transport-rules/new/index.js +18 -2
  123. package/dist/apps/escrow/_layout.js +3 -3
  124. package/dist/apps/escrow/audit-log/index.js +26 -1
  125. package/dist/apps/escrow/matters/[uid].js +77 -42
  126. package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +11 -2
  127. package/dist/apps/shared/components/admin/layout/AdminShell.js +37 -4
  128. package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +72 -0
  129. package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
  130. package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +22 -4
  131. package/dist/apps/shared/components/admin/settings/BrandingForm.js +116 -0
  132. package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +83 -0
  133. package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +62 -0
  134. package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +25 -0
  135. package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +112 -0
  136. package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +74 -0
  137. package/dist/apps/shared/components/admin/settings/PluginsManager.js +572 -0
  138. package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +73 -0
  139. package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +147 -0
  140. package/dist/apps/shared/components/admin/setup/SetupWizard.js +208 -0
  141. package/dist/apps/shared/components/admin/signOut.js +75 -0
  142. package/dist/apps/shared/components/admin/usePagedList.js +99 -0
  143. package/dist/apps/shared/components/calendar/CalendarListSidebar.js +24 -13
  144. package/dist/apps/shared/components/calendar/EventModal.js +154 -21
  145. package/dist/apps/shared/components/calendar/MonthView.js +12 -5
  146. package/dist/apps/shared/components/calendar/RecurrenceEditor.js +40 -5
  147. package/dist/apps/shared/components/calendar/SplitDayView.js +10 -4
  148. package/dist/apps/shared/components/calendar/TimeGridView.js +23 -7
  149. package/dist/apps/shared/components/calendar/allDay.js +111 -0
  150. package/dist/apps/shared/components/calendar/layout/CalendarShell.js +47 -39
  151. package/dist/apps/shared/components/contacts/ContactDetailPane.js +43 -5
  152. package/dist/apps/shared/components/contacts/ContactForm.js +45 -12
  153. package/dist/apps/shared/components/contacts/ContactsSidebar.js +2 -2
  154. package/dist/apps/shared/components/contacts/KeyChangeReview.js +63 -0
  155. package/dist/apps/shared/components/contacts/contactKeys.js +64 -0
  156. package/dist/apps/shared/components/escrow/layout/EscrowShell.js +24 -5
  157. package/dist/apps/shared/components/layout/AppShell.js +100 -8
  158. package/dist/apps/shared/components/layout/BrandingChrome.js +45 -10
  159. package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +63 -14
  160. package/dist/apps/shared/components/layout/MailboxProvisioning.js +10 -2
  161. package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +174 -0
  162. package/dist/apps/shared/components/layout/UnlockPromptProvider.js +136 -0
  163. package/dist/apps/shared/components/mail/ConversationThreadPane.js +50 -12
  164. package/dist/apps/shared/components/mail/MessageDetailPane.js +464 -34
  165. package/dist/apps/shared/components/mail/compose/ComposeContext.js +9 -6
  166. package/dist/apps/shared/components/mail/compose/ComposeWindow.js +807 -116
  167. package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +50 -0
  168. package/dist/apps/shared/components/mail/layout/MailShell.js +116 -41
  169. package/dist/apps/shared/components/mail/pinnedSigners.js +98 -0
  170. package/dist/apps/shared/components/mail/verificationSeals.js +112 -0
  171. package/dist/apps/shared/components/mail/writableMailboxes.js +87 -0
  172. package/dist/apps/shared/components/rules/RuleBuilder.js +34 -6
  173. package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
  174. package/dist/apps/shared/mail/findWellKnownFolderUid.js +12 -0
  175. package/dist/apps/shared/mail/listAllPages.js +25 -0
  176. package/dist/apps/shared/search/LocalIndexLifecycle.js +80 -0
  177. package/dist/apps/shared/search/localIndexBlockCipher.js +63 -0
  178. package/dist/apps/shared/search/localIndexBuilder.js +408 -0
  179. package/dist/apps/shared/search/localIndexKey.js +25 -0
  180. package/dist/apps/shared/search/localIndexRpcClient.js +241 -0
  181. package/dist/apps/shared/search/localIndexSchema.js +185 -0
  182. package/dist/apps/shared/search/localIndexSizePreference.js +78 -0
  183. package/dist/apps/shared/search/localIndexStorage.js +86 -0
  184. package/dist/apps/shared/search/localIndexVFS.js +258 -0
  185. package/dist/apps/shared/search/localIndexWorker.js +687 -0
  186. package/dist/apps/shared/search/searchTier2.js +38 -0
  187. package/dist/apps/www/calendar/index.js +38 -18
  188. package/dist/apps/www/contacts/[uid].js +13 -2
  189. package/dist/apps/www/contacts/index.js +94 -15
  190. package/dist/apps/www/index.js +770 -137
  191. package/dist/apps/www/messages/[uid].js +23 -7
  192. package/dist/apps/www/settings/auto-reply/index.js +9 -4
  193. package/dist/apps/www/settings/booking-types/[uid].js +17 -12
  194. package/dist/apps/www/settings/encryption/index.js +541 -96
  195. package/dist/apps/www/settings/filters/[uid].js +22 -7
  196. package/dist/apps/www/settings/filters/new/index.js +8 -2
  197. package/dist/apps/www/settings/focused-inbox/index.js +3 -1
  198. package/dist/apps/www/settings/privacy/index.js +57 -22
  199. package/dist/apps/www/settings/read-receipts/index.js +10 -3
  200. package/dist/apps/www/settings/sharing/index.js +124 -0
  201. package/dist/apps/www/tasks/index.js +76 -14
  202. package/package.json +3 -2
@@ -19,7 +19,7 @@ export default function MessageDetailPage(props) {
19
19
  return (_jsx(MailShell, { ...props, children: _jsx(MessageDetailContent, { uid: props.params.uid }) }));
20
20
  }
21
21
  function MessageDetailContent({ uid }) {
22
- const { folders, mailboxUid } = useMailShell();
22
+ const { mailboxFolders, mailboxUid } = useMailShell();
23
23
  const [message, setMessage] = useState(null);
24
24
  const [loading, setLoading] = useState(true);
25
25
  const [error, setError] = useState(null);
@@ -33,13 +33,25 @@ function MessageDetailContent({ uid }) {
33
33
  .finally(() => setLoading(false));
34
34
  }, [uid]);
35
35
  // See `apps/www/index.tsx`'s identical effect's own doc comment - a failure here just hides the
36
- // Labels control rather than blocking the rest of the page. No `mailboxUid` guard needed - `MailShell`
37
- // never renders this component at all until `mailboxUid` has resolved.
36
+ // Labels control rather than blocking the rest of the page. Keyed on the message's own mailbox, not the
37
+ // shell's ambient one: this route is reached from aggregate/search rows too, where they can differ.
38
+ const messageMailboxUid = message?.mailboxUid;
38
39
  useEffect(() => {
39
- listLabels(mailboxUid, { limit: 200 })
40
- .then(setLabels)
41
- .catch(() => setLabels([]));
42
- }, [mailboxUid]);
40
+ if (!messageMailboxUid) {
41
+ return;
42
+ }
43
+ let cancelled = false;
44
+ listLabels(messageMailboxUid, { limit: 200 })
45
+ .then((result) => {
46
+ if (!cancelled) {
47
+ setLabels(result);
48
+ }
49
+ })
50
+ .catch(() => undefined);
51
+ return () => {
52
+ cancelled = true;
53
+ };
54
+ }, [messageMailboxUid]);
43
55
  const attachments = useMessageAttachments(message);
44
56
  useMarkMessageRead(message, setMessage);
45
57
  if (loading) {
@@ -48,6 +60,10 @@ function MessageDetailContent({ uid }) {
48
60
  if (error || !message) {
49
61
  return _jsx(Alert, { children: error ?? "Message not found." });
50
62
  }
63
+ // Looked up by the message's own mailboxUid, not the shell's ambient `mailboxUid` - the mobile detail
64
+ // route reaches here from an aggregate ("All Inboxes" etc.) list row too, where there's no single
65
+ // selected mailbox to fall back to.
66
+ const folders = mailboxFolders.find((mf) => mf.mailbox.uid === message.mailboxUid)?.folders ?? [];
51
67
  const backHref = `/?mailboxUid=${encodeURIComponent(message.mailboxUid)}&folderUid=${encodeURIComponent(message.folderUid)}`;
52
68
  const isSentItems = folders.find((f) => f.uid === message.folderUid)?.type === "sent_items";
53
69
  const isOutbox = folders.find((f) => f.uid === message.folderUid)?.type === "outbox";
@@ -24,6 +24,9 @@ function AutoReplyContent() {
24
24
  const [oofMessage, setOofMessage] = useState(mailbox.oofMessage ?? "");
25
25
  const [oofStartTime, setOofStartTime] = useState(mailbox.oofStartTime ? toDatetimeLocal(mailbox.oofStartTime) : "");
26
26
  const [oofEndTime, setOofEndTime] = useState(mailbox.oofEndTime ? toDatetimeLocal(mailbox.oofEndTime) : "");
27
+ // `SettingsShell`'s `mailboxes` is fetched once - every save bumps the server's version, so a second
28
+ // save without a reload must send the version the previous save returned, not the stale original.
29
+ const [version, setVersion] = useState(mailbox.version);
27
30
  const [error, setError] = useState(null);
28
31
  const [saving, setSaving] = useState(false);
29
32
  const [saved, setSaved] = useState(false);
@@ -33,14 +36,16 @@ function AutoReplyContent() {
33
36
  setSaved(false);
34
37
  setSaving(true);
35
38
  try {
36
- await updateMailbox({
39
+ const updated = await updateMailbox({
37
40
  uid: mailbox.uid,
38
- version: mailbox.version,
41
+ version,
39
42
  oofEnabled,
40
43
  oofMessage,
41
- oofStartTime: oofStartTime ? new Date(oofStartTime).toISOString() : undefined,
42
- oofEndTime: oofEndTime ? new Date(oofEndTime).toISOString() : undefined,
44
+ // `null` (not omitted) clears a previously saved window - an omitted field is left as-is.
45
+ oofStartTime: oofStartTime ? new Date(oofStartTime).toISOString() : null,
46
+ oofEndTime: oofEndTime ? new Date(oofEndTime).toISOString() : null,
43
47
  });
48
+ setVersion(updated.version);
44
49
  setSaved(true);
45
50
  }
46
51
  catch (err) {
@@ -30,7 +30,10 @@ function BookingTypeDetailContent({ uid }) {
30
30
  const [requiresApproval, setRequiresApproval] = useState(false);
31
31
  const [enabled, setEnabled] = useState(true);
32
32
  const [loading, setLoading] = useState(true);
33
- const [error, setError] = useState(null);
33
+ // Split so a failed save keeps the form (and the user's edits) on screen - only a failed *load* has
34
+ // nothing to show but the error.
35
+ const [loadError, setLoadError] = useState(null);
36
+ const [saveError, setSaveError] = useState(null);
34
37
  const [saving, setSaving] = useState(false);
35
38
  const [saved, setSaved] = useState(false);
36
39
  const [copied, setCopied] = useState(false);
@@ -39,7 +42,7 @@ function BookingTypeDetailContent({ uid }) {
39
42
  const [deleteError, setDeleteError] = useState(null);
40
43
  useEffect(() => {
41
44
  setLoading(true);
42
- setError(null);
45
+ setLoadError(null);
43
46
  getBookingType(uid)
44
47
  .then((bt) => {
45
48
  setBookingType(bt);
@@ -54,12 +57,12 @@ function BookingTypeDetailContent({ uid }) {
54
57
  setRequiresApproval(bt.requiresApproval);
55
58
  setEnabled(bt.enabled);
56
59
  })
57
- .catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load this booking link."))
60
+ .catch((err) => setLoadError(err instanceof ApiRequestError ? err.message : "Could not load this booking link."))
58
61
  .finally(() => setLoading(false));
59
62
  }, [uid]);
60
63
  async function handleSubmit(e) {
61
64
  e.preventDefault();
62
- setError(null);
65
+ setSaveError(null);
63
66
  setSaved(false);
64
67
  setSaving(true);
65
68
  try {
@@ -67,7 +70,9 @@ function BookingTypeDetailContent({ uid }) {
67
70
  uid: bookingType.uid,
68
71
  version: bookingType.version,
69
72
  name,
70
- description: description.trim() || undefined,
73
+ // `null` (not omitted) clears a saved description - an omitted field is left unchanged by the
74
+ // server's partial update. `UpdateBookingTypeInput` doesn't declare `null` yet, hence the cast.
75
+ description: description.trim() || null,
71
76
  hostDisplayName,
72
77
  durationMinutes,
73
78
  timezone,
@@ -81,7 +86,7 @@ function BookingTypeDetailContent({ uid }) {
81
86
  setSaved(true);
82
87
  }
83
88
  catch (err) {
84
- setError(err instanceof ApiRequestError ? err.message : "Could not save this booking link.");
89
+ setSaveError(err instanceof ApiRequestError ? err.message : "Could not save this booking link.");
85
90
  }
86
91
  finally {
87
92
  setSaving(false);
@@ -112,18 +117,18 @@ function BookingTypeDetailContent({ uid }) {
112
117
  if (loading) {
113
118
  return _jsx("p", { className: "p-6 text-sm text-text-muted", children: "Loading\u2026" });
114
119
  }
115
- if (error || !bookingType) {
116
- // `error` is always set whenever `bookingType` is falsy here: the load effect above destructures
120
+ if (loadError || !bookingType) {
121
+ // `loadError` is always set whenever `bookingType` is falsy here: the load effect above destructures
117
122
  // 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
123
+ // successful-but-empty response throws into `.catch()` — which sets `loadError` — before this
124
+ // component ever renders past the `loading` guard above. `!bookingType` alone (with `loadError` still
120
125
  // `null`) is therefore unreachable, unlike e.g. `messages/[uid].tsx`'s identical-looking check,
121
126
  // which stores its fetched value whole rather than destructuring it.
122
- return (_jsx("div", { className: "p-6", children: _jsx(Alert, { children: error }) }));
127
+ return (_jsx("div", { className: "p-6", children: _jsx(Alert, { children: loadError }) }));
123
128
  }
124
129
  // `bookingType` only ever becomes non-null via the client-only fetch above, so by the time this line
125
130
  // runs `window` is always defined — the `!bookingType` early return just above covers every real SSR
126
131
  // pass, where `bookingType` is still `null`.
127
132
  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" })] })] })] }) }));
133
+ 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" })] }), saveError && _jsx(Alert, { children: saveError }), saved && !saveError && _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
134
  }