@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.
- package/apps/admin/audit-log/index.tsx +35 -8
- package/apps/admin/branding/index.tsx +39 -404
- package/apps/admin/data-requests/index.tsx +480 -485
- package/apps/admin/distribution-lists/[uid].tsx +19 -1
- package/apps/admin/domains/[uid].tsx +92 -259
- package/apps/admin/encryption-policy/index.tsx +19 -0
- package/apps/admin/escrow-scopes/[uid].tsx +348 -237
- package/apps/admin/escrow-scopes/new/index.tsx +8 -2
- package/apps/admin/index.tsx +118 -82
- package/apps/admin/ingest-queue/index.tsx +44 -5
- package/apps/admin/mailbox-policy/index.tsx +19 -0
- package/apps/admin/mailboxes/[uid].tsx +211 -184
- package/apps/admin/mailboxes/new/index.tsx +28 -291
- package/apps/admin/plugins/index.tsx +15 -0
- package/apps/admin/quarantine/index.tsx +46 -14
- package/apps/admin/retention-policy/index.tsx +39 -132
- package/apps/admin/setup/index.tsx +15 -0
- package/apps/admin/transport-rules/[uid].tsx +30 -1
- package/apps/admin/transport-rules/_transportRuleConfig.tsx +38 -2
- package/apps/admin/transport-rules/index.tsx +24 -6
- package/apps/admin/transport-rules/new/index.tsx +30 -1
- package/apps/escrow/_layout.tsx +2 -3
- package/apps/escrow/audit-log/index.tsx +196 -168
- package/apps/escrow/matters/[uid].tsx +621 -521
- package/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.tsx +22 -1
- package/apps/shared/components/admin/layout/AdminShell.tsx +251 -210
- package/apps/shared/components/admin/mailboxes/EscrowScopeCard.tsx +152 -0
- package/apps/shared/components/admin/mailboxes/ResourceSettingsCard.tsx +3 -3
- package/apps/shared/components/admin/mailboxes/ShareAccessCard.tsx +55 -11
- package/apps/shared/components/admin/settings/BrandingForm.tsx +385 -0
- package/apps/shared/components/admin/settings/DomainDnsSetup.tsx +187 -0
- package/apps/shared/components/admin/settings/EncryptionPolicyForm.tsx +112 -0
- package/apps/shared/components/admin/settings/LoadedSettingsForm.tsx +34 -0
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +308 -0
- package/apps/shared/components/admin/settings/MailboxPolicyForm.tsx +152 -0
- package/apps/shared/components/admin/settings/PluginsManager.tsx +1235 -0
- package/apps/shared/components/admin/settings/RetentionPolicyForm.tsx +174 -0
- package/apps/shared/components/admin/setup/EscrowSetupStep.tsx +290 -0
- package/apps/shared/components/admin/setup/SetupWizard.tsx +416 -0
- package/apps/shared/components/admin/signOut.ts +79 -0
- package/apps/shared/components/admin/usePagedList.tsx +129 -0
- package/apps/shared/components/calendar/CalendarListSidebar.tsx +120 -76
- package/apps/shared/components/calendar/EventModal.tsx +717 -513
- package/apps/shared/components/calendar/MonthView.tsx +173 -139
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +222 -180
- package/apps/shared/components/calendar/SplitDayView.tsx +143 -137
- package/apps/shared/components/calendar/TimeGridView.tsx +244 -198
- package/apps/shared/components/calendar/allDay.ts +124 -0
- package/apps/shared/components/calendar/layout/CalendarShell.tsx +80 -99
- package/apps/shared/components/contacts/ContactDetailPane.tsx +100 -21
- package/apps/shared/components/contacts/ContactForm.tsx +377 -314
- package/apps/shared/components/contacts/ContactsSidebar.tsx +6 -2
- package/apps/shared/components/contacts/KeyChangeReview.tsx +192 -0
- package/apps/shared/components/contacts/contactKeys.ts +78 -0
- package/apps/shared/components/escrow/layout/EscrowShell.tsx +148 -134
- package/apps/shared/components/layout/AppShell.tsx +270 -169
- package/apps/shared/components/layout/BrandingChrome.tsx +48 -10
- package/apps/shared/components/layout/KeyEnrollmentGate.tsx +150 -26
- package/apps/shared/components/layout/MailboxProvisioning.tsx +19 -3
- package/apps/shared/components/layout/RecoveryCodeUnlock.tsx +350 -0
- package/apps/shared/components/layout/UnlockPromptProvider.tsx +257 -0
- package/apps/shared/components/mail/ConversationThreadPane.tsx +216 -181
- package/apps/shared/components/mail/MessageDetailPane.tsx +799 -76
- package/apps/shared/components/mail/compose/ComposeContext.tsx +26 -16
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +1652 -765
- package/apps/shared/components/mail/compose/composeFlushRegistry.ts +60 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +418 -302
- package/apps/shared/components/mail/pinnedSigners.ts +124 -0
- package/apps/shared/components/mail/verificationSeals.ts +125 -0
- package/apps/shared/components/mail/writableMailboxes.ts +101 -0
- package/apps/shared/components/rules/RuleBuilder.tsx +311 -276
- package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
- package/apps/shared/mail/findWellKnownFolderUid.ts +13 -0
- package/apps/shared/mail/listAllPages.ts +39 -0
- package/apps/shared/search/LocalIndexLifecycle.tsx +98 -0
- package/apps/shared/search/localIndexBlockCipher.ts +83 -0
- package/apps/shared/search/localIndexBuilder.ts +481 -0
- package/apps/shared/search/localIndexKey.ts +27 -0
- package/apps/shared/search/localIndexRpcClient.ts +316 -0
- package/apps/shared/search/localIndexSchema.ts +236 -0
- package/apps/shared/search/localIndexSizePreference.ts +88 -0
- package/apps/shared/search/localIndexStorage.ts +98 -0
- package/apps/shared/search/localIndexVFS.ts +266 -0
- package/apps/shared/search/localIndexWorker.ts +926 -0
- package/apps/shared/search/searchTier2.ts +79 -0
- package/apps/shared/search/wa-sqlite-shims.d.ts +44 -0
- package/apps/www/calendar/index.tsx +438 -407
- package/apps/www/contacts/[uid].tsx +21 -2
- package/apps/www/contacts/index.tsx +148 -17
- package/apps/www/index.tsx +1314 -486
- package/apps/www/messages/[uid].tsx +23 -7
- package/apps/www/settings/auto-reply/index.tsx +134 -129
- package/apps/www/settings/booking-types/[uid].tsx +306 -300
- package/apps/www/settings/encryption/index.tsx +800 -215
- package/apps/www/settings/filters/[uid].tsx +171 -155
- package/apps/www/settings/filters/new/index.tsx +8 -1
- package/apps/www/settings/focused-inbox/index.tsx +150 -148
- package/apps/www/settings/privacy/index.tsx +494 -436
- package/apps/www/settings/read-receipts/index.tsx +148 -125
- package/apps/www/settings/sharing/index.tsx +274 -0
- package/apps/www/tasks/index.tsx +638 -530
- package/dist/apps/admin/audit-log/index.js +38 -8
- package/dist/apps/admin/branding/index.js +4 -98
- package/dist/apps/admin/data-requests/index.js +52 -72
- package/dist/apps/admin/distribution-lists/[uid].js +1 -1
- package/dist/apps/admin/domains/[uid].js +5 -68
- package/dist/apps/admin/encryption-policy/index.js +8 -0
- package/dist/apps/admin/escrow-scopes/[uid].js +91 -12
- package/dist/apps/admin/escrow-scopes/new/index.js +8 -3
- package/dist/apps/admin/index.js +17 -1
- package/dist/apps/admin/ingest-queue/index.js +24 -6
- package/dist/apps/admin/mailbox-policy/index.js +8 -0
- package/dist/apps/admin/mailboxes/[uid].js +20 -4
- package/dist/apps/admin/mailboxes/new/index.js +4 -89
- package/dist/apps/admin/plugins/index.js +6 -0
- package/dist/apps/admin/quarantine/index.js +20 -11
- package/dist/apps/admin/retention-policy/index.js +3 -36
- package/dist/apps/admin/setup/index.js +6 -0
- package/dist/apps/admin/transport-rules/[uid].js +18 -2
- package/dist/apps/admin/transport-rules/_transportRuleConfig.js +19 -0
- package/dist/apps/admin/transport-rules/index.js +22 -6
- package/dist/apps/admin/transport-rules/new/index.js +18 -2
- package/dist/apps/escrow/_layout.js +3 -3
- package/dist/apps/escrow/audit-log/index.js +26 -1
- package/dist/apps/escrow/matters/[uid].js +77 -42
- package/dist/apps/shared/components/admin/escrowScopes/EscrowScopeKeyAndHoldersFields.js +11 -2
- package/dist/apps/shared/components/admin/layout/AdminShell.js +37 -4
- package/dist/apps/shared/components/admin/mailboxes/EscrowScopeCard.js +72 -0
- package/dist/apps/shared/components/admin/mailboxes/ResourceSettingsCard.js +3 -3
- package/dist/apps/shared/components/admin/mailboxes/ShareAccessCard.js +22 -4
- package/dist/apps/shared/components/admin/settings/BrandingForm.js +116 -0
- package/dist/apps/shared/components/admin/settings/DomainDnsSetup.js +83 -0
- package/dist/apps/shared/components/admin/settings/EncryptionPolicyForm.js +62 -0
- package/dist/apps/shared/components/admin/settings/LoadedSettingsForm.js +25 -0
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +112 -0
- package/dist/apps/shared/components/admin/settings/MailboxPolicyForm.js +74 -0
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +572 -0
- package/dist/apps/shared/components/admin/settings/RetentionPolicyForm.js +73 -0
- package/dist/apps/shared/components/admin/setup/EscrowSetupStep.js +147 -0
- package/dist/apps/shared/components/admin/setup/SetupWizard.js +208 -0
- package/dist/apps/shared/components/admin/signOut.js +75 -0
- package/dist/apps/shared/components/admin/usePagedList.js +99 -0
- package/dist/apps/shared/components/calendar/CalendarListSidebar.js +24 -13
- package/dist/apps/shared/components/calendar/EventModal.js +154 -21
- package/dist/apps/shared/components/calendar/MonthView.js +12 -5
- package/dist/apps/shared/components/calendar/RecurrenceEditor.js +40 -5
- package/dist/apps/shared/components/calendar/SplitDayView.js +10 -4
- package/dist/apps/shared/components/calendar/TimeGridView.js +23 -7
- package/dist/apps/shared/components/calendar/allDay.js +111 -0
- package/dist/apps/shared/components/calendar/layout/CalendarShell.js +47 -39
- package/dist/apps/shared/components/contacts/ContactDetailPane.js +43 -5
- package/dist/apps/shared/components/contacts/ContactForm.js +45 -12
- package/dist/apps/shared/components/contacts/ContactsSidebar.js +2 -2
- package/dist/apps/shared/components/contacts/KeyChangeReview.js +63 -0
- package/dist/apps/shared/components/contacts/contactKeys.js +64 -0
- package/dist/apps/shared/components/escrow/layout/EscrowShell.js +24 -5
- package/dist/apps/shared/components/layout/AppShell.js +100 -8
- package/dist/apps/shared/components/layout/BrandingChrome.js +45 -10
- package/dist/apps/shared/components/layout/KeyEnrollmentGate.js +63 -14
- package/dist/apps/shared/components/layout/MailboxProvisioning.js +10 -2
- package/dist/apps/shared/components/layout/RecoveryCodeUnlock.js +174 -0
- package/dist/apps/shared/components/layout/UnlockPromptProvider.js +136 -0
- package/dist/apps/shared/components/mail/ConversationThreadPane.js +50 -12
- package/dist/apps/shared/components/mail/MessageDetailPane.js +464 -34
- package/dist/apps/shared/components/mail/compose/ComposeContext.js +9 -6
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +807 -116
- package/dist/apps/shared/components/mail/compose/composeFlushRegistry.js +50 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +116 -41
- package/dist/apps/shared/components/mail/pinnedSigners.js +98 -0
- package/dist/apps/shared/components/mail/verificationSeals.js +112 -0
- package/dist/apps/shared/components/mail/writableMailboxes.js +87 -0
- package/dist/apps/shared/components/rules/RuleBuilder.js +34 -6
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
- package/dist/apps/shared/mail/findWellKnownFolderUid.js +12 -0
- package/dist/apps/shared/mail/listAllPages.js +25 -0
- package/dist/apps/shared/search/LocalIndexLifecycle.js +80 -0
- package/dist/apps/shared/search/localIndexBlockCipher.js +63 -0
- package/dist/apps/shared/search/localIndexBuilder.js +408 -0
- package/dist/apps/shared/search/localIndexKey.js +25 -0
- package/dist/apps/shared/search/localIndexRpcClient.js +241 -0
- package/dist/apps/shared/search/localIndexSchema.js +185 -0
- package/dist/apps/shared/search/localIndexSizePreference.js +78 -0
- package/dist/apps/shared/search/localIndexStorage.js +86 -0
- package/dist/apps/shared/search/localIndexVFS.js +258 -0
- package/dist/apps/shared/search/localIndexWorker.js +687 -0
- package/dist/apps/shared/search/searchTier2.js +38 -0
- package/dist/apps/www/calendar/index.js +38 -18
- package/dist/apps/www/contacts/[uid].js +13 -2
- package/dist/apps/www/contacts/index.js +94 -15
- package/dist/apps/www/index.js +770 -137
- package/dist/apps/www/messages/[uid].js +23 -7
- package/dist/apps/www/settings/auto-reply/index.js +9 -4
- package/dist/apps/www/settings/booking-types/[uid].js +17 -12
- package/dist/apps/www/settings/encryption/index.js +541 -96
- package/dist/apps/www/settings/filters/[uid].js +22 -7
- package/dist/apps/www/settings/filters/new/index.js +8 -2
- package/dist/apps/www/settings/focused-inbox/index.js +3 -1
- package/dist/apps/www/settings/privacy/index.js +57 -22
- package/dist/apps/www/settings/read-receipts/index.js +10 -3
- package/dist/apps/www/settings/sharing/index.js +124 -0
- package/dist/apps/www/tasks/index.js +76 -14
- package/package.json +3 -2
|
@@ -4,7 +4,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
4
4
|
// SPDX-License-Identifier: MPL-2.0
|
|
5
5
|
///////////////////////////////////////////////////////////////////////////////
|
|
6
6
|
import { useEffect, useMemo, useState } from "react";
|
|
7
|
-
import { endOfWeek, isAfter, isBefore, isToday, startOfDay } from "date-fns";
|
|
7
|
+
import { endOfWeek, isAfter, isBefore, isToday, parseISO, startOfDay } from "date-fns";
|
|
8
8
|
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
9
9
|
import { createTask, deleteTask, listTasks, setTaskCompleted, setTaskMyDay, } from "@rapidmx/react-shared/tasks/tasksApi.js";
|
|
10
10
|
import { listFlaggedMessages } from "@rapidmx/react-shared/mail/flaggedMessages.js";
|
|
@@ -13,17 +13,29 @@ import TasksSidebar from "../../shared/components/tasks/TasksSidebar.js";
|
|
|
13
13
|
import TasksToolbar from "../../shared/components/tasks/TasksToolbar.js";
|
|
14
14
|
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
15
15
|
import Button from "@rapidmx/react-shared/components/buttons/Button.js";
|
|
16
|
+
import Modal from "@rapidmx/react-shared/components/overlays/Modal.js";
|
|
17
|
+
import { findWellKnownFolderUid } from "../../shared/mail/findWellKnownFolderUid.js";
|
|
18
|
+
import { useWritableMailboxes } from "../../shared/components/mail/writableMailboxes.js";
|
|
19
|
+
import { LIST_PAGE_SIZE, MAX_LIST_PAGES, listAllPages } from "../../shared/mail/listAllPages.js";
|
|
16
20
|
const INPUT_CLASS = "text-sm py-1.5 px-2 border border-border rounded-sm bg-surface text-text focus:outline-none focus:border-primary";
|
|
17
21
|
export default function TasksPage(props) {
|
|
18
22
|
return (_jsx(TasksShell, { ...props, children: _jsx(TasksContent, {}) }));
|
|
19
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Parses a task's `dueDate` - `parseISO()` rather than `new Date()`, since `new Date("2026-06-16")` reads a
|
|
26
|
+
* date-only value as UTC midnight, which is the *previous* local day anywhere west of UTC. A full
|
|
27
|
+
* timestamp parses identically either way.
|
|
28
|
+
*/
|
|
29
|
+
function parseDueDate(value) {
|
|
30
|
+
return parseISO(value);
|
|
31
|
+
}
|
|
20
32
|
const BUCKET_ORDER = ["Overdue", "Today", "This Week", "Later", "No due date"];
|
|
21
33
|
/** Buckets a task by its due date relative to `now`, matching the Outlook/To-Do convention this list mirrors. */
|
|
22
34
|
function bucketFor(task, now) {
|
|
23
35
|
if (!task.dueDate) {
|
|
24
36
|
return "No due date";
|
|
25
37
|
}
|
|
26
|
-
const due =
|
|
38
|
+
const due = parseDueDate(task.dueDate);
|
|
27
39
|
if (isBefore(due, startOfDay(now))) {
|
|
28
40
|
return "Overdue";
|
|
29
41
|
}
|
|
@@ -42,10 +54,18 @@ const PRIORITY_CLASS = {
|
|
|
42
54
|
high: "text-danger",
|
|
43
55
|
};
|
|
44
56
|
function TasksContent() {
|
|
45
|
-
const { folderUid, mailboxUid, userUid } = useTasksShell();
|
|
57
|
+
const { folderUid, mailboxUid, userUid, mailboxes } = useTasksShell();
|
|
58
|
+
// The quick-add form's Mailbox choices - view-only shares are left out (see writableMailboxes.ts).
|
|
59
|
+
const writableMailboxes = useWritableMailboxes(mailboxes, userUid, mailboxUid);
|
|
60
|
+
// The quick-add form's chosen mailbox - `undefined` means "the mailbox being viewed".
|
|
61
|
+
const [targetMailboxUid, setTargetMailboxUid] = useState(undefined);
|
|
62
|
+
// Set after a task is added to a different mailbox than the one this list shows.
|
|
63
|
+
const [addedElsewhere, setAddedElsewhere] = useState(null);
|
|
46
64
|
const [tasks, setTasks] = useState([]);
|
|
47
65
|
const [loading, setLoading] = useState(true);
|
|
48
66
|
const [error, setError] = useState(null);
|
|
67
|
+
// Set when `listAllPages()` stopped at its page cap - the list shown isn't every task.
|
|
68
|
+
const [truncated, setTruncated] = useState(false);
|
|
49
69
|
const [title, setTitle] = useState("");
|
|
50
70
|
const [dueDate, setDueDate] = useState("");
|
|
51
71
|
const [priority, setPriority] = useState("normal");
|
|
@@ -57,22 +77,33 @@ function TasksContent() {
|
|
|
57
77
|
const [flaggedMessages, setFlaggedMessages] = useState([]);
|
|
58
78
|
const [flaggedLoading, setFlaggedLoading] = useState(false);
|
|
59
79
|
const [flaggedError, setFlaggedError] = useState(null);
|
|
80
|
+
// What the delete confirmation dialog is asking about - one task (a row's delete button), or every
|
|
81
|
+
// checked task (the toolbar's Delete).
|
|
82
|
+
const [pendingDelete, setPendingDelete] = useState(null);
|
|
60
83
|
function reload() {
|
|
61
84
|
if (!folderUid) {
|
|
62
85
|
setTasks([]);
|
|
86
|
+
setTruncated(false);
|
|
63
87
|
setLoading(false);
|
|
64
88
|
return Promise.resolve();
|
|
65
89
|
}
|
|
66
90
|
setLoading(true);
|
|
67
91
|
setError(null);
|
|
68
|
-
return listTasks(folderUid, { limit:
|
|
69
|
-
.then(
|
|
92
|
+
return listAllPages((page) => listTasks(folderUid, { limit: LIST_PAGE_SIZE, page }))
|
|
93
|
+
.then((result) => {
|
|
94
|
+
setTasks(result.items);
|
|
95
|
+
setTruncated(result.truncated);
|
|
96
|
+
})
|
|
70
97
|
.catch((err) => setError(err instanceof ApiRequestError ? err.message : "Could not load tasks."))
|
|
71
98
|
.finally(() => setLoading(false));
|
|
72
99
|
}
|
|
73
100
|
useEffect(() => {
|
|
74
101
|
void reload();
|
|
75
102
|
}, [folderUid]);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
setTargetMailboxUid(undefined);
|
|
105
|
+
setAddedElsewhere(null);
|
|
106
|
+
}, [mailboxUid]);
|
|
76
107
|
useEffect(() => {
|
|
77
108
|
if (view.type !== "flagged" || !mailboxUid) {
|
|
78
109
|
return;
|
|
@@ -94,16 +125,30 @@ function TasksContent() {
|
|
|
94
125
|
if (!mailboxUid || !folderUid) {
|
|
95
126
|
return;
|
|
96
127
|
}
|
|
128
|
+
const target = targetMailboxUid ?? mailboxUid;
|
|
97
129
|
setCreating(true);
|
|
98
130
|
try {
|
|
131
|
+
const targetFolderUid = target === mailboxUid ? folderUid : await findWellKnownFolderUid(target, "tasks");
|
|
132
|
+
if (!targetFolderUid) {
|
|
133
|
+
setCreateError("That mailbox has no Tasks folder.");
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
99
136
|
const created = await createTask({
|
|
100
|
-
mailboxUid,
|
|
101
|
-
folderUid,
|
|
137
|
+
mailboxUid: target,
|
|
138
|
+
folderUid: targetFolderUid,
|
|
102
139
|
title: title.trim(),
|
|
103
|
-
|
|
140
|
+
// The date input's "yyyy-MM-dd" is the user's *local* day - see `parseDueDate()`.
|
|
141
|
+
dueDate: dueDate ? parseDueDate(dueDate).toISOString() : undefined,
|
|
104
142
|
priority,
|
|
105
143
|
});
|
|
106
|
-
|
|
144
|
+
if (target === mailboxUid) {
|
|
145
|
+
setAddedElsewhere(null);
|
|
146
|
+
setTasks((prev) => [...prev, created]);
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Created in another mailbox - it doesn't belong in this mailbox's list.
|
|
150
|
+
setAddedElsewhere({ mailboxUid: target, title: created.title });
|
|
151
|
+
}
|
|
107
152
|
setTitle("");
|
|
108
153
|
setDueDate("");
|
|
109
154
|
setPriority("normal");
|
|
@@ -215,6 +260,19 @@ function TasksContent() {
|
|
|
215
260
|
await reload();
|
|
216
261
|
setError(bulkError);
|
|
217
262
|
}
|
|
263
|
+
function requestDelete(task) {
|
|
264
|
+
setPendingDelete({ type: "single", task });
|
|
265
|
+
}
|
|
266
|
+
function handleConfirmDelete() {
|
|
267
|
+
const pending = pendingDelete;
|
|
268
|
+
setPendingDelete(null);
|
|
269
|
+
if (pending.type === "single") {
|
|
270
|
+
void handleDelete(pending.task);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
void handleBulkDelete();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
218
276
|
const grouped = useMemo(() => {
|
|
219
277
|
const now = new Date();
|
|
220
278
|
const map = new Map(BUCKET_ORDER.map((b) => [b, []]));
|
|
@@ -227,13 +285,17 @@ function TasksContent() {
|
|
|
227
285
|
return map;
|
|
228
286
|
}, [viewFiltered]);
|
|
229
287
|
const completedTasks = viewFiltered.filter((t) => t.completed);
|
|
230
|
-
return (_jsxs("div", { className: "flex-1 flex min-h-0", children: [_jsx(TasksSidebar, { mailboxUid: mailboxUid, tasks: tasks, userUid: userUid, active: view, onSelect: handleSelectView }), _jsxs("div", { className: "flex-1 min-w-0 flex flex-col overflow-y-auto", children: [_jsx(TasksToolbar, { viewMode: viewMode, onViewModeChange: setViewMode, selectedCount: checkedTasks.length, onComplete: handleBulkComplete, onDelete:
|
|
288
|
+
return (_jsxs("div", { className: "flex-1 flex min-h-0", children: [_jsx(TasksSidebar, { mailboxUid: mailboxUid, tasks: tasks, userUid: userUid, active: view, onSelect: handleSelectView }), _jsxs("div", { className: "flex-1 min-w-0 flex flex-col overflow-y-auto", children: [_jsx(TasksToolbar, { viewMode: viewMode, onViewModeChange: setViewMode, selectedCount: checkedTasks.length, onComplete: handleBulkComplete, onDelete: () => setPendingDelete({ type: "bulk" }), onAddToMyDay: handleBulkAddToMyDay }), _jsxs("div", { role: "region", "aria-label": "Tasks list", className: "max-w-2xl mx-auto w-full flex flex-col gap-6 p-6", children: [_jsx("h1", { className: "text-xl font-bold uppercase tracking-wide", children: "Tasks" }), error && _jsx(Alert, { children: error }), truncated && view.type !== "flagged" && (_jsxs(Alert, { children: ["This folder has more tasks than can be shown at once - only the first ", LIST_PAGE_SIZE * MAX_LIST_PAGES, " are listed."] })), view.type === "flagged" ? (_jsx(FlaggedEmailList, { loading: flaggedLoading, error: flaggedError, messages: flaggedMessages })) : (_jsxs(_Fragment, { children: [_jsxs("form", { onSubmit: handleCreate, className: "flex items-center gap-2 bg-surface border border-border rounded-md p-2", children: [_jsx("input", { type: "text", "aria-label": "Add a task", className: `${INPUT_CLASS} flex-1`, value: title, onChange: (e) => setTitle(e.target.value), placeholder: "Add a task" }), _jsx("input", { type: "date", "aria-label": "Due date", className: INPUT_CLASS, value: dueDate, onChange: (e) => setDueDate(e.target.value) }), _jsxs("select", { "aria-label": "Priority", className: INPUT_CLASS, value: priority, onChange: (e) => setPriority(e.target.value), children: [_jsx("option", { value: "low", children: "Low" }), _jsx("option", { value: "normal", children: "Normal" }), _jsx("option", { value: "high", children: "High" })] }), writableMailboxes.length > 1 && (_jsx("select", { "aria-label": "Task mailbox", className: `${INPUT_CLASS} max-w-40`,
|
|
289
|
+
// `writableMailboxes` only has entries once `mailboxUid` has resolved.
|
|
290
|
+
value: targetMailboxUid ?? mailboxUid, onChange: (e) => setTargetMailboxUid(e.target.value), children: writableMailboxes.map((mb) => (_jsxs("option", { value: mb.uid, children: [mb.displayName, mb.ownerUserUid === userUid ? "" : " (shared)"] }, mb.uid))) })), _jsx(Button, { type: "submit", loading: creating, disabled: creating, className: "!w-auto shrink-0", children: "Add" })] }), createError && _jsx(Alert, { children: createError }), addedElsewhere && (_jsxs("p", { role: "status", className: "text-sm py-2 px-3 rounded-sm bg-surface-alt text-text", children: ["\u201C", addedElsewhere.title, "\u201D was added to", " ", mailboxes.find((mb) => mb.uid === addedElsewhere.mailboxUid)?.displayName ?? "another mailbox", ".", " ", _jsx("a", { href: `/tasks?mailboxUid=${encodeURIComponent(addedElsewhere.mailboxUid)}`, className: "font-medium text-primary-dark hover:underline", children: "View that mailbox\u2019s tasks" })] })), loading ? (_jsx("p", { className: "text-sm text-text-muted", children: "Loading\u2026" })) : viewFiltered.length === 0 ? (_jsx("p", { className: "text-sm text-text-muted", children: "No tasks yet." })) : viewMode === "grid" ? (_jsx(TaskTable, { tasks: viewFiltered, checkedUids: checkedUids, onToggleChecked: toggleChecked, onToggle: handleToggle, onDelete: requestDelete })) : (_jsxs(_Fragment, { children: [BUCKET_ORDER.map((bucket) => {
|
|
231
291
|
const items = grouped.get(bucket);
|
|
232
292
|
if (items.length === 0) {
|
|
233
293
|
return null;
|
|
234
294
|
}
|
|
235
|
-
return (_jsx(TaskGroup, { label: bucket, tasks: items, checkedUids: checkedUids, onToggleChecked: toggleChecked, onToggle: handleToggle, onDelete:
|
|
236
|
-
}), completedTasks.length > 0 && (_jsx(TaskGroup, { label: "Completed", tasks: completedTasks, checkedUids: checkedUids, onToggleChecked: toggleChecked, onToggle: handleToggle, onDelete:
|
|
295
|
+
return (_jsx(TaskGroup, { label: bucket, tasks: items, checkedUids: checkedUids, onToggleChecked: toggleChecked, onToggle: handleToggle, onDelete: requestDelete }, bucket));
|
|
296
|
+
}), completedTasks.length > 0 && (_jsx(TaskGroup, { label: "Completed", tasks: completedTasks, checkedUids: checkedUids, onToggleChecked: toggleChecked, onToggle: handleToggle, onDelete: requestDelete }))] }))] }))] })] }), _jsxs(Modal, { open: pendingDelete !== null, onClose: () => setPendingDelete(null), title: "Delete tasks", children: [_jsx("p", { className: "text-sm mb-5", children: pendingDelete?.type === "single"
|
|
297
|
+
? `Delete "${pendingDelete.task.title}"?`
|
|
298
|
+
: `Delete ${checkedTasks.length} selected ${checkedTasks.length === 1 ? "task" : "tasks"}?` }), _jsxs("div", { className: "flex gap-3 justify-end", children: [_jsx(Button, { type: "button", variant: "secondary", className: "!w-auto", onClick: () => setPendingDelete(null), children: "Cancel" }), _jsx(Button, { type: "button", className: "!w-auto !bg-none !bg-danger !border-danger hover:!bg-danger", onClick: handleConfirmDelete, children: "Delete" })] })] })] }));
|
|
237
299
|
}
|
|
238
300
|
function FlaggedEmailList({ loading, error, messages }) {
|
|
239
301
|
if (error) {
|
|
@@ -256,7 +318,7 @@ function CompletionToggle({ task, onToggle }) {
|
|
|
256
318
|
].join(" "), children: "\u2713" }));
|
|
257
319
|
}
|
|
258
320
|
function TaskGroup({ label, tasks, checkedUids, onToggleChecked, onToggle, onDelete }) {
|
|
259
|
-
return (_jsxs("div", { children: [_jsx("h2", { className: "text-xs font-bold uppercase tracking-wide text-text-muted mb-2", children: label }), _jsx("ul", { className: "bg-surface border border-border rounded-md divide-y divide-border", children: tasks.map((task) => (_jsxs("li", { className: "flex items-center gap-3 py-2.5 px-3", children: [_jsx("input", { type: "checkbox", "aria-label": `Select ${task.title}`, checked: checkedUids.has(task.uid), onChange: () => onToggleChecked(task.uid) }), _jsx(CompletionToggle, { task: task, onToggle: onToggle }), _jsx("span", { className: ["flex-1 text-sm", task.completed ? "line-through text-text-muted" : ""].join(" "), children: task.title }), task.priority !== "normal" && (_jsx("span", { className: ["text-xs font-medium", PRIORITY_CLASS[task.priority]].join(" "), children: PRIORITY_LABEL[task.priority] })), task.dueDate && (_jsx("span", { className: "text-xs text-text-muted shrink-0", children:
|
|
321
|
+
return (_jsxs("div", { children: [_jsx("h2", { className: "text-xs font-bold uppercase tracking-wide text-text-muted mb-2", children: label }), _jsx("ul", { className: "bg-surface border border-border rounded-md divide-y divide-border", children: tasks.map((task) => (_jsxs("li", { className: "flex items-center gap-3 py-2.5 px-3", children: [_jsx("input", { type: "checkbox", "aria-label": `Select ${task.title}`, checked: checkedUids.has(task.uid), onChange: () => onToggleChecked(task.uid) }), _jsx(CompletionToggle, { task: task, onToggle: onToggle }), _jsx("span", { className: ["flex-1 text-sm", task.completed ? "line-through text-text-muted" : ""].join(" "), children: task.title }), task.priority !== "normal" && (_jsx("span", { className: ["text-xs font-medium", PRIORITY_CLASS[task.priority]].join(" "), children: PRIORITY_LABEL[task.priority] })), task.dueDate && (_jsx("span", { className: "text-xs text-text-muted shrink-0", children: parseDueDate(task.dueDate).toLocaleDateString() })), _jsx("button", { type: "button", onClick: () => onDelete(task), "aria-label": `Delete "${task.title}"`, className: "text-text-muted hover:text-danger text-sm px-1", children: "\u00D7" })] }, task.uid))) })] }));
|
|
260
322
|
}
|
|
261
323
|
function TaskTable({ tasks, checkedUids, onToggleChecked, onToggle, onDelete }) {
|
|
262
324
|
const allChecked = tasks.length > 0 && tasks.every((t) => checkedUids.has(t.uid));
|
|
@@ -276,5 +338,5 @@ function TaskTable({ tasks, checkedUids, onToggleChecked, onToggle, onDelete })
|
|
|
276
338
|
}
|
|
277
339
|
}
|
|
278
340
|
}
|
|
279
|
-
return (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm bg-surface border border-border rounded-md", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-border text-left", children: [_jsx("th", { className: "w-8 px-3 py-2", children: _jsx("input", { type: "checkbox", "aria-label": "Select all tasks", checked: allChecked, onChange: toggleAll }) }), _jsx("th", { className: "w-8 px-3 py-2" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Title" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Due Date" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Importance" }), _jsx("th", { className: "w-8 px-3 py-2" })] }) }), _jsx("tbody", { children: tasks.map((task) => (_jsxs("tr", { className: "border-b border-border last:border-0", children: [_jsx("td", { className: "px-3 py-2", children: _jsx("input", { type: "checkbox", "aria-label": `Select ${task.title}`, checked: checkedUids.has(task.uid), onChange: () => onToggleChecked(task.uid) }) }), _jsx("td", { className: "px-3 py-2", children: _jsx(CompletionToggle, { task: task, onToggle: onToggle }) }), _jsx("td", { className: ["px-3 py-2", task.completed ? "line-through text-text-muted" : ""].join(" "), children: task.title }), _jsx("td", { className: "px-3 py-2 text-text-muted", children: task.dueDate ?
|
|
341
|
+
return (_jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm bg-surface border border-border rounded-md", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-b border-border text-left", children: [_jsx("th", { className: "w-8 px-3 py-2", children: _jsx("input", { type: "checkbox", "aria-label": "Select all tasks", checked: allChecked, onChange: toggleAll }) }), _jsx("th", { className: "w-8 px-3 py-2" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Title" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Due Date" }), _jsx("th", { className: "px-3 py-2 text-xs font-bold uppercase tracking-wide text-text-muted", children: "Importance" }), _jsx("th", { className: "w-8 px-3 py-2" })] }) }), _jsx("tbody", { children: tasks.map((task) => (_jsxs("tr", { className: "border-b border-border last:border-0", children: [_jsx("td", { className: "px-3 py-2", children: _jsx("input", { type: "checkbox", "aria-label": `Select ${task.title}`, checked: checkedUids.has(task.uid), onChange: () => onToggleChecked(task.uid) }) }), _jsx("td", { className: "px-3 py-2", children: _jsx(CompletionToggle, { task: task, onToggle: onToggle }) }), _jsx("td", { className: ["px-3 py-2", task.completed ? "line-through text-text-muted" : ""].join(" "), children: task.title }), _jsx("td", { className: "px-3 py-2 text-text-muted", children: task.dueDate ? parseDueDate(task.dueDate).toLocaleDateString() : "" }), _jsx("td", { className: ["px-3 py-2", PRIORITY_CLASS[task.priority]].join(" "), children: PRIORITY_LABEL[task.priority] }), _jsx("td", { className: "px-3 py-2", children: _jsx("button", { type: "button", onClick: () => onDelete(task), "aria-label": `Delete "${task.title}"`, className: "text-text-muted hover:text-danger text-sm px-1", children: "\u00D7" }) })] }, task.uid))) })] }) }));
|
|
280
342
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rapidmx/web-client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "RapidMX's webmail and admin console React UI for web-based clients.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": "https://github.com/rapidmx/web-client",
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
39
|
"@dnd-kit/core": "^6.3.1",
|
|
40
|
+
"@journeyapps/wa-sqlite": "^2.0.4",
|
|
40
41
|
"@peculiar/x509": "^2.1.0",
|
|
41
|
-
"@rapidmx/react-shared": "
|
|
42
|
+
"@rapidmx/react-shared": "patch:@rapidmx/react-shared@npm%3A0.4.0#~/.yarn/patches/@rapidmx-react-shared-npm-0.4.0-e713beecf2.patch",
|
|
42
43
|
"@tiptap/core": "^3.31.3",
|
|
43
44
|
"@tiptap/extension-highlight": "^3.31.3",
|
|
44
45
|
"@tiptap/extension-image": "^3.31.3",
|