@rapidmx/web-client 0.15.1 → 0.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +381 -373
- package/apps/admin/branding/index.tsx +39 -39
- package/apps/admin/data-requests/index.tsx +482 -480
- package/apps/admin/distribution-lists/new/index.tsx +3 -1
- package/apps/admin/domains/[uid].tsx +166 -164
- package/apps/admin/domains/new/index.tsx +3 -1
- package/apps/admin/escrow-scopes/[uid].tsx +350 -348
- package/apps/admin/escrow-scopes/new/index.tsx +3 -1
- package/apps/admin/index.tsx +129 -124
- package/apps/admin/mailboxes/[uid].tsx +271 -224
- package/apps/admin/mailboxes/new/index.tsx +30 -28
- package/apps/admin/plugins/index.tsx +15 -15
- package/apps/admin/retention-policy/index.tsx +39 -39
- package/apps/admin/signing-certificates/index.tsx +343 -343
- package/apps/admin/transport-rules/new/index.tsx +3 -1
- package/apps/escrow/audit-log/index.tsx +196 -196
- package/apps/escrow/matters/[uid].tsx +621 -621
- package/apps/escrow/matters/new/index.tsx +3 -1
- package/apps/shared/auth/adminAccess.ts +99 -99
- package/apps/shared/components/admin/layout/AdminShell.tsx +381 -378
- package/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.tsx +238 -0
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -152
- package/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.tsx +194 -0
- package/apps/shared/components/admin/settings/BrandingForm.tsx +423 -423
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +119 -119
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +50 -3
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +198 -198
- package/apps/shared/components/admin/settings/PluginsManager.tsx +1545 -1545
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +182 -182
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +288 -288
- package/apps/shared/components/admin/setup/SetupWizard.tsx +446 -444
- package/apps/shared/components/admin/usePagedList.tsx +129 -129
- package/apps/shared/components/calendar/EventEditor.tsx +5 -10
- package/apps/shared/components/calendar/EventFormParts.tsx +16 -47
- package/apps/shared/components/calendar/EventModal.tsx +206 -206
- package/apps/shared/components/calendar/GuestInput.tsx +100 -0
- package/apps/shared/components/calendar/MonthView.tsx +185 -185
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +227 -227
- package/apps/shared/components/calendar/RequestChangeForm.tsx +23 -54
- package/apps/shared/components/calendar/SplitDayView.tsx +144 -144
- package/apps/shared/components/calendar/TimeGridView.tsx +246 -246
- package/apps/shared/components/calendar/allDay.ts +124 -124
- package/apps/shared/components/calendar/eventForm.ts +2 -2
- package/apps/shared/components/calendar/eventFormat.ts +49 -22
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +201 -200
- package/apps/shared/components/contacts/ContactForm.tsx +383 -383
- package/apps/shared/components/contacts/ContactsSidebar.tsx +1 -1
- package/apps/shared/components/contacts/ContactsToolbar.tsx +103 -98
- package/apps/shared/components/contacts/layout/ContactsShell.tsx +218 -216
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +155 -155
- package/apps/shared/components/layout/AppShell.tsx +461 -480
- package/apps/shared/components/layout/FloatingActionButton.tsx +31 -0
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +398 -398
- package/apps/shared/components/layout/MailboxProvisioning.tsx +168 -168
- package/apps/shared/components/layout/ResponsiveToolbar.tsx +315 -315
- package/apps/shared/components/layout/ThemeSwitch.tsx +84 -84
- package/apps/shared/components/layout/UserMenu.tsx +439 -424
- package/apps/shared/components/mail/ConversationList.tsx +323 -323
- package/apps/shared/components/mail/ConversationThreadPane.tsx +613 -491
- package/apps/shared/components/mail/EmptyFolderBar.tsx +41 -0
- package/apps/shared/components/mail/MailSelectionBar.tsx +240 -227
- package/apps/shared/components/mail/MenuButton.tsx +31 -11
- package/apps/shared/components/mail/MessageDetailPane.tsx +1757 -1559
- package/apps/shared/components/mail/PermanentDeleteDialog.tsx +47 -0
- package/apps/shared/components/mail/compose/ComposeContext.tsx +312 -312
- package/apps/shared/components/mail/compose/ComposeToolbar.tsx +422 -422
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1681 -1677
- package/apps/shared/components/mail/compose/RecipientInput.tsx +54 -11
- package/apps/shared/components/mail/compose/RichTextEditor.tsx +147 -147
- package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -60
- package/apps/shared/components/mail/compose/quotedBody.ts +161 -161
- package/apps/shared/components/mail/layout/FolderBadgeChip.tsx +21 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +161 -134
- package/apps/shared/components/mail/layout/SidebarSection.tsx +66 -0
- package/apps/shared/components/mail/reading/MessageMoreMenu.tsx +258 -0
- package/apps/shared/components/mail/reading/MessageSourceDialog.tsx +79 -0
- package/apps/shared/components/mail/reading/PendingMessageCard.tsx +68 -0
- package/apps/shared/components/mail/reading/messageExport.ts +59 -0
- package/apps/shared/components/mail/reading/printMessage.ts +99 -0
- package/apps/shared/components/mail/reading/useMessageActions.ts +443 -0
- package/apps/shared/components/mail/verificationSeals.ts +125 -125
- package/apps/shared/components/rules/RuleBuilder.tsx +311 -311
- package/apps/shared/components/settings/SigningCertificateCard.tsx +344 -344
- package/apps/shared/components/settings/layout/SettingsShell.tsx +257 -254
- package/apps/shared/components/tasks/TasksSidebar.tsx +1 -1
- package/apps/shared/components/tasks/layout/TasksShell.tsx +219 -217
- package/apps/shared/keyboard/GlobalShortcuts.tsx +51 -51
- package/apps/shared/keyboard/ShortcutProvider.tsx +62 -62
- package/apps/shared/keyboard/ShortcutsDialog.tsx +84 -84
- package/apps/shared/keyboard/dispatch.ts +124 -124
- package/apps/shared/keyboard/format.ts +89 -89
- package/apps/shared/keyboard/keymap.ts +114 -114
- package/apps/shared/keyboard/registry.ts +65 -65
- package/apps/shared/keyboard/targets.ts +79 -79
- package/apps/shared/mail/folderCounts.ts +17 -0
- package/apps/shared/mail/folderOfType.ts +49 -0
- package/apps/shared/mail/folderTree.ts +143 -143
- package/apps/shared/mail/listAllPages.ts +39 -39
- package/apps/shared/mail/newMailNotifications.ts +171 -171
- package/apps/shared/mail/outbox/outgoingReplies.ts +192 -0
- package/apps/shared/mail/outbox/sendJob.ts +19 -1
- package/apps/shared/mail/outbox/sendOutcomes.ts +13 -4
- package/apps/shared/mail/permanentDelete.ts +160 -0
- package/apps/shared/mail/primaryMailbox.ts +71 -0
- package/apps/shared/mail/reportNotices.ts +66 -0
- package/apps/shared/mail/senderBlocking.ts +141 -0
- package/apps/shared/mail/useCollapsedSections.ts +146 -0
- package/apps/shared/mail/useMailConnection.ts +205 -203
- package/apps/shared/mail/useMailLiveUpdates.ts +277 -277
- package/apps/shared/mail/useMailboxUpdateAccess.ts +60 -0
- package/apps/shared/mail/useMarkMessageRead.ts +47 -47
- package/apps/shared/mail/useNewMailNotifications.ts +178 -178
- package/apps/shared/mail/usePermanentDelete.tsx +160 -0
- package/apps/shared/navigation/frameContext.tsx +1 -1
- package/apps/shared/navigation/index.ts +43 -0
- package/apps/shared/navigation/pageTitle.ts +19 -0
- package/apps/shared/notifications/store.ts +560 -560
- package/apps/shared/search/LocalIndexLifecycle.tsx +114 -114
- package/apps/shared/search/crossMailboxSearch.ts +169 -0
- package/apps/shared/search/localIndexBuilder.ts +481 -481
- package/apps/shared/signing/enrollmentStorage.ts +33 -33
- package/apps/shared/signing/enrollmentTracker.ts +385 -385
- package/apps/shared/signing/enrollmentView.ts +251 -251
- package/apps/shared/signing/useNow.ts +19 -19
- package/apps/shared/signing/useSigningEnrollmentWatcher.ts +90 -90
- package/apps/shared/styles/app.css +396 -386
- package/apps/www/_shell.tsx +82 -0
- package/apps/www/calendar/index.tsx +581 -571
- package/apps/www/contacts/[uid].tsx +112 -109
- package/apps/www/contacts/index.tsx +14 -3
- package/apps/www/index.tsx +2962 -2479
- package/apps/www/messages/[uid].tsx +139 -135
- package/apps/www/settings/appearance/index.tsx +5 -2
- package/apps/www/settings/auto-reply/index.tsx +136 -133
- package/apps/www/settings/blocked-senders/index.tsx +303 -0
- package/apps/www/settings/encryption/index.tsx +1290 -1287
- package/apps/www/settings/filters/[uid].tsx +179 -176
- package/apps/www/settings/filters/index.tsx +105 -102
- package/apps/www/settings/filters/new/index.tsx +165 -140
- package/apps/www/settings/labels/index.tsx +207 -204
- package/apps/www/settings/privacy/index.tsx +495 -492
- package/apps/www/settings/profile/index.tsx +251 -248
- package/apps/www/settings/read-receipts/index.tsx +150 -147
- package/apps/www/settings/sharing/index.tsx +259 -256
- package/apps/www/settings/signatures/[uid].tsx +175 -172
- package/apps/www/settings/signatures/index.tsx +91 -88
- package/apps/www/settings/signatures/new/index.tsx +138 -135
- package/apps/www/tasks/index.tsx +654 -649
- package/dist/apps/admin/data-requests/index.js +1 -1
- package/dist/apps/admin/distribution-lists/new/index.js +3 -1
- package/dist/apps/admin/domains/[uid].js +3 -1
- package/dist/apps/admin/domains/new/index.js +3 -1
- package/dist/apps/admin/escrow-scopes/[uid].js +3 -1
- package/dist/apps/admin/escrow-scopes/new/index.js +3 -1
- package/dist/apps/admin/index.js +5 -2
- package/dist/apps/admin/mailboxes/[uid].js +15 -3
- package/dist/apps/admin/mailboxes/new/index.js +3 -1
- package/dist/apps/admin/transport-rules/new/index.js +3 -1
- package/dist/apps/escrow/matters/new/index.js +3 -1
- package/dist/apps/shared/components/admin/layout/AdminShell.js +6 -3
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.d.ts +35 -0
- package/dist/apps/shared/components/admin/mailboxes/EraseLeftoverDataDialog.js +115 -0
- package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.d.ts +16 -0
- package/dist/apps/shared/components/admin/mailboxes/LeftoverMailboxesSection.js +92 -0
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +3 -3
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +25 -3
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +3 -1
- package/dist/apps/shared/components/calendar/EventEditor.js +5 -10
- package/dist/apps/shared/components/calendar/EventFormParts.d.ts +3 -2
- package/dist/apps/shared/components/calendar/EventFormParts.js +5 -16
- package/dist/apps/shared/components/calendar/GuestInput.d.ts +45 -0
- package/dist/apps/shared/components/calendar/GuestInput.js +30 -0
- package/dist/apps/shared/components/calendar/RequestChangeForm.js +11 -22
- package/dist/apps/shared/components/calendar/eventForm.d.ts +2 -2
- package/dist/apps/shared/components/calendar/eventFormat.d.ts +21 -8
- package/dist/apps/shared/components/calendar/eventFormat.js +50 -23
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +5 -4
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +1 -1
- package/dist/apps/shared/components/contacts/ContactsToolbar.d.ts +3 -1
- package/dist/apps/shared/components/contacts/ContactsToolbar.js +4 -2
- package/dist/apps/shared/components/contacts/layout/ContactsShell.js +7 -5
- package/dist/apps/shared/components/layout/AppShell.d.ts +8 -11
- package/dist/apps/shared/components/layout/AppShell.js +24 -33
- package/dist/apps/shared/components/layout/FloatingActionButton.d.ts +13 -0
- package/dist/apps/shared/components/layout/FloatingActionButton.js +9 -0
- package/dist/apps/shared/components/layout/UserMenu.d.ts +4 -1
- package/dist/apps/shared/components/layout/UserMenu.js +6 -5
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +127 -22
- package/dist/apps/shared/components/mail/EmptyFolderBar.d.ts +18 -0
- package/dist/apps/shared/components/mail/EmptyFolderBar.js +10 -0
- package/dist/apps/shared/components/mail/MailSelectionBar.d.ts +14 -4
- package/dist/apps/shared/components/mail/MailSelectionBar.js +11 -13
- package/dist/apps/shared/components/mail/MenuButton.d.ts +9 -2
- package/dist/apps/shared/components/mail/MenuButton.js +15 -11
- package/dist/apps/shared/components/mail/MessageDetailPane.d.ts +5 -0
- package/dist/apps/shared/components/mail/MessageDetailPane.js +147 -7
- package/dist/apps/shared/components/mail/PermanentDeleteDialog.d.ts +19 -0
- package/dist/apps/shared/components/mail/PermanentDeleteDialog.js +11 -0
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +8 -4
- package/dist/apps/shared/components/mail/compose/RecipientInput.d.ts +21 -1
- package/dist/apps/shared/components/mail/compose/RecipientInput.js +18 -10
- package/dist/apps/shared/components/mail/layout/FolderBadgeChip.d.ts +6 -0
- package/dist/apps/shared/components/mail/layout/FolderBadgeChip.js +9 -0
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +16 -7
- package/dist/apps/shared/components/mail/layout/MailShell.js +78 -65
- package/dist/apps/shared/components/mail/layout/SidebarSection.d.ts +23 -0
- package/dist/apps/shared/components/mail/layout/SidebarSection.js +16 -0
- package/dist/apps/shared/components/mail/reading/MessageMoreMenu.d.ts +56 -0
- package/dist/apps/shared/components/mail/reading/MessageMoreMenu.js +153 -0
- package/dist/apps/shared/components/mail/reading/MessageSourceDialog.d.ts +27 -0
- package/dist/apps/shared/components/mail/reading/MessageSourceDialog.js +27 -0
- package/dist/apps/shared/components/mail/reading/PendingMessageCard.d.ts +14 -0
- package/dist/apps/shared/components/mail/reading/PendingMessageCard.js +16 -0
- package/dist/apps/shared/components/mail/reading/messageExport.d.ts +19 -0
- package/dist/apps/shared/components/mail/reading/messageExport.js +51 -0
- package/dist/apps/shared/components/mail/reading/printMessage.d.ts +30 -0
- package/dist/apps/shared/components/mail/reading/printMessage.js +70 -0
- package/dist/apps/shared/components/mail/reading/useMessageActions.d.ts +57 -0
- package/dist/apps/shared/components/mail/reading/useMessageActions.js +366 -0
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +10 -7
- package/dist/apps/shared/components/tasks/TasksSidebar.js +1 -1
- package/dist/apps/shared/components/tasks/layout/TasksShell.js +7 -5
- package/dist/apps/shared/keyboard/GlobalShortcuts.js +1 -1
- package/dist/apps/shared/mail/folderCounts.d.ts +10 -0
- package/dist/apps/shared/mail/folderCounts.js +12 -0
- package/dist/apps/shared/mail/folderOfType.d.ts +13 -0
- package/dist/apps/shared/mail/folderOfType.js +40 -0
- package/dist/apps/shared/mail/outbox/outgoingReplies.d.ts +80 -0
- package/dist/apps/shared/mail/outbox/outgoingReplies.js +131 -0
- package/dist/apps/shared/mail/outbox/sendJob.d.ts +5 -1
- package/dist/apps/shared/mail/outbox/sendJob.js +14 -1
- package/dist/apps/shared/mail/outbox/sendOutcomes.js +13 -4
- package/dist/apps/shared/mail/permanentDelete.d.ts +62 -0
- package/dist/apps/shared/mail/permanentDelete.js +127 -0
- package/dist/apps/shared/mail/primaryMailbox.d.ts +29 -0
- package/dist/apps/shared/mail/primaryMailbox.js +61 -0
- package/dist/apps/shared/mail/reportNotices.d.ts +21 -0
- package/dist/apps/shared/mail/reportNotices.js +47 -0
- package/dist/apps/shared/mail/senderBlocking.d.ts +26 -0
- package/dist/apps/shared/mail/senderBlocking.js +92 -0
- package/dist/apps/shared/mail/useCollapsedSections.d.ts +32 -0
- package/dist/apps/shared/mail/useCollapsedSections.js +110 -0
- package/dist/apps/shared/mail/useMailConnection.js +3 -1
- package/dist/apps/shared/mail/useMailboxUpdateAccess.d.ts +11 -0
- package/dist/apps/shared/mail/useMailboxUpdateAccess.js +52 -0
- package/dist/apps/shared/mail/usePermanentDelete.d.ts +35 -0
- package/dist/apps/shared/mail/usePermanentDelete.js +96 -0
- package/dist/apps/shared/navigation/frameContext.d.ts +1 -1
- package/dist/apps/shared/navigation/index.d.ts +16 -0
- package/dist/apps/shared/navigation/index.js +34 -0
- package/dist/apps/shared/navigation/pageTitle.d.ts +11 -0
- package/dist/apps/shared/navigation/pageTitle.js +12 -0
- package/dist/apps/shared/search/crossMailboxSearch.d.ts +72 -0
- package/dist/apps/shared/search/crossMailboxSearch.js +136 -0
- package/dist/apps/shared/styles/app.css +396 -386
- package/dist/apps/www/_shell.d.ts +26 -0
- package/dist/apps/www/_shell.js +31 -0
- package/dist/apps/www/calendar/index.d.ts +7 -2
- package/dist/apps/www/calendar/index.js +7 -4
- package/dist/apps/www/contacts/[uid].d.ts +14 -3
- package/dist/apps/www/contacts/[uid].js +5 -3
- package/dist/apps/www/contacts/index.d.ts +7 -2
- package/dist/apps/www/contacts/index.js +8 -4
- package/dist/apps/www/index.d.ts +7 -2
- package/dist/apps/www/index.js +542 -207
- package/dist/apps/www/messages/[uid].d.ts +14 -3
- package/dist/apps/www/messages/[uid].js +7 -5
- package/dist/apps/www/settings/appearance/index.d.ts +8 -2
- package/dist/apps/www/settings/appearance/index.js +4 -2
- package/dist/apps/www/settings/auto-reply/index.d.ts +7 -2
- package/dist/apps/www/settings/auto-reply/index.js +4 -2
- package/dist/apps/www/settings/blocked-senders/index.d.ts +9 -0
- package/dist/apps/www/settings/blocked-senders/index.js +134 -0
- package/dist/apps/www/settings/encryption/index.d.ts +7 -2
- package/dist/apps/www/settings/encryption/index.js +4 -2
- package/dist/apps/www/settings/filters/[uid].d.ts +7 -2
- package/dist/apps/www/settings/filters/[uid].js +4 -2
- package/dist/apps/www/settings/filters/index.d.ts +7 -2
- package/dist/apps/www/settings/filters/index.js +4 -2
- package/dist/apps/www/settings/filters/new/index.d.ts +7 -2
- package/dist/apps/www/settings/filters/new/index.js +28 -5
- package/dist/apps/www/settings/labels/index.d.ts +7 -2
- package/dist/apps/www/settings/labels/index.js +4 -2
- package/dist/apps/www/settings/privacy/index.d.ts +7 -2
- package/dist/apps/www/settings/privacy/index.js +4 -2
- package/dist/apps/www/settings/profile/index.d.ts +7 -2
- package/dist/apps/www/settings/profile/index.js +4 -2
- package/dist/apps/www/settings/read-receipts/index.d.ts +7 -2
- package/dist/apps/www/settings/read-receipts/index.js +4 -2
- package/dist/apps/www/settings/sharing/index.d.ts +7 -2
- package/dist/apps/www/settings/sharing/index.js +4 -2
- package/dist/apps/www/settings/signatures/[uid].d.ts +7 -2
- package/dist/apps/www/settings/signatures/[uid].js +4 -2
- package/dist/apps/www/settings/signatures/index.d.ts +7 -2
- package/dist/apps/www/settings/signatures/index.js +4 -2
- package/dist/apps/www/settings/signatures/new/index.d.ts +7 -2
- package/dist/apps/www/settings/signatures/new/index.js +5 -3
- package/dist/apps/www/tasks/index.d.ts +7 -2
- package/dist/apps/www/tasks/index.js +5 -3
- package/package.json +4 -2
- package/apps/shared/navigation/AppRouter.tsx +0 -300
- package/apps/shared/navigation/idle.ts +0 -45
- package/apps/shared/navigation/routerContext.tsx +0 -83
- package/apps/shared/navigation/routes.ts +0 -72
- package/apps/www/_routedPage.tsx +0 -24
- package/apps/www/_routes.ts +0 -37
- package/dist/apps/shared/navigation/AppRouter.d.ts +0 -52
- package/dist/apps/shared/navigation/AppRouter.js +0 -242
- package/dist/apps/shared/navigation/idle.d.ts +0 -14
- package/dist/apps/shared/navigation/idle.js +0 -43
- package/dist/apps/shared/navigation/routerContext.d.ts +0 -37
- package/dist/apps/shared/navigation/routerContext.js +0 -56
- package/dist/apps/shared/navigation/routes.d.ts +0 -32
- package/dist/apps/shared/navigation/routes.js +0 -37
- package/dist/apps/www/_routedPage.d.ts +0 -12
- package/dist/apps/www/_routedPage.js +0 -19
- package/dist/apps/www/_routes.d.ts +0 -11
- package/dist/apps/www/_routes.js +0 -31
|
@@ -1,217 +1,219 @@
|
|
|
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 {
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
export
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
/** The selected
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
const [
|
|
58
|
-
const [
|
|
59
|
-
const [
|
|
60
|
-
const [
|
|
61
|
-
const [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
//
|
|
124
|
-
//
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
{
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
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 { useLocation } from "@rapidrest/react/client";
|
|
14
|
+
import { useNavigate } from "../../../navigation/index.js";
|
|
15
|
+
import MailboxProvisioning from "../../layout/MailboxProvisioning.js";
|
|
16
|
+
import { orderMailboxes, primaryMailboxUid } from "../../../mail/primaryMailbox.js";
|
|
17
|
+
|
|
18
|
+
export type TasksShellProps = Omit<AppShellProps, "active">;
|
|
19
|
+
|
|
20
|
+
export interface TasksShellContextValue {
|
|
21
|
+
/** The mailbox currently selected (`?mailboxUid=`, or the caller's first accessible mailbox). */
|
|
22
|
+
mailboxUid?: string;
|
|
23
|
+
/** The selected mailbox's single `tasks`-type folder. */
|
|
24
|
+
folderUid?: string;
|
|
25
|
+
mailboxes: Mailbox[];
|
|
26
|
+
/** The caller's own uid — exposed here (rather than only as `AppShell`'s prop) so the page content
|
|
27
|
+
* can compute "assigned to me" without needing it threaded through separately. */
|
|
28
|
+
userUid?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const TasksShellContext = createContext<TasksShellContextValue>({ mailboxes: [] });
|
|
32
|
+
|
|
33
|
+
/** Reads the mailbox/folder Tasks is currently showing, as resolved by the enclosing `TasksShell`. */
|
|
34
|
+
export function useTasksShell(): TasksShellContextValue {
|
|
35
|
+
return useContext(TasksShellContext);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
type Status = "checking" | "error" | "ready";
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* The Tasks app's shell — structurally identical to `ContactsShell` (a mailbox has exactly one
|
|
42
|
+
* well-known `tasks` folder, guaranteed to exist by `BaseMailboxRoute.create()`'s eager provisioning
|
|
43
|
+
* in `@rapidmx/restapi`), just bound to a different folder type. Kept as its own small component
|
|
44
|
+
* (rather than a single generic "SingleFolderShell" parameterized by type) so each app's sidebar can
|
|
45
|
+
* grow its own app-specific controls later without threading extra props through a shared one.
|
|
46
|
+
*/
|
|
47
|
+
export default function TasksShell({
|
|
48
|
+
userUid,
|
|
49
|
+
authServerUrl,
|
|
50
|
+
impersonating,
|
|
51
|
+
impersonationBaseUrl,
|
|
52
|
+
trusted,
|
|
53
|
+
trustedRoles,
|
|
54
|
+
pluginNav,
|
|
55
|
+
children,
|
|
56
|
+
}: PropsWithChildren<TasksShellProps>) {
|
|
57
|
+
const [status, setStatus] = useState<Status>("checking");
|
|
58
|
+
const [error, setError] = useState<string | null>(null);
|
|
59
|
+
const [mailboxes, setMailboxes] = useState<Mailbox[]>([]);
|
|
60
|
+
const [folders, setFolders] = useState<Folder[]>([]);
|
|
61
|
+
const [folderError, setFolderError] = useState<string | null>(null);
|
|
62
|
+
const [requestedMailboxUid, setRequestedMailboxUid] = useState<string | null>(null);
|
|
63
|
+
const [drawerOpen, setDrawerOpen] = useState(false);
|
|
64
|
+
|
|
65
|
+
// Read from the router's location, so a mailbox change (a link, or `navigate()`) takes effect without a page load - and in an
|
|
66
|
+
// effect, not during render, so the server render and the hydrating render agree.
|
|
67
|
+
const { search } = useLocation();
|
|
68
|
+
const navigate = useNavigate();
|
|
69
|
+
useEffect(() => {
|
|
70
|
+
setRequestedMailboxUid(new URLSearchParams(search).get("mailboxUid"));
|
|
71
|
+
}, [search]);
|
|
72
|
+
// Choosing a folder (or mailbox) changes the URL without a page load now, so the drawer that held the choice - which used to go
|
|
73
|
+
// with the page - is closed here.
|
|
74
|
+
useEffect(() => {
|
|
75
|
+
setDrawerOpen(false);
|
|
76
|
+
}, [search]);
|
|
77
|
+
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
if (!userUid) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
listMailboxes({ limit: 100 })
|
|
83
|
+
.then((result) => {
|
|
84
|
+
setMailboxes(orderMailboxes(result, userUid));
|
|
85
|
+
setStatus("ready");
|
|
86
|
+
})
|
|
87
|
+
.catch((err) => {
|
|
88
|
+
setError(err instanceof ApiRequestError ? err.message : "Could not load your mailboxes.");
|
|
89
|
+
setStatus("error");
|
|
90
|
+
});
|
|
91
|
+
}, [userUid]);
|
|
92
|
+
|
|
93
|
+
const mailboxUid: string | undefined =
|
|
94
|
+
(requestedMailboxUid && mailboxes.some((mb) => mb.uid === requestedMailboxUid) ? requestedMailboxUid : undefined) ??
|
|
95
|
+
primaryMailboxUid(mailboxes, userUid);
|
|
96
|
+
|
|
97
|
+
useEffect(() => {
|
|
98
|
+
if (!mailboxUid) {
|
|
99
|
+
setFolders([]);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
setFolderError(null);
|
|
103
|
+
listFolders(mailboxUid)
|
|
104
|
+
.then(setFolders)
|
|
105
|
+
.catch((err) => setFolderError(err instanceof ApiRequestError ? err.message : "Could not load this mailbox's tasks folder."));
|
|
106
|
+
}, [mailboxUid]);
|
|
107
|
+
|
|
108
|
+
const folderUid: string | undefined = folders.find((f) => f.type === "tasks")?.uid;
|
|
109
|
+
|
|
110
|
+
const contextValue = useMemo<TasksShellContextValue>(
|
|
111
|
+
() => ({ mailboxUid, folderUid, mailboxes, userUid }),
|
|
112
|
+
[mailboxUid, folderUid, mailboxes, userUid],
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
// A full-screen takeover, not nested inside the rest of the app's chrome — there's nothing else
|
|
116
|
+
// for a mailbox-less caller to do here yet, so the icon rail/header don't render at all.
|
|
117
|
+
if (userUid && status === "ready" && !mailboxUid) {
|
|
118
|
+
return <MailboxProvisioning />;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
let inner: ReactNode = null;
|
|
122
|
+
if (userUid && status === "checking") {
|
|
123
|
+
// Renders immediately (no network round trip needed) so switching into Tasks never shows a
|
|
124
|
+
// blank pane while `listMailboxes()` is in flight — the real sidebar (My Day/Important/Planned/
|
|
125
|
+
// lists) lives in `apps/www/tasks/index.tsx`'s own content, so this mimics its rough shape rather
|
|
126
|
+
// than the (minimal, mailbox-switcher-only) shape of this shell's own sidebar.
|
|
127
|
+
inner = (
|
|
128
|
+
<aside className="w-56 shrink-0 bg-surface border-r border-border flex flex-col p-3 gap-4">
|
|
129
|
+
<Skeleton height="h-9" />
|
|
130
|
+
<SkeletonList count={5} />
|
|
131
|
+
</aside>
|
|
132
|
+
);
|
|
133
|
+
} else if (userUid && status === "error") {
|
|
134
|
+
inner = (
|
|
135
|
+
<div className="flex-1 flex items-center justify-center p-8">
|
|
136
|
+
<div className="w-full max-w-md">
|
|
137
|
+
<Alert>{error}</Alert>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
);
|
|
141
|
+
} else if (userUid && status === "ready") {
|
|
142
|
+
// A function, not a plain JSX constant — see MailShell/ContactsShell/CalendarShell's identical
|
|
143
|
+
// comment: it's rendered twice (desktop `<aside>` + mobile `Drawer`), possibly simultaneously
|
|
144
|
+
// mounted, so the `<select>`'s `id`/its `<label>`'s `htmlFor` need a distinct value per instance.
|
|
145
|
+
const sidebarContent = (idPrefix: string) => (
|
|
146
|
+
<>
|
|
147
|
+
{mailboxes.length > 1 && (
|
|
148
|
+
<div>
|
|
149
|
+
<label
|
|
150
|
+
className="block text-xs font-bold uppercase tracking-wide text-text-muted mb-1"
|
|
151
|
+
htmlFor={`${idPrefix}-tasks-mailbox-switcher`}
|
|
152
|
+
>
|
|
153
|
+
Mailbox
|
|
154
|
+
</label>
|
|
155
|
+
<select
|
|
156
|
+
id={`${idPrefix}-tasks-mailbox-switcher`}
|
|
157
|
+
className="w-full text-sm border border-border rounded-sm py-1.5 px-2 bg-surface"
|
|
158
|
+
value={mailboxUid}
|
|
159
|
+
onChange={(e) => {
|
|
160
|
+
navigate(`/tasks?mailboxUid=${encodeURIComponent(e.target.value)}`);
|
|
161
|
+
}}
|
|
162
|
+
>
|
|
163
|
+
{mailboxes.map((mb) => (
|
|
164
|
+
<option key={mb.uid} value={mb.uid}>
|
|
165
|
+
{mb.displayName}
|
|
166
|
+
{mb.ownerUserUid ? "" : " (shared)"}
|
|
167
|
+
</option>
|
|
168
|
+
))}
|
|
169
|
+
</select>
|
|
170
|
+
</div>
|
|
171
|
+
)}
|
|
172
|
+
{folderError && <Alert>{folderError}</Alert>}
|
|
173
|
+
</>
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
// With a single mailbox and no error this column would be empty: no 224 px of nothing beside the tasks' own menu.
|
|
177
|
+
const hasSidebar = mailboxes.length > 1 || !!folderError;
|
|
178
|
+
inner = (
|
|
179
|
+
<>
|
|
180
|
+
{hasSidebar && (
|
|
181
|
+
<aside className="hidden lg:flex w-56 shrink-0 bg-surface border-r border-border flex-col p-3 gap-3">
|
|
182
|
+
{sidebarContent("desktop")}
|
|
183
|
+
</aside>
|
|
184
|
+
)}
|
|
185
|
+
<Drawer open={drawerOpen} onClose={() => setDrawerOpen(false)} title="Mailbox" fullScreen>
|
|
186
|
+
<div className="flex flex-col gap-3">{sidebarContent("mobile")}</div>
|
|
187
|
+
</Drawer>
|
|
188
|
+
<main className="flex-1 min-w-0 flex flex-col">
|
|
189
|
+
{hasSidebar && (
|
|
190
|
+
<button
|
|
191
|
+
type="button"
|
|
192
|
+
className="lg:hidden m-3 w-9 h-9 flex items-center justify-center rounded-sm text-text-muted hover:bg-surface-alt hover:text-text"
|
|
193
|
+
aria-label="Open mailbox switcher"
|
|
194
|
+
onClick={() => setDrawerOpen(true)}
|
|
195
|
+
>
|
|
196
|
+
<HiOutlineBars3 size={20} aria-hidden="true" />
|
|
197
|
+
</button>
|
|
198
|
+
)}
|
|
199
|
+
<TasksShellContext.Provider value={contextValue}>{children}</TasksShellContext.Provider>
|
|
200
|
+
</main>
|
|
201
|
+
</>
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return (
|
|
206
|
+
<AppShell
|
|
207
|
+
active="tasks"
|
|
208
|
+
userUid={userUid}
|
|
209
|
+
authServerUrl={authServerUrl}
|
|
210
|
+
impersonating={impersonating}
|
|
211
|
+
impersonationBaseUrl={impersonationBaseUrl}
|
|
212
|
+
trusted={trusted}
|
|
213
|
+
trustedRoles={trustedRoles}
|
|
214
|
+
pluginNav={pluginNav}
|
|
215
|
+
>
|
|
216
|
+
{inner}
|
|
217
|
+
</AppShell>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
-
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
-
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
-
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
-
import { accountUrlOf } from "../auth/accountUrl.js";
|
|
6
|
-
import { APP_HREFS, SETTINGS_HREF, isSettingsPath } from "../navigation/appHrefs.js";
|
|
7
|
-
import { useNavigate } from "../navigation/
|
|
8
|
-
import { SHORTCUTS } from "./keymap.js";
|
|
9
|
-
import { useShortcut } from "./useShortcut.js";
|
|
10
|
-
|
|
11
|
-
export interface GlobalShortcutsProps {
|
|
12
|
-
/** auth-server's base URL - "Go to Account" is offered only when it is set. */
|
|
13
|
-
authServerUrl?: string;
|
|
14
|
-
/** Opens the keyboard shortcuts dialog, or closes it if it is open. */
|
|
15
|
-
onToggleHelp: () => void;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* The shortcuts that work in every view: the "Go to ..." navigation set and the keyboard help. Mounted once by `AppChrome`, next to the
|
|
20
|
-
* `ShortcutProvider`, so it works from Settings and every app alike. Renders nothing.
|
|
21
|
-
*
|
|
22
|
-
* In-app places go through the client-side router (`useNavigate()`); Account is another origin, so it is a plain navigation. Asking for the
|
|
23
|
-
* page you are already on does nothing - but the key is still taken, so the browser doesn't act on it either.
|
|
24
|
-
*/
|
|
25
|
-
export function GlobalShortcuts({ authServerUrl, onToggleHelp }: GlobalShortcutsProps) {
|
|
26
|
-
const navigate = useNavigate();
|
|
27
|
-
const accountUrl = accountUrlOf(authServerUrl);
|
|
28
|
-
|
|
29
|
-
/** A handler that goes to `href` unless the address bar's path says it is already there. */
|
|
30
|
-
const goTo = (href: string, isHere: (pathname: string) => boolean) => () => {
|
|
31
|
-
if (!isHere(window.location.pathname)) {
|
|
32
|
-
navigate(href);
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
const isPath = (path: string) => (pathname: string) => pathname === path;
|
|
36
|
-
|
|
37
|
-
useShortcut(SHORTCUTS.global.mail, goTo(APP_HREFS.mail, isPath(APP_HREFS.mail)));
|
|
38
|
-
useShortcut(SHORTCUTS.global.calendar, goTo(APP_HREFS.calendar, isPath(APP_HREFS.calendar)));
|
|
39
|
-
useShortcut(SHORTCUTS.global.contacts, goTo(APP_HREFS.contacts, isPath(APP_HREFS.contacts)));
|
|
40
|
-
useShortcut(SHORTCUTS.global.tasks, goTo(APP_HREFS.tasks, isPath(APP_HREFS.tasks)));
|
|
41
|
-
useShortcut(SHORTCUTS.global.settings, goTo(SETTINGS_HREF, isSettingsPath));
|
|
42
|
-
useShortcut(
|
|
43
|
-
SHORTCUTS.global.account,
|
|
44
|
-
() => {
|
|
45
|
-
window.location.href = accountUrl!;
|
|
46
|
-
},
|
|
47
|
-
{ enabled: !!accountUrl },
|
|
48
|
-
);
|
|
49
|
-
useShortcut(SHORTCUTS.global.help, onToggleHelp);
|
|
50
|
-
return null;
|
|
51
|
-
}
|
|
1
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
2
|
+
// Copyright (C) 2026 Jean-Philippe Steinmetz
|
|
3
|
+
// SPDX-License-Identifier: MPL-2.0
|
|
4
|
+
///////////////////////////////////////////////////////////////////////////////
|
|
5
|
+
import { accountUrlOf } from "../auth/accountUrl.js";
|
|
6
|
+
import { APP_HREFS, SETTINGS_HREF, isSettingsPath } from "../navigation/appHrefs.js";
|
|
7
|
+
import { useNavigate } from "../navigation/index.js";
|
|
8
|
+
import { SHORTCUTS } from "./keymap.js";
|
|
9
|
+
import { useShortcut } from "./useShortcut.js";
|
|
10
|
+
|
|
11
|
+
export interface GlobalShortcutsProps {
|
|
12
|
+
/** auth-server's base URL - "Go to Account" is offered only when it is set. */
|
|
13
|
+
authServerUrl?: string;
|
|
14
|
+
/** Opens the keyboard shortcuts dialog, or closes it if it is open. */
|
|
15
|
+
onToggleHelp: () => void;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The shortcuts that work in every view: the "Go to ..." navigation set and the keyboard help. Mounted once by `AppChrome`, next to the
|
|
20
|
+
* `ShortcutProvider`, so it works from Settings and every app alike. Renders nothing.
|
|
21
|
+
*
|
|
22
|
+
* In-app places go through the client-side router (`useNavigate()`); Account is another origin, so it is a plain navigation. Asking for the
|
|
23
|
+
* page you are already on does nothing - but the key is still taken, so the browser doesn't act on it either.
|
|
24
|
+
*/
|
|
25
|
+
export function GlobalShortcuts({ authServerUrl, onToggleHelp }: GlobalShortcutsProps) {
|
|
26
|
+
const navigate = useNavigate();
|
|
27
|
+
const accountUrl = accountUrlOf(authServerUrl);
|
|
28
|
+
|
|
29
|
+
/** A handler that goes to `href` unless the address bar's path says it is already there. */
|
|
30
|
+
const goTo = (href: string, isHere: (pathname: string) => boolean) => () => {
|
|
31
|
+
if (!isHere(window.location.pathname)) {
|
|
32
|
+
navigate(href);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
const isPath = (path: string) => (pathname: string) => pathname === path;
|
|
36
|
+
|
|
37
|
+
useShortcut(SHORTCUTS.global.mail, goTo(APP_HREFS.mail, isPath(APP_HREFS.mail)));
|
|
38
|
+
useShortcut(SHORTCUTS.global.calendar, goTo(APP_HREFS.calendar, isPath(APP_HREFS.calendar)));
|
|
39
|
+
useShortcut(SHORTCUTS.global.contacts, goTo(APP_HREFS.contacts, isPath(APP_HREFS.contacts)));
|
|
40
|
+
useShortcut(SHORTCUTS.global.tasks, goTo(APP_HREFS.tasks, isPath(APP_HREFS.tasks)));
|
|
41
|
+
useShortcut(SHORTCUTS.global.settings, goTo(SETTINGS_HREF, isSettingsPath));
|
|
42
|
+
useShortcut(
|
|
43
|
+
SHORTCUTS.global.account,
|
|
44
|
+
() => {
|
|
45
|
+
window.location.href = accountUrl!;
|
|
46
|
+
},
|
|
47
|
+
{ enabled: !!accountUrl },
|
|
48
|
+
);
|
|
49
|
+
useShortcut(SHORTCUTS.global.help, onToggleHelp);
|
|
50
|
+
return null;
|
|
51
|
+
}
|