@rapidmx/web-client 0.5.0 → 0.7.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.
- package/README.md +88 -0
- package/apps/shared/components/admin/layout/AdminShell.tsx +25 -8
- package/apps/shared/components/admin/settings/BrandingForm.tsx +398 -385
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -112
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +159 -152
- package/apps/shared/components/admin/settings/PluginsManager.tsx +1288 -1235
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +9 -1
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -290
- package/apps/shared/components/admin/setup/SetupWizard.tsx +443 -416
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +194 -192
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +199 -197
- package/apps/shared/components/layout/AppShell.tsx +288 -270
- package/apps/shared/components/mail/ConversationList.tsx +225 -33
- package/apps/shared/components/mail/ConversationThreadPane.tsx +434 -216
- package/apps/shared/components/mail/MailListToolbar.tsx +265 -0
- package/apps/shared/components/mail/MailSelectionBar.tsx +222 -0
- package/apps/shared/components/mail/MenuButton.tsx +384 -0
- package/apps/shared/components/mail/MessageDetailPane.tsx +280 -215
- package/apps/shared/components/mail/MoveToFolderDialog.tsx +263 -0
- package/apps/shared/components/mail/compose/ComposeContext.tsx +29 -2
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1700 -1652
- package/apps/shared/components/mail/compose/RecipientInput.tsx +356 -0
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +38 -3
- package/apps/shared/components/mail/compose/quotedBody.ts +100 -0
- package/apps/shared/components/mail/compose/recipients.ts +104 -0
- package/apps/shared/components/mail/labelMenu.tsx +278 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +31 -4
- package/apps/shared/components/mail/listPreferences.ts +228 -0
- package/apps/shared/components/settings/layout/SettingsShell.tsx +23 -10
- package/apps/shared/components/tasks/layout/TasksShell.tsx +201 -199
- package/apps/shared/plugins/pluginNav.ts +73 -0
- package/apps/shared/search/localIndexRpcClient.ts +3 -1
- package/apps/shared/styles/app.css +28 -5
- package/apps/www/index.tsx +1854 -1314
- package/apps/www/messages/[uid].tsx +5 -4
- package/dist/apps/admin/_404.d.ts +2 -0
- package/dist/apps/admin/_500.d.ts +2 -0
- package/dist/apps/admin/_layout.d.ts +8 -0
- package/dist/apps/admin/audit-log/index.d.ts +11 -0
- package/dist/apps/admin/branding/index.d.ts +3 -0
- package/dist/apps/admin/data-requests/index.d.ts +3 -0
- package/dist/apps/admin/distribution-lists/[uid].d.ts +7 -0
- package/dist/apps/admin/distribution-lists/index.d.ts +3 -0
- package/dist/apps/admin/distribution-lists/new/index.d.ts +3 -0
- package/dist/apps/admin/domains/[uid].d.ts +7 -0
- package/dist/apps/admin/domains/index.d.ts +3 -0
- package/dist/apps/admin/domains/new/index.d.ts +3 -0
- package/dist/apps/admin/encryption-policy/index.d.ts +3 -0
- package/dist/apps/admin/escrow-scopes/[uid].d.ts +21 -0
- package/dist/apps/admin/escrow-scopes/index.d.ts +3 -0
- package/dist/apps/admin/escrow-scopes/new/index.d.ts +3 -0
- package/dist/apps/admin/index.d.ts +3 -0
- package/dist/apps/admin/ingest-queue/index.d.ts +4 -0
- package/dist/apps/admin/mailbox-policy/index.d.ts +3 -0
- package/dist/apps/admin/mailboxes/[uid].d.ts +7 -0
- package/dist/apps/admin/mailboxes/new/index.d.ts +3 -0
- package/dist/apps/admin/plugins/index.d.ts +3 -0
- package/dist/apps/admin/quarantine/index.d.ts +6 -0
- package/dist/apps/admin/retention-policy/index.d.ts +3 -0
- package/dist/apps/admin/setup/index.d.ts +3 -0
- package/dist/apps/admin/transport-rules/[uid].d.ts +7 -0
- package/dist/apps/admin/transport-rules/_transportRuleConfig.d.ts +21 -0
- package/dist/apps/admin/transport-rules/index.d.ts +3 -0
- package/dist/apps/admin/transport-rules/new/index.d.ts +3 -0
- package/dist/apps/escrow/_layout.d.ts +10 -0
- package/dist/apps/escrow/audit-log/index.d.ts +9 -0
- package/dist/apps/escrow/index.d.ts +3 -0
- package/dist/apps/escrow/matters/[uid].d.ts +7 -0
- package/dist/apps/escrow/matters/new/index.d.ts +3 -0
- package/dist/apps/shared/components/admin/distributionLists/MemberListCard.d.ts +17 -0
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.d.ts +32 -0
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +32 -0
- package/dist/apps/shared/components/admin/layout/AdminShell.js +12 -5
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.d.ts +12 -0
- package/dist/apps/shared/components/admin/mailboxes/MailboxTable.d.ts +6 -0
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.d.ts +19 -0
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/BrandingForm.d.ts +13 -0
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +6 -5
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.d.ts +15 -0
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +2 -2
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.d.ts +9 -0
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.d.ts +19 -0
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.d.ts +13 -0
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +2 -2
- package/dist/apps/shared/components/admin/settings/PluginsManager.d.ts +11 -0
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +33 -14
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.d.ts +12 -0
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +2 -2
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.d.ts +14 -0
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +1 -1
- package/dist/apps/shared/components/admin/setup/SetupWizard.d.ts +36 -0
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +14 -10
- package/dist/apps/shared/components/admin/signOut.d.ts +23 -0
- package/dist/apps/shared/components/admin/usePagedList.d.ts +39 -0
- package/dist/apps/shared/components/calendar/CalendarListSidebar.d.ts +26 -0
- package/dist/apps/shared/components/calendar/EventModal.d.ts +46 -0
- package/dist/apps/shared/components/calendar/MonthView.d.ts +15 -0
- package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +20 -0
- package/dist/apps/shared/components/calendar/ResourcePicker.d.ts +19 -0
- package/dist/apps/shared/components/calendar/SplitDayView.d.ts +28 -0
- package/dist/apps/shared/components/calendar/TimeGridView.d.ts +17 -0
- package/dist/apps/shared/components/calendar/allDay.d.ts +51 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.d.ts +40 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +2 -2
- package/dist/apps/shared/components/contacts/ContactDetailPane.d.ts +23 -0
- package/dist/apps/shared/components/contacts/ContactForm.d.ts +20 -0
- package/dist/apps/shared/components/contacts/ContactsSidebar.d.ts +40 -0
- package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +25 -0
- package/dist/apps/shared/components/contacts/KeyChangeReview.d.ts +40 -0
- package/dist/apps/shared/components/contacts/contactKeys.d.ts +29 -0
- package/dist/apps/shared/components/contacts/layout/ContactsShell.d.ts +21 -0
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +2 -2
- package/dist/apps/shared/components/escrow/layout/EscrowShell.d.ts +25 -0
- package/dist/apps/shared/components/forms/StringListField.d.ts +22 -0
- package/dist/apps/shared/components/layout/AppShell.d.ts +49 -0
- package/dist/apps/shared/components/layout/AppShell.js +15 -13
- package/dist/apps/shared/components/layout/BrandingChrome.d.ts +18 -0
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.d.ts +51 -0
- package/dist/apps/shared/components/layout/MailboxProvisioning.d.ts +13 -0
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.d.ts +66 -0
- package/dist/apps/shared/components/layout/UnlockPromptProvider.d.ts +45 -0
- package/dist/apps/shared/components/layout/UserMenu.d.ts +23 -0
- package/dist/apps/shared/components/mail/ConversationList.d.ts +47 -0
- package/dist/apps/shared/components/mail/ConversationList.js +84 -10
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +62 -0
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +217 -60
- package/dist/apps/shared/components/mail/MailListToolbar.d.ts +55 -0
- package/dist/apps/shared/components/mail/MailListToolbar.js +149 -0
- package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +59 -0
- package/dist/apps/shared/components/mail/MailSelectionBar.js +48 -0
- package/dist/apps/shared/components/mail/MenuButton.d.ts +71 -0
- package/dist/apps/shared/components/mail/MenuButton.js +211 -0
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +101 -0
- package/dist/apps/shared/components/mail/MessageDetailPane.js +126 -129
- package/dist/apps/shared/components/mail/MoveToFolderDialog.d.ts +57 -0
- package/dist/apps/shared/components/mail/MoveToFolderDialog.js +138 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.d.ts +73 -0
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +3 -1
- package/dist/apps/shared/components/mail/compose/ComposeToolbar.d.ts +15 -0
- package/dist/apps/shared/components/mail/compose/ComposeWindow.d.ts +37 -0
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +52 -20
- package/dist/apps/shared/components/mail/compose/EmojiPicker.d.ts +14 -0
- package/dist/apps/shared/components/mail/compose/GifPicker.d.ts +13 -0
- package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +36 -0
- package/dist/apps/shared/components/mail/compose/RecipientInput.js +203 -0
- package/dist/apps/shared/components/mail/compose/RichTextEditor.d.ts +43 -0
- package/dist/apps/shared/components/mail/compose/RichTextEditor.js +21 -3
- package/dist/apps/shared/components/mail/compose/ScheduleSendPicker.d.ts +16 -0
- package/dist/apps/shared/components/mail/compose/composeFlushRegistry.d.ts +27 -0
- package/dist/apps/shared/components/mail/compose/quotedBody.d.ts +37 -0
- package/dist/apps/shared/components/mail/compose/quotedBody.js +85 -0
- package/dist/apps/shared/components/mail/compose/recipients.d.ts +24 -0
- package/dist/apps/shared/components/mail/compose/recipients.js +87 -0
- package/dist/apps/shared/components/mail/labelMenu.d.ts +97 -0
- package/dist/apps/shared/components/mail/labelMenu.js +134 -0
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +65 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +17 -5
- package/dist/apps/shared/components/mail/listPreferences.d.ts +101 -0
- package/dist/apps/shared/components/mail/listPreferences.js +186 -0
- package/dist/apps/shared/components/mail/pinnedSigners.d.ts +33 -0
- package/dist/apps/shared/components/mail/verificationSeals.d.ts +22 -0
- package/dist/apps/shared/components/mail/writableMailboxes.d.ts +15 -0
- package/dist/apps/shared/components/rules/RuleBuilder.d.ts +70 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.d.ts +41 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +19 -10
- package/dist/apps/shared/components/tasks/TasksSidebar.d.ts +41 -0
- package/dist/apps/shared/components/tasks/TasksToolbar.d.ts +14 -0
- package/dist/apps/shared/components/tasks/layout/TasksShell.d.ts +24 -0
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +2 -2
- package/dist/apps/shared/mail/findWellKnownFolderUid.d.ts +5 -0
- package/dist/apps/shared/mail/listAllPages.d.ts +17 -0
- package/dist/apps/shared/plugins/pluginNav.d.ts +39 -0
- package/dist/apps/shared/plugins/pluginNav.js +33 -0
- package/dist/apps/shared/search/LocalIndexLifecycle.d.ts +13 -0
- package/dist/apps/shared/search/localIndexBlockCipher.d.ts +36 -0
- package/dist/apps/shared/search/localIndexBuilder.d.ts +85 -0
- package/dist/apps/shared/search/localIndexKey.d.ts +4 -0
- package/dist/apps/shared/search/localIndexRpcClient.d.ts +71 -0
- package/dist/apps/shared/search/localIndexRpcClient.js +3 -1
- package/dist/apps/shared/search/localIndexSchema.d.ts +111 -0
- package/dist/apps/shared/search/localIndexSizePreference.d.ts +27 -0
- package/dist/apps/shared/search/localIndexStorage.d.ts +28 -0
- package/dist/apps/shared/search/localIndexVFS.d.ts +101 -0
- package/dist/apps/shared/search/localIndexWorker.d.ts +145 -0
- package/dist/apps/shared/search/searchTier2.d.ts +30 -0
- package/dist/apps/shared/styles/app.css +28 -5
- package/dist/apps/www/_404.d.ts +2 -0
- package/dist/apps/www/_500.d.ts +2 -0
- package/dist/apps/www/_layout.d.ts +14 -0
- package/dist/apps/www/calendar/index.d.ts +3 -0
- package/dist/apps/www/contacts/[uid].d.ts +13 -0
- package/dist/apps/www/contacts/index.d.ts +3 -0
- package/dist/apps/www/index.d.ts +3 -0
- package/dist/apps/www/index.js +506 -112
- package/dist/apps/www/messages/[uid].d.ts +11 -0
- package/dist/apps/www/messages/[uid].js +2 -3
- package/dist/apps/www/settings/auto-reply/index.d.ts +4 -0
- package/dist/apps/www/settings/encryption/index.d.ts +7 -0
- package/dist/apps/www/settings/filters/[uid].d.ts +8 -0
- package/dist/apps/www/settings/filters/_mailFilterRuleConfig.d.ts +11 -0
- package/dist/apps/www/settings/filters/index.d.ts +4 -0
- package/dist/apps/www/settings/filters/new/index.d.ts +4 -0
- package/dist/apps/www/settings/labels/index.d.ts +4 -0
- package/dist/apps/www/settings/privacy/index.d.ts +4 -0
- package/dist/apps/www/settings/read-receipts/index.d.ts +4 -0
- package/dist/apps/www/settings/sharing/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/[uid].d.ts +8 -0
- package/dist/apps/www/settings/signatures/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/new/index.d.ts +4 -0
- package/dist/apps/www/settings/signatures/signatureDefaults.d.ts +10 -0
- package/dist/apps/www/tasks/index.d.ts +3 -0
- package/package.json +3 -3
- package/apps/shared/components/booking/AvailabilityEditor.tsx +0 -118
- package/apps/www/settings/booking-types/[uid].tsx +0 -306
- package/apps/www/settings/booking-types/index.tsx +0 -98
- package/apps/www/settings/booking-types/new/index.tsx +0 -212
- package/apps/www/settings/focused-inbox/index.tsx +0 -150
- package/dist/apps/shared/components/booking/AvailabilityEditor.js +0 -45
- package/dist/apps/www/settings/booking-types/[uid].js +0 -134
- package/dist/apps/www/settings/booking-types/index.js +0 -29
- package/dist/apps/www/settings/booking-types/new/index.js +0 -86
- package/dist/apps/www/settings/focused-inbox/index.js +0 -71
|
@@ -1,197 +1,199 @@
|
|
|
1
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import React, { createContext, PropsWithChildren, ReactNode, useContext, useEffect, useMemo, useState } from "react";
|
|
6
|
-
import { HiOutlineBars3 } from "react-icons/hi2";
|
|
7
|
-
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
8
|
-
import Drawer from "@rapidmx/react-shared/components/overlays/Drawer.js";
|
|
9
|
-
import { Folder, Mailbox, listFolders, listMailboxes } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
10
|
-
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
11
|
-
import Skeleton, { SkeletonList } from "@rapidmx/react-shared/components/feedback/Skeleton.js";
|
|
12
|
-
import AppShell, { AppShellProps } from "../../layout/AppShell.js";
|
|
13
|
-
import MailboxProvisioning from "../../layout/MailboxProvisioning.js";
|
|
14
|
-
|
|
15
|
-
export type ContactsShellProps = Omit<AppShellProps, "active">;
|
|
16
|
-
|
|
17
|
-
export interface ContactsShellContextValue {
|
|
18
|
-
/** The mailbox currently selected (`?mailboxUid=`, or the caller's first accessible mailbox). */
|
|
19
|
-
mailboxUid?: string;
|
|
20
|
-
/** The selected mailbox's single `contacts`-type folder. */
|
|
21
|
-
folderUid?: string;
|
|
22
|
-
mailboxes: Mailbox[];
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const ContactsShellContext = createContext<ContactsShellContextValue>({ mailboxes: [] });
|
|
26
|
-
|
|
27
|
-
/** Reads the mailbox/folder Contacts is currently showing, as resolved by the enclosing `ContactsShell`. */
|
|
28
|
-
export function useContactsShell(): ContactsShellContextValue {
|
|
29
|
-
return useContext(ContactsShellContext);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
type Status = "checking" | "error" | "ready";
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* The Contacts app's shell: unlike `MailShell` (a folder tree, since a mailbox has many mail folders),
|
|
36
|
-
* a mailbox has exactly one well-known `contacts` folder — see `BaseMailboxRoute.create()`'s eager
|
|
37
|
-
* provisioning in `@rapidmx/restapi`, which guarantees it exists for every mailbox. This shell's own
|
|
38
|
-
* sidebar is therefore just a mailbox switcher (when the caller has more than one); the actual contact
|
|
39
|
-
* list/detail UI is `apps/www/contacts/index.tsx`'s own content, rendered as `children` here.
|
|
40
|
-
*/
|
|
41
|
-
export default function ContactsShell({
|
|
42
|
-
userUid,
|
|
43
|
-
authServerUrl,
|
|
44
|
-
impersonating,
|
|
45
|
-
impersonationBaseUrl,
|
|
46
|
-
trusted,
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
const [
|
|
51
|
-
const [
|
|
52
|
-
const [
|
|
53
|
-
const [
|
|
54
|
-
const [
|
|
55
|
-
const [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
mailboxes
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
.
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
//
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
//
|
|
108
|
-
//
|
|
109
|
-
//
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
<
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
//
|
|
127
|
-
//
|
|
128
|
-
// label-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
{mb.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
{
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import React, { createContext, PropsWithChildren, ReactNode, useContext, useEffect, useMemo, useState } from "react";
|
|
6
|
+
import { HiOutlineBars3 } from "react-icons/hi2";
|
|
7
|
+
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
8
|
+
import Drawer from "@rapidmx/react-shared/components/overlays/Drawer.js";
|
|
9
|
+
import { Folder, Mailbox, listFolders, listMailboxes } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
10
|
+
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
11
|
+
import Skeleton, { SkeletonList } from "@rapidmx/react-shared/components/feedback/Skeleton.js";
|
|
12
|
+
import AppShell, { AppShellProps } from "../../layout/AppShell.js";
|
|
13
|
+
import MailboxProvisioning from "../../layout/MailboxProvisioning.js";
|
|
14
|
+
|
|
15
|
+
export type ContactsShellProps = Omit<AppShellProps, "active">;
|
|
16
|
+
|
|
17
|
+
export interface ContactsShellContextValue {
|
|
18
|
+
/** The mailbox currently selected (`?mailboxUid=`, or the caller's first accessible mailbox). */
|
|
19
|
+
mailboxUid?: string;
|
|
20
|
+
/** The selected mailbox's single `contacts`-type folder. */
|
|
21
|
+
folderUid?: string;
|
|
22
|
+
mailboxes: Mailbox[];
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const ContactsShellContext = createContext<ContactsShellContextValue>({ mailboxes: [] });
|
|
26
|
+
|
|
27
|
+
/** Reads the mailbox/folder Contacts is currently showing, as resolved by the enclosing `ContactsShell`. */
|
|
28
|
+
export function useContactsShell(): ContactsShellContextValue {
|
|
29
|
+
return useContext(ContactsShellContext);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
type Status = "checking" | "error" | "ready";
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The Contacts app's shell: unlike `MailShell` (a folder tree, since a mailbox has many mail folders),
|
|
36
|
+
* a mailbox has exactly one well-known `contacts` folder — see `BaseMailboxRoute.create()`'s eager
|
|
37
|
+
* provisioning in `@rapidmx/restapi`, which guarantees it exists for every mailbox. This shell's own
|
|
38
|
+
* sidebar is therefore just a mailbox switcher (when the caller has more than one); the actual contact
|
|
39
|
+
* list/detail UI is `apps/www/contacts/index.tsx`'s own content, rendered as `children` here.
|
|
40
|
+
*/
|
|
41
|
+
export default function ContactsShell({
|
|
42
|
+
userUid,
|
|
43
|
+
authServerUrl,
|
|
44
|
+
impersonating,
|
|
45
|
+
impersonationBaseUrl,
|
|
46
|
+
trusted,
|
|
47
|
+
pluginNav,
|
|
48
|
+
children,
|
|
49
|
+
}: PropsWithChildren<ContactsShellProps>) {
|
|
50
|
+
const [status, setStatus] = useState<Status>("checking");
|
|
51
|
+
const [error, setError] = useState<string | null>(null);
|
|
52
|
+
const [mailboxes, setMailboxes] = useState<Mailbox[]>([]);
|
|
53
|
+
const [folders, setFolders] = useState<Folder[]>([]);
|
|
54
|
+
const [folderError, setFolderError] = useState<string | null>(null);
|
|
55
|
+
const [requestedMailboxUid, setRequestedMailboxUid] = useState<string | null>(null);
|
|
56
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
57
|
+
|
|
58
|
+
useEffect(() => {
|
|
59
|
+
setRequestedMailboxUid(new URLSearchParams(window.location.search).get("mailboxUid"));
|
|
60
|
+
}, []);
|
|
61
|
+
|
|
62
|
+
useEffect(() => {
|
|
63
|
+
if (!userUid) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
listMailboxes({ limit: 100 })
|
|
67
|
+
.then((result) => {
|
|
68
|
+
setMailboxes(result);
|
|
69
|
+
setStatus("ready");
|
|
70
|
+
})
|
|
71
|
+
.catch((err) => {
|
|
72
|
+
setError(err instanceof ApiRequestError ? err.message : "Could not load your mailboxes.");
|
|
73
|
+
setStatus("error");
|
|
74
|
+
});
|
|
75
|
+
}, [userUid]);
|
|
76
|
+
|
|
77
|
+
const mailboxUid: string | undefined =
|
|
78
|
+
(requestedMailboxUid && mailboxes.some((mb) => mb.uid === requestedMailboxUid) ? requestedMailboxUid : undefined) ??
|
|
79
|
+
mailboxes[0]?.uid;
|
|
80
|
+
|
|
81
|
+
useEffect(() => {
|
|
82
|
+
if (!mailboxUid) {
|
|
83
|
+
setFolders([]);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
setFolderError(null);
|
|
87
|
+
listFolders(mailboxUid)
|
|
88
|
+
.then(setFolders)
|
|
89
|
+
.catch((err) => setFolderError(err instanceof ApiRequestError ? err.message : "Could not load this mailbox's contacts folder."));
|
|
90
|
+
}, [mailboxUid]);
|
|
91
|
+
|
|
92
|
+
const folderUid: string | undefined = folders.find((f) => f.type === "contacts")?.uid;
|
|
93
|
+
|
|
94
|
+
const contextValue = useMemo<ContactsShellContextValue>(
|
|
95
|
+
() => ({ mailboxUid, folderUid, mailboxes }),
|
|
96
|
+
[mailboxUid, folderUid, mailboxes],
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
// A full-screen takeover, not nested inside the rest of the app's chrome — there's nothing else
|
|
100
|
+
// for a mailbox-less caller to do here yet, so the icon rail/header don't render at all.
|
|
101
|
+
if (userUid && status === "ready" && !mailboxUid) {
|
|
102
|
+
return <MailboxProvisioning />;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let inner: ReactNode = null;
|
|
106
|
+
if (userUid && status === "checking") {
|
|
107
|
+
// Renders immediately (no network round trip needed) so switching into Contacts never shows a
|
|
108
|
+
// blank pane while `listMailboxes()` is in flight — the real sidebar (favorites/lists/categories)
|
|
109
|
+
// lives in `apps/www/contacts/index.tsx`'s own content, so this mimics its rough shape rather
|
|
110
|
+
// than the (minimal, mailbox-switcher-only) shape of this shell's own sidebar.
|
|
111
|
+
inner = (
|
|
112
|
+
<div className="w-56 shrink-0 border-r border-border flex flex-col gap-4 p-3">
|
|
113
|
+
<Skeleton height="h-9" />
|
|
114
|
+
<SkeletonList count={5} />
|
|
115
|
+
</div>
|
|
116
|
+
);
|
|
117
|
+
} else if (userUid && status === "error") {
|
|
118
|
+
inner = (
|
|
119
|
+
<div className="flex-1 flex items-center justify-center p-8">
|
|
120
|
+
<div className="w-full max-w-md">
|
|
121
|
+
<Alert>{error}</Alert>
|
|
122
|
+
</div>
|
|
123
|
+
</div>
|
|
124
|
+
);
|
|
125
|
+
} else if (userUid && status === "ready") {
|
|
126
|
+
// A function, not a plain JSX constant — see MailShell's identical comment: it's rendered twice
|
|
127
|
+
// (desktop `<aside>` + mobile `Drawer`), possibly simultaneously mounted, so the `<select>`'s
|
|
128
|
+
// `id`/its `<label>`'s `htmlFor` need a distinct value per instance to avoid a duplicate-id
|
|
129
|
+
// label-association break.
|
|
130
|
+
const sidebarContent = (idPrefix: string) => (
|
|
131
|
+
<>
|
|
132
|
+
{mailboxes.length > 1 && (
|
|
133
|
+
<div>
|
|
134
|
+
<label
|
|
135
|
+
className="block text-xs font-bold uppercase tracking-wide text-text-muted mb-1"
|
|
136
|
+
htmlFor={`${idPrefix}-contacts-mailbox-switcher`}
|
|
137
|
+
>
|
|
138
|
+
Mailbox
|
|
139
|
+
</label>
|
|
140
|
+
<select
|
|
141
|
+
id={`${idPrefix}-contacts-mailbox-switcher`}
|
|
142
|
+
className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
|
|
143
|
+
value={mailboxUid}
|
|
144
|
+
onChange={(e) => {
|
|
145
|
+
window.location.href = `/contacts?mailboxUid=${encodeURIComponent(e.target.value)}`;
|
|
146
|
+
}}
|
|
147
|
+
>
|
|
148
|
+
{mailboxes.map((mb) => (
|
|
149
|
+
<option key={mb.uid} value={mb.uid}>
|
|
150
|
+
{mb.displayName}
|
|
151
|
+
{mb.ownerUserUid ? "" : " (shared)"}
|
|
152
|
+
</option>
|
|
153
|
+
))}
|
|
154
|
+
</select>
|
|
155
|
+
</div>
|
|
156
|
+
)}
|
|
157
|
+
{folderError && <Alert>{folderError}</Alert>}
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
inner = (
|
|
162
|
+
<>
|
|
163
|
+
<aside className="hidden md:flex w-56 shrink-0 bg-surface border-r border-border flex-col p-3 gap-3">
|
|
164
|
+
{sidebarContent("desktop")}
|
|
165
|
+
</aside>
|
|
166
|
+
<Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Mailbox">
|
|
167
|
+
<div className="flex flex-col gap-3">{sidebarContent("mobile")}</div>
|
|
168
|
+
</Drawer>
|
|
169
|
+
<main className="flex-1 min-w-0 flex flex-col">
|
|
170
|
+
{(mailboxes.length > 1 || folderError) && (
|
|
171
|
+
<button
|
|
172
|
+
type="button"
|
|
173
|
+
className="md:hidden m-3 w-9 h-9 flex items-center justify-center rounded-sm text-text-muted hover:bg-surface-alt hover:text-text"
|
|
174
|
+
aria-label="Open mailbox switcher"
|
|
175
|
+
onClick={() => setDrawerOpen(true)}
|
|
176
|
+
>
|
|
177
|
+
<HiOutlineBars3 size={20} aria-hidden="true" />
|
|
178
|
+
</button>
|
|
179
|
+
)}
|
|
180
|
+
<ContactsShellContext.Provider value={contextValue}>{children}</ContactsShellContext.Provider>
|
|
181
|
+
</main>
|
|
182
|
+
</>
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return (
|
|
187
|
+
<AppShell
|
|
188
|
+
active="contacts"
|
|
189
|
+
userUid={userUid}
|
|
190
|
+
authServerUrl={authServerUrl}
|
|
191
|
+
impersonating={impersonating}
|
|
192
|
+
impersonationBaseUrl={impersonationBaseUrl}
|
|
193
|
+
trusted={trusted}
|
|
194
|
+
pluginNav={pluginNav}
|
|
195
|
+
>
|
|
196
|
+
{inner}
|
|
197
|
+
</AppShell>
|
|
198
|
+
);
|
|
199
|
+
}
|