@rapidmx/web-client 0.14.1 → 0.15.1
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/domains/[uid].tsx +3 -2
- package/apps/shared/appearance/AppearanceForm.tsx +9 -1
- package/apps/shared/calendar/bookingPlugin.ts +100 -0
- package/apps/shared/calendar/calendarLiveUpdates.ts +27 -0
- package/apps/shared/components/admin/layout/AdminShell.tsx +37 -5
- package/apps/shared/components/admin/settings/MailboxCreateForm.tsx +3 -1
- package/apps/shared/components/admin/settings/PluginsManager.tsx +1545 -1491
- package/apps/shared/components/calendar/AppointmentQuickForm.tsx +327 -0
- package/apps/shared/components/calendar/DescriptionEditor.tsx +274 -0
- package/apps/shared/components/calendar/EventDescriptionView.tsx +70 -0
- package/apps/shared/components/calendar/EventDetails.tsx +401 -0
- package/apps/shared/components/calendar/EventEditor.tsx +640 -0
- package/apps/shared/components/calendar/EventExpandedForm.tsx +210 -0
- package/apps/shared/components/calendar/EventFormParts.tsx +622 -0
- package/apps/shared/components/calendar/EventModal.tsx +126 -866
- package/apps/shared/components/calendar/EventQuickForm.tsx +116 -0
- package/apps/shared/components/calendar/EventShell.tsx +202 -0
- package/apps/shared/components/calendar/FindATime.tsx +379 -0
- package/apps/shared/components/calendar/LazyDescriptionEditor.tsx +70 -0
- package/apps/shared/components/calendar/MonthView.tsx +15 -3
- package/apps/shared/components/calendar/QuickCreateFaces.tsx +87 -0
- package/apps/shared/components/calendar/QuickCreateTabs.tsx +81 -0
- package/apps/shared/components/calendar/QuickFaceFrame.tsx +81 -0
- package/apps/shared/components/calendar/RecurrenceEditor.tsx +10 -5
- package/apps/shared/components/calendar/RequestChangeForm.tsx +271 -0
- package/apps/shared/components/calendar/SplitDayView.tsx +6 -5
- package/apps/shared/components/calendar/TaskQuickForm.tsx +289 -0
- package/apps/shared/components/calendar/TimeGridView.tsx +8 -6
- package/apps/shared/components/calendar/eventDialogFields.ts +86 -0
- package/apps/shared/components/calendar/eventForm.ts +108 -0
- package/apps/shared/components/calendar/eventFormat.ts +183 -0
- package/apps/shared/components/calendar/findTimeGrid.ts +90 -0
- package/apps/shared/components/calendar/swipeNavigation.ts +14 -0
- package/apps/shared/components/layout/UserMenu.tsx +80 -28
- package/apps/shared/components/mail/ConversationList.tsx +100 -48
- package/apps/shared/components/mail/ConversationThreadPane.tsx +490 -486
- package/apps/shared/components/mail/InviteCard.tsx +387 -0
- package/apps/shared/components/mail/MessageDetailPane.tsx +24 -2
- package/apps/shared/components/mail/SwipeRow.tsx +120 -0
- package/apps/shared/components/mail/compose/ComposeWindow.tsx +7 -3
- package/apps/shared/components/mail/invite/InviteRowChip.tsx +104 -0
- package/apps/shared/components/mail/invite/InviteRsvpPopover.tsx +271 -0
- package/apps/shared/components/mail/invite/InviteTimeline.tsx +200 -0
- package/apps/shared/components/mail/invite/ProposeTimeForm.tsx +109 -0
- package/apps/shared/components/mail/invite/inviteFormat.ts +110 -0
- package/apps/shared/components/mail/invite/inviteStore.ts +114 -0
- package/apps/shared/components/mail/layout/MailShell.tsx +522 -490
- package/apps/shared/components/settings/layout/SettingsShell.tsx +1 -0
- package/apps/shared/gestures/useEnterSlide.ts +54 -0
- package/apps/shared/gestures/useSwipe.ts +114 -0
- package/apps/shared/gestures/useSwipeSlide.ts +113 -0
- package/apps/shared/gestures/useWheelPaging.ts +107 -0
- package/apps/shared/mail/newMailNotifications.ts +171 -183
- package/apps/shared/mail/useNewMailNotifications.ts +178 -178
- package/apps/shared/notifications/preferences.ts +36 -0
- package/apps/shared/notifications/store.ts +560 -551
- package/apps/www/_routes.ts +1 -0
- package/apps/www/calendar/index.tsx +139 -37
- package/apps/www/index.tsx +273 -126
- package/apps/www/messages/[uid].tsx +31 -4
- package/apps/www/settings/profile/index.tsx +248 -0
- package/dist/apps/admin/domains/[uid].js +4 -2
- package/dist/apps/shared/appearance/AppearanceForm.js +9 -1
- package/dist/apps/shared/calendar/bookingPlugin.d.ts +50 -0
- package/dist/apps/shared/calendar/bookingPlugin.js +57 -0
- package/dist/apps/shared/calendar/calendarLiveUpdates.d.ts +11 -0
- package/dist/apps/shared/calendar/calendarLiveUpdates.js +23 -0
- package/dist/apps/shared/components/admin/layout/AdminShell.d.ts +1 -1
- package/dist/apps/shared/components/admin/layout/AdminShell.js +7 -3
- package/dist/apps/shared/components/admin/settings/MailboxCreateForm.js +3 -1
- package/dist/apps/shared/components/admin/settings/PluginsManager.js +40 -6
- package/dist/apps/shared/components/calendar/AppointmentQuickForm.d.ts +47 -0
- package/dist/apps/shared/components/calendar/AppointmentQuickForm.js +135 -0
- package/dist/apps/shared/components/calendar/DescriptionEditor.d.ts +26 -0
- package/dist/apps/shared/components/calendar/DescriptionEditor.js +192 -0
- package/dist/apps/shared/components/calendar/EventDescriptionView.d.ts +14 -0
- package/dist/apps/shared/components/calendar/EventDescriptionView.js +39 -0
- package/dist/apps/shared/components/calendar/EventDetails.d.ts +33 -0
- package/dist/apps/shared/components/calendar/EventDetails.js +137 -0
- package/dist/apps/shared/components/calendar/EventEditor.d.ts +59 -0
- package/dist/apps/shared/components/calendar/EventEditor.js +549 -0
- package/dist/apps/shared/components/calendar/EventExpandedForm.d.ts +14 -0
- package/dist/apps/shared/components/calendar/EventExpandedForm.js +44 -0
- package/dist/apps/shared/components/calendar/EventFormParts.d.ts +69 -0
- package/dist/apps/shared/components/calendar/EventFormParts.js +202 -0
- package/dist/apps/shared/components/calendar/EventModal.d.ts +26 -13
- package/dist/apps/shared/components/calendar/EventModal.js +57 -459
- package/dist/apps/shared/components/calendar/EventQuickForm.d.ts +18 -0
- package/dist/apps/shared/components/calendar/EventQuickForm.js +25 -0
- package/dist/apps/shared/components/calendar/EventShell.d.ts +64 -0
- package/dist/apps/shared/components/calendar/EventShell.js +134 -0
- package/dist/apps/shared/components/calendar/FindATime.d.ts +18 -0
- package/dist/apps/shared/components/calendar/FindATime.js +190 -0
- package/dist/apps/shared/components/calendar/LazyDescriptionEditor.d.ts +8 -0
- package/dist/apps/shared/components/calendar/LazyDescriptionEditor.js +44 -0
- package/dist/apps/shared/components/calendar/MonthView.d.ts +5 -1
- package/dist/apps/shared/components/calendar/MonthView.js +11 -5
- package/dist/apps/shared/components/calendar/QuickCreateFaces.d.ts +30 -0
- package/dist/apps/shared/components/calendar/QuickCreateFaces.js +44 -0
- package/dist/apps/shared/components/calendar/QuickCreateTabs.d.ts +24 -0
- package/dist/apps/shared/components/calendar/QuickCreateTabs.js +46 -0
- package/dist/apps/shared/components/calendar/QuickFaceFrame.d.ts +25 -0
- package/dist/apps/shared/components/calendar/QuickFaceFrame.js +19 -0
- package/dist/apps/shared/components/calendar/RecurrenceEditor.d.ts +4 -1
- package/dist/apps/shared/components/calendar/RecurrenceEditor.js +2 -2
- package/dist/apps/shared/components/calendar/RequestChangeForm.d.ts +36 -0
- package/dist/apps/shared/components/calendar/RequestChangeForm.js +138 -0
- package/dist/apps/shared/components/calendar/SplitDayView.d.ts +3 -2
- package/dist/apps/shared/components/calendar/SplitDayView.js +3 -2
- package/dist/apps/shared/components/calendar/TaskQuickForm.d.ts +40 -0
- package/dist/apps/shared/components/calendar/TaskQuickForm.js +101 -0
- package/dist/apps/shared/components/calendar/TimeGridView.d.ts +4 -2
- package/dist/apps/shared/components/calendar/TimeGridView.js +3 -2
- package/dist/apps/shared/components/calendar/eventDialogFields.d.ts +28 -0
- package/dist/apps/shared/components/calendar/eventDialogFields.js +59 -0
- package/dist/apps/shared/components/calendar/eventForm.d.ts +98 -0
- package/dist/apps/shared/components/calendar/eventForm.js +1 -0
- package/dist/apps/shared/components/calendar/eventFormat.d.ts +67 -0
- package/dist/apps/shared/components/calendar/eventFormat.js +163 -0
- package/dist/apps/shared/components/calendar/findTimeGrid.d.ts +30 -0
- package/dist/apps/shared/components/calendar/findTimeGrid.js +83 -0
- package/dist/apps/shared/components/calendar/swipeNavigation.d.ts +9 -0
- package/dist/apps/shared/components/calendar/swipeNavigation.js +8 -0
- package/dist/apps/shared/components/layout/UserMenu.d.ts +10 -8
- package/dist/apps/shared/components/layout/UserMenu.js +70 -23
- package/dist/apps/shared/components/mail/ConversationList.d.ts +12 -1
- package/dist/apps/shared/components/mail/ConversationList.js +21 -4
- package/dist/apps/shared/components/mail/ConversationThreadPane.d.ts +4 -1
- package/dist/apps/shared/components/mail/InviteCard.d.ts +20 -0
- package/dist/apps/shared/components/mail/InviteCard.js +150 -0
- package/dist/apps/shared/components/mail/MessageDetailPane.js +13 -2
- package/dist/apps/shared/components/mail/SwipeRow.d.ts +22 -0
- package/dist/apps/shared/components/mail/SwipeRow.js +71 -0
- package/dist/apps/shared/components/mail/compose/ComposeWindow.js +8 -3
- package/dist/apps/shared/components/mail/invite/InviteRowChip.d.ts +23 -0
- package/dist/apps/shared/components/mail/invite/InviteRowChip.js +46 -0
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.d.ts +20 -0
- package/dist/apps/shared/components/mail/invite/InviteRsvpPopover.js +141 -0
- package/dist/apps/shared/components/mail/invite/InviteTimeline.d.ts +27 -0
- package/dist/apps/shared/components/mail/invite/InviteTimeline.js +120 -0
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.d.ts +17 -0
- package/dist/apps/shared/components/mail/invite/ProposeTimeForm.js +45 -0
- package/dist/apps/shared/components/mail/invite/inviteFormat.d.ts +28 -0
- package/dist/apps/shared/components/mail/invite/inviteFormat.js +94 -0
- package/dist/apps/shared/components/mail/invite/inviteStore.d.ts +28 -0
- package/dist/apps/shared/components/mail/invite/inviteStore.js +95 -0
- package/dist/apps/shared/components/mail/layout/MailShell.d.ts +5 -0
- package/dist/apps/shared/components/mail/layout/MailShell.js +14 -3
- package/dist/apps/shared/components/settings/layout/SettingsShell.js +1 -0
- package/dist/apps/shared/gestures/useEnterSlide.d.ts +14 -0
- package/dist/apps/shared/gestures/useEnterSlide.js +47 -0
- package/dist/apps/shared/gestures/useSwipe.d.ts +45 -0
- package/dist/apps/shared/gestures/useSwipe.js +90 -0
- package/dist/apps/shared/gestures/useSwipeSlide.d.ts +40 -0
- package/dist/apps/shared/gestures/useSwipeSlide.js +95 -0
- package/dist/apps/shared/gestures/useWheelPaging.d.ts +32 -0
- package/dist/apps/shared/gestures/useWheelPaging.js +85 -0
- package/dist/apps/shared/mail/newMailNotifications.d.ts +3 -8
- package/dist/apps/shared/mail/newMailNotifications.js +3 -12
- package/dist/apps/shared/mail/useNewMailNotifications.js +3 -2
- package/dist/apps/shared/notifications/preferences.d.ts +13 -0
- package/dist/apps/shared/notifications/preferences.js +36 -0
- package/dist/apps/shared/notifications/store.d.ts +1 -0
- package/dist/apps/shared/notifications/store.js +7 -23
- package/dist/apps/www/_routes.js +1 -0
- package/dist/apps/www/calendar/index.js +76 -6
- package/dist/apps/www/index.js +140 -39
- package/dist/apps/www/messages/[uid].js +13 -5
- package/dist/apps/www/settings/profile/index.d.ts +4 -0
- package/dist/apps/www/settings/profile/index.js +124 -0
- package/package.json +2 -2
package/apps/www/_routes.ts
CHANGED
|
@@ -28,6 +28,7 @@ export const wwwRoutes: readonly RouteDefinition[] = [
|
|
|
28
28
|
{ path: "/settings/filters/:uid", active: "settings", load: () => import("./settings/filters/[uid].js") },
|
|
29
29
|
{ path: "/settings/labels", active: "settings", load: () => import("./settings/labels/index.js") },
|
|
30
30
|
{ path: "/settings/privacy", active: "settings", load: () => import("./settings/privacy/index.js") },
|
|
31
|
+
{ path: "/settings/profile", active: "settings", load: () => import("./settings/profile/index.js") },
|
|
31
32
|
{ path: "/settings/read-receipts", active: "settings", load: () => import("./settings/read-receipts/index.js") },
|
|
32
33
|
{ path: "/settings/sharing", active: "settings", load: () => import("./settings/sharing/index.js") },
|
|
33
34
|
{ path: "/settings/signatures", active: "settings", load: () => import("./settings/signatures/index.js") },
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// SPDX-License-Identifier: MPL-2.0
|
|
4
4
|
///////////////////////////////////////////////////////////////////////////////
|
|
5
5
|
import { routedPage } from "../_routedPage.js";
|
|
6
|
-
import React, { useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
7
7
|
import { DndContext, DragEndEvent, MouseSensor, TouchSensor, useSensor, useSensors } from "@dnd-kit/core";
|
|
8
8
|
import { HiOutlineBars3 } from "react-icons/hi2";
|
|
9
9
|
import {
|
|
@@ -21,7 +21,9 @@ import {
|
|
|
21
21
|
startOfWeek,
|
|
22
22
|
} from "date-fns";
|
|
23
23
|
import { ApiRequestError } from "@rapidmx/react-shared/util/api.js";
|
|
24
|
-
import
|
|
24
|
+
import useIsMobile from "@rapidmx/react-shared/util/useIsMobile.js";
|
|
25
|
+
import { CalendarEvent, getCalendarEvent, listCalendarEvents } from "@rapidmx/react-shared/calendar/calendarApi.js";
|
|
26
|
+
import { getPushClient } from "@rapidmx/react-shared/mail/pushClient.js";
|
|
25
27
|
import { moveOccurrence, resizeOccurrenceEnd } from "@rapidmx/react-shared/calendar/calendarMutations.js";
|
|
26
28
|
import { resolveDragAction } from "@rapidmx/react-shared/calendar/calendarDragIds.js";
|
|
27
29
|
import { createFolder } from "@rapidmx/react-shared/mail/mailApi.js";
|
|
@@ -31,21 +33,28 @@ import CalendarShell, { CalendarShellProps, useCalendarShell } from "../../share
|
|
|
31
33
|
import CalendarListSidebar from "../../shared/components/calendar/CalendarListSidebar.js";
|
|
32
34
|
import { useWritableMailboxes } from "../../shared/components/mail/writableMailboxes.js";
|
|
33
35
|
import EventModal from "../../shared/components/calendar/EventModal.js";
|
|
36
|
+
import { EventAnchor, anchorOf } from "../../shared/components/calendar/EventShell.js";
|
|
34
37
|
import MiniDatePicker from "@rapidmx/react-shared/components/pickers/MiniDatePicker.js";
|
|
35
38
|
import MonthView from "../../shared/components/calendar/MonthView.js";
|
|
36
39
|
import SplitDayView from "../../shared/components/calendar/SplitDayView.js";
|
|
37
40
|
import TimeGridView from "../../shared/components/calendar/TimeGridView.js";
|
|
38
41
|
import Alert from "@rapidmx/react-shared/components/feedback/Alert.js";
|
|
39
42
|
import Button from "@rapidmx/react-shared/components/buttons/Button.js";
|
|
43
|
+
import { SWIPE_PERIOD_SHIFT } from "../../shared/components/calendar/swipeNavigation.js";
|
|
44
|
+
import { useSwipeSlide } from "../../shared/gestures/useSwipeSlide.js";
|
|
45
|
+
import { useEnterSlide } from "../../shared/gestures/useEnterSlide.js";
|
|
46
|
+
import { useWheelPaging, type WheelEdge } from "../../shared/gestures/useWheelPaging.js";
|
|
40
47
|
import { SHORTCUTS, ShortcutDef } from "../../shared/keyboard/keymap.js";
|
|
41
48
|
import { useShortcut } from "../../shared/keyboard/useShortcut.js";
|
|
42
49
|
import { useShortcutProps } from "../../shared/keyboard/useShortcutProps.js";
|
|
43
50
|
import { notifyApiError } from "../../shared/notifications/apiErrors.js";
|
|
51
|
+
import { bookingSettingsHref } from "../../shared/calendar/bookingPlugin.js";
|
|
52
|
+
import { redactedEventUidOf } from "../../shared/calendar/calendarLiveUpdates.js";
|
|
44
53
|
|
|
45
54
|
function CalendarPage(props: CalendarShellProps) {
|
|
46
55
|
return (
|
|
47
56
|
<CalendarShell {...props}>
|
|
48
|
-
<CalendarContent userUid={props.userUid} />
|
|
57
|
+
<CalendarContent userUid={props.userUid} bookingHref={bookingSettingsHref(props.pluginNav)} />
|
|
49
58
|
</CalendarShell>
|
|
50
59
|
);
|
|
51
60
|
}
|
|
@@ -90,9 +99,13 @@ interface ModalState {
|
|
|
90
99
|
/** Overrides the default calendar a new event is created into (e.g. the column clicked in Split
|
|
91
100
|
* view) — ignored when editing an existing occurrence, which always keeps its own `folderUid`. */
|
|
92
101
|
targetFolderUid?: string;
|
|
102
|
+
/** What was clicked to start a new event, for the quick-create popover to open beside (none: centered near the top). */
|
|
103
|
+
anchor?: EventAnchor;
|
|
104
|
+
/** A new event that starts as an all-day one (a day of the month view was clicked). */
|
|
105
|
+
initialAllDay?: boolean;
|
|
93
106
|
}
|
|
94
107
|
|
|
95
|
-
function CalendarContent({ userUid }: { userUid?: string }) {
|
|
108
|
+
function CalendarContent({ userUid, bookingHref }: { userUid?: string; bookingHref?: string }) {
|
|
96
109
|
const { mailboxUid, folderUid, calendarFolders, mailboxCalendars, mailboxes, reloadFolders, colorFor } = useCalendarShell();
|
|
97
110
|
// `PointerSensor` alone activates a drag on the very first touch-move, indistinguishable from a
|
|
98
111
|
// scroll gesture on a touch device. `MouseSensor` (a small `distance` — desktop drags still start
|
|
@@ -111,6 +124,8 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
111
124
|
const [loading, setLoading] = useState(true);
|
|
112
125
|
const [error, setError] = useState<string | null>(null);
|
|
113
126
|
const [modal, setModal] = useState<ModalState | null>(null);
|
|
127
|
+
// True from the moment a touch drag of an event (or its resize handle) activates until it ends or is cancelled.
|
|
128
|
+
const [dragging, setDragging] = useState(false);
|
|
114
129
|
// `null` means "not yet customized by the user" — every calendar is treated as checked without
|
|
115
130
|
// needing to be seeded from `calendarFolders` the moment it loads (see `checkedFolderUids` below).
|
|
116
131
|
// Once the user toggles anything, this becomes a real (possibly empty) set of exactly what's checked.
|
|
@@ -235,6 +250,39 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
235
250
|
const checkedFolderUidsKey = Array.from(checkedFolderUids).sort().join(",");
|
|
236
251
|
useEffect(reload, [calendarFolderUidsKey, checkedFolderUidsKey]);
|
|
237
252
|
|
|
253
|
+
// A private or confidential event that somebody creates or changes is announced on the push connection as its busy block, whatever the reader may
|
|
254
|
+
// see (see `redactedEventUidOf()`): that payload is never stored here. The event is fetched again by its uid, which comes back as much as this
|
|
255
|
+
// reader may see - all of it for the owner - and replaces (or joins) what the calendar holds; one that is gone (a 404) leaves it. A failed fetch
|
|
256
|
+
// changes nothing: the next load shows the event as it is.
|
|
257
|
+
const checkedFolderUidsRef = useRef(checkedFolderUids);
|
|
258
|
+
checkedFolderUidsRef.current = checkedFolderUids;
|
|
259
|
+
useEffect(
|
|
260
|
+
() =>
|
|
261
|
+
getPushClient().onEvent((event) => {
|
|
262
|
+
const uid = redactedEventUidOf(event);
|
|
263
|
+
if (!uid) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
void getCalendarEvent(uid).then(
|
|
267
|
+
(fresh) => {
|
|
268
|
+
if (checkedFolderUidsRef.current.has(fresh.folderUid)) {
|
|
269
|
+
setEvents((previous) =>
|
|
270
|
+
previous.some((existing) => existing.uid === fresh.uid)
|
|
271
|
+
? previous.map((existing) => (existing.uid === fresh.uid ? fresh : existing))
|
|
272
|
+
: [...previous, fresh],
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
(err: unknown) => {
|
|
277
|
+
if (err instanceof ApiRequestError && err.status === 404) {
|
|
278
|
+
setEvents((previous) => previous.filter((existing) => existing.uid !== uid));
|
|
279
|
+
}
|
|
280
|
+
},
|
|
281
|
+
);
|
|
282
|
+
}),
|
|
283
|
+
[],
|
|
284
|
+
);
|
|
285
|
+
|
|
238
286
|
const occurrences = useMemo(
|
|
239
287
|
() => expandAllOccurrences(events, rangeStart, rangeEnd),
|
|
240
288
|
[events, rangeStart, rangeEnd],
|
|
@@ -258,6 +306,41 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
258
306
|
);
|
|
259
307
|
}
|
|
260
308
|
|
|
309
|
+
// The phone layout's swipe between periods. Only the view area carries it (not the toolbar), it calls the same `shiftView()`
|
|
310
|
+
// the Previous/Next buttons and shortcuts do, and it is off while an event is being dragged or the editor is open. The views
|
|
311
|
+
// never scroll sideways (their columns share the width), so there is no horizontal scroller for the gesture to fight with.
|
|
312
|
+
// The view follows the finger and, once the swipe commits, slides out while the next period slides in (see `useSwipeSlide()`).
|
|
313
|
+
const isMobile = useIsMobile();
|
|
314
|
+
const swipe = useSwipeSlide({
|
|
315
|
+
enabled: isMobile && !dragging && !modal,
|
|
316
|
+
onShift: (direction) => shiftView(SWIPE_PERIOD_SHIFT[direction]),
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
// The desktop's mouse wheel steps through the months without end; in the views that scroll through the hours of a day it scrolls
|
|
320
|
+
// them as usual and, pushed past the last (or first) hour, carries on into the next (or previous) day, week or work week. Each
|
|
321
|
+
// step is the same `shiftView()` and enters with a short vertical slide (`useEnterSlide()`), which never waits for the last one.
|
|
322
|
+
const wheelSlide = useEnterSlide();
|
|
323
|
+
/** Where the scroller of the page a wheel step arrived at starts: its top after going on, its bottom after going back. */
|
|
324
|
+
const arrivalEdge = useRef<WheelEdge | null>(null);
|
|
325
|
+
const scrollerOf = (): HTMLElement | null => swipe.ref.current?.querySelector<HTMLElement>("[data-calendar-scroller]") ?? null;
|
|
326
|
+
useWheelPaging(swipe.ref, {
|
|
327
|
+
enabled: !isMobile && !dragging && !modal,
|
|
328
|
+
getScroller: () => (view === "month" ? null : scrollerOf()),
|
|
329
|
+
onStep: (direction, edge) => {
|
|
330
|
+
arrivalEdge.current = edge;
|
|
331
|
+
shiftView(direction);
|
|
332
|
+
wheelSlide.enter(direction);
|
|
333
|
+
},
|
|
334
|
+
});
|
|
335
|
+
useLayoutEffect(() => {
|
|
336
|
+
const edge = arrivalEdge.current;
|
|
337
|
+
arrivalEdge.current = null;
|
|
338
|
+
const scroller = edge ? scrollerOf() : null;
|
|
339
|
+
if (scroller) {
|
|
340
|
+
scroller.scrollTop = edge === "top" ? 0 : scroller.scrollHeight;
|
|
341
|
+
}
|
|
342
|
+
}, [viewDate]);
|
|
343
|
+
|
|
261
344
|
function goToday() {
|
|
262
345
|
setViewDate(startOfDay(new Date()));
|
|
263
346
|
}
|
|
@@ -267,7 +350,7 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
267
350
|
setViewDate(startOfDay(date));
|
|
268
351
|
}
|
|
269
352
|
|
|
270
|
-
function openNewEvent(start?: Date, end?: Date, targetFolderUid?: string) {
|
|
353
|
+
function openNewEvent(start?: Date, end?: Date, targetFolderUid?: string, anchor?: EventAnchor, initialAllDay?: boolean) {
|
|
271
354
|
if (!mailboxUid || !folderUid) {
|
|
272
355
|
return;
|
|
273
356
|
}
|
|
@@ -276,6 +359,8 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
276
359
|
initialStart: start ?? new Date(),
|
|
277
360
|
initialEnd: end ?? new Date(Date.now() + 30 * 60_000),
|
|
278
361
|
targetFolderUid,
|
|
362
|
+
anchor,
|
|
363
|
+
initialAllDay,
|
|
279
364
|
});
|
|
280
365
|
}
|
|
281
366
|
|
|
@@ -312,6 +397,7 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
312
397
|
}
|
|
313
398
|
|
|
314
399
|
async function handleDragEnd(event: DragEndEvent) {
|
|
400
|
+
setDragging(false);
|
|
315
401
|
const overId = event.over ? String(event.over.id) : undefined;
|
|
316
402
|
const action = resolveDragAction(String(event.active.id), overId, occurrences);
|
|
317
403
|
if (!action) {
|
|
@@ -380,7 +466,7 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
380
466
|
>
|
|
381
467
|
<HiOutlineBars3 size={20} aria-hidden="true" />
|
|
382
468
|
</button>
|
|
383
|
-
<Button type="button" onClick={() => openNewEvent()} className="!w-auto shrink-0" {...newEventHint}>
|
|
469
|
+
<Button type="button" onClick={(e) => openNewEvent(undefined, undefined, undefined, anchorOf(e.currentTarget, "below"))} className="!w-auto shrink-0" {...newEventHint}>
|
|
384
470
|
+ New event
|
|
385
471
|
</Button>
|
|
386
472
|
<div className="flex items-center gap-1">
|
|
@@ -408,37 +494,49 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
408
494
|
</div>
|
|
409
495
|
)}
|
|
410
496
|
|
|
411
|
-
{
|
|
412
|
-
<
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
497
|
+
<div ref={swipe.ref} className="flex-1 min-w-0 flex flex-col min-h-0 overflow-hidden" {...swipe.handlers} style={swipe.style}>
|
|
498
|
+
<div data-swipe-phase={swipe.phase} className="flex-1 min-w-0 flex flex-col min-h-0" style={swipe.contentStyle}>
|
|
499
|
+
<div className="flex-1 min-w-0 flex flex-col min-h-0" style={wheelSlide.style}>
|
|
500
|
+
{loading ? (
|
|
501
|
+
<p className="p-4 text-sm text-text-muted">Loading…</p>
|
|
502
|
+
) : (
|
|
503
|
+
<DndContext
|
|
504
|
+
sensors={sensors}
|
|
505
|
+
onDragStart={() => setDragging(true)}
|
|
506
|
+
onDragEnd={handleDragEnd}
|
|
507
|
+
onDragCancel={() => setDragging(false)}
|
|
508
|
+
>
|
|
509
|
+
{view === "month" ? (
|
|
510
|
+
<MonthView
|
|
511
|
+
viewDate={viewDate}
|
|
512
|
+
occurrences={occurrences}
|
|
513
|
+
folderColors={folderColors}
|
|
514
|
+
onSelectDay={handleSelectDay}
|
|
515
|
+
onSelectEvent={openEvent}
|
|
516
|
+
onSelectSlot={(start, end, anchor) => openNewEvent(start, end, undefined, anchor, true)}
|
|
517
|
+
/>
|
|
518
|
+
) : view === "split" ? (
|
|
519
|
+
<SplitDayView
|
|
520
|
+
day={viewDate}
|
|
521
|
+
columns={splitColumns}
|
|
522
|
+
occurrences={occurrences}
|
|
523
|
+
onSelectEvent={openEvent}
|
|
524
|
+
onSelectSlot={(start, end, targetFolderUid, anchor) => openNewEvent(start, end, targetFolderUid, anchor)}
|
|
525
|
+
/>
|
|
526
|
+
) : (
|
|
527
|
+
<TimeGridView
|
|
528
|
+
days={days}
|
|
529
|
+
occurrences={occurrences}
|
|
530
|
+
folderColors={folderColors}
|
|
531
|
+
onSelectEvent={openEvent}
|
|
532
|
+
onSelectSlot={(start, end, anchor) => openNewEvent(start, end, undefined, anchor)}
|
|
533
|
+
/>
|
|
534
|
+
)}
|
|
535
|
+
</DndContext>
|
|
536
|
+
)}
|
|
537
|
+
</div>
|
|
538
|
+
</div>
|
|
539
|
+
</div>
|
|
442
540
|
|
|
443
541
|
{/* `folderUid` is guaranteed defined whenever `modal` is: `openNewEvent` only sets it after
|
|
444
542
|
checking it, and `openEvent` only fires from an occurrence that itself required a
|
|
@@ -452,11 +550,15 @@ function CalendarContent({ userUid }: { userUid?: string }) {
|
|
|
452
550
|
folderUid={modalFolderUid!}
|
|
453
551
|
calendars={calendarFolders.filter((f) => f.mailboxUid === modalMailbox.uid).map((f) => ({ uid: f.uid, name: f.name }))}
|
|
454
552
|
mailboxOptions={mailboxOptions}
|
|
553
|
+
folderColors={folderColors}
|
|
455
554
|
organizerAddress={modalMailbox.primarySmtpAddress}
|
|
456
555
|
organizerAliases={modalMailbox.aliasAddresses}
|
|
457
556
|
occurrence={modal.occurrence}
|
|
458
557
|
initialStart={modal.initialStart}
|
|
459
558
|
initialEnd={modal.initialEnd}
|
|
559
|
+
initialAllDay={modal.initialAllDay}
|
|
560
|
+
anchor={modal.anchor}
|
|
561
|
+
bookingHref={bookingHref}
|
|
460
562
|
onSaved={handleSaved}
|
|
461
563
|
onDeleted={handleDeleted}
|
|
462
564
|
/>
|