feat: P2.2 Create Appointment from Email + P2.4 Calendar Dashlet + P2.12 Action Wheel + P2.14 Share Files

- P2.2: 'Create Appointment' button in email viewer → pre-fills event modal
  with subject, body, participants, date. calendar-store newEventPrefill state.
- P2.4: MiniCalendarDashlet in sidebar bottom — month grid with event dots,
  day click navigates to calendar. Collapsible, respect firstDayOfWeek.
- P2.12: Custom radial menu (components/ui/radial-menu.tsx) — circular SVG
  menu with keyboard nav, animations. Wired into email-list, contact-list,
  file-browser, calendar-month-view right-click handlers.
- P2.14: 'Send as Attachment' button in file browser — opens compose tab
  with selected files pre-attached via Pro tab store.
This commit is contained in:
Bernd Rodler
2026-08-07 13:15:04 +02:00
parent 67f61f18d0
commit 83e29b3ef1
14 changed files with 933 additions and 42 deletions
+27 -2
View File
@@ -97,6 +97,7 @@ export default function CalendarPage() {
setSelectedDate, setViewMode, toggleCalendarVisibility, updateCalendar, shareCalendar,
removeCalendar, clearCalendarEvents,
refreshAllSubscriptions, icalSubscriptions,
newEventPrefill, setNewEventPrefill,
} = useCalendarStore();
const calendarEnabled = usePolicyStore((s) => s.isFeatureEnabled('calendarEnabled'));
const calendarTasksEnabled = usePolicyStore((s) => s.isFeatureEnabled('calendarTasksEnabled'));
@@ -464,6 +465,19 @@ export default function CalendarPage() {
setShowEventModal(true);
}, [selectedDate, setSelectedDate]);
useEffect(() => {
if (!newEventPrefill) return;
setEditEvent(null);
if (newEventPrefill.date) {
const d = new Date(newEventPrefill.date);
if (!isNaN(d.getTime())) {
setDefaultModalDate(d);
setSelectedDate(d);
}
}
setShowEventModal(true);
}, [newEventPrefill, setSelectedDate]);
const openEditModal = useCallback((event: CalendarEvent) => {
setEditEvent(event);
setDefaultModalDate(undefined);
@@ -1198,6 +1212,9 @@ export default function CalendarPage() {
onContextMenuEvent={handleContextMenuEvent}
onContextMenuEmpty={handleContextMenuEmpty}
onCreateAtTime={openCreateModal}
onEditEvent={openEditModal}
onDeleteEvent={handleDeleteContextMenu}
onDuplicateEvent={handleDuplicateContextMenu}
firstDayOfWeek={firstDayOfWeek}
isMobile={isMobile}
pendingPreview={pendingPreview}
@@ -1490,10 +1507,14 @@ export default function CalendarPage() {
onDelete={handleDeleteEvent}
onDuplicate={handleDuplicateEvent}
onRsvp={handleRsvp}
onClose={() => { setShowEventModal(false); setEditEvent(null); setPendingPreview(null); setDefaultCalendarIdForCreate(undefined); setDefaultModalAllDay(false); }}
onClose={() => { setShowEventModal(false); setEditEvent(null); setPendingPreview(null); setDefaultCalendarIdForCreate(undefined); setDefaultModalAllDay(false); setNewEventPrefill(null); }}
onPreviewChange={setPendingPreview}
currentUserEmails={currentUserEmails}
isMobile={false}
prefillTitle={editEvent ? undefined : newEventPrefill?.title}
prefillDescription={editEvent ? undefined : newEventPrefill?.description}
prefillParticipants={editEvent ? undefined : newEventPrefill?.participants}
prefillDate={editEvent ? undefined : newEventPrefill?.date}
/>
</div>
)}
@@ -1620,9 +1641,13 @@ export default function CalendarPage() {
onDelete={handleDeleteEvent}
onDuplicate={handleDuplicateEvent}
onRsvp={handleRsvp}
onClose={() => { setShowEventModal(false); setEditEvent(null); setDefaultCalendarIdForCreate(undefined); setDefaultModalAllDay(false); }}
onClose={() => { setShowEventModal(false); setEditEvent(null); setDefaultCalendarIdForCreate(undefined); setDefaultModalAllDay(false); setNewEventPrefill(null); }}
currentUserEmails={currentUserEmails}
isMobile={true}
prefillTitle={editEvent ? undefined : newEventPrefill?.title}
prefillDescription={editEvent ? undefined : newEventPrefill?.description}
prefillParticipants={editEvent ? undefined : newEventPrefill?.participants}
prefillDate={editEvent ? undefined : newEventPrefill?.date}
/>
)}