From 4c853f176bf24ddc651ab346810f2ae9b8e34bed Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Sun, 29 Mar 2026 18:27:16 +0200 Subject: [PATCH] feat: add iCal subscription editing and batch event import --- app/[locale]/calendar/page.tsx | 16 +- .../calendar/calendar-sidebar-panel.tsx | 14 +- .../calendar/ical-subscription-modal.tsx | 43 ++-- .../settings/calendar-management-settings.tsx | 17 ++ lib/demo/demo-client.ts | 9 + lib/jmap/client-interface.ts | 1 + lib/jmap/client.ts | 69 ++++++ locales/en/common.json | 6 + stores/calendar-store.ts | 212 ++++++++++-------- 9 files changed, 278 insertions(+), 109 deletions(-) diff --git a/app/[locale]/calendar/page.tsx b/app/[locale]/calendar/page.tsx index 19fce4dd..0b1e2238 100644 --- a/app/[locale]/calendar/page.tsx +++ b/app/[locale]/calendar/page.tsx @@ -67,7 +67,7 @@ export default function CalendarPage() { isLoading, isLoadingEvents, supportsCalendar, error, fetchCalendars, fetchEvents, createEvent, updateEvent, deleteEvent, rsvpEvent, setSelectedDate, setViewMode, toggleCalendarVisibility, updateCalendar, - refreshAllSubscriptions, + refreshAllSubscriptions, icalSubscriptions, } = useCalendarStore(); const { firstDayOfWeek, timeFormat, showWeekNumbers, enableCalendarTasks, showTasksOnCalendar, calendarHoverPreview } = useSettingsStore(); const taskStore = useTaskStore(); @@ -83,6 +83,7 @@ export default function CalendarPage() { const [showEventModal, setShowEventModal] = useState(false); const [showImportModal, setShowImportModal] = useState(false); const [showSubscriptionModal, setShowSubscriptionModal] = useState(false); + const [editingSubscription, setEditingSubscription] = useState(null); const [editEvent, setEditEvent] = useState(null); const [defaultModalDate, setDefaultModalDate] = useState(); const [defaultModalEndDate, setDefaultModalEndDate] = useState(); @@ -948,6 +949,7 @@ export default function CalendarPage() { updateCalendar(client, calendarId, { color }); } : undefined} onSubscribe={() => setShowSubscriptionModal(true)} + onEditSubscription={(subId) => setEditingSubscription(subId)} client={client} /> @@ -1114,6 +1116,18 @@ export default function CalendarPage() { /> )} + {editingSubscription && client && (() => { + const sub = icalSubscriptions.find(s => s.id === editingSubscription); + if (!sub) return null; + return ( + setEditingSubscription(null)} + /> + ); + })()} + void; onColorChange?: (calendarId: string, color: string) => void; onSubscribe?: () => void; + onEditSubscription?: (subscriptionId: string) => void; client?: IJMAPClient | null; } @@ -27,6 +28,7 @@ export function CalendarSidebarPanel({ onToggleVisibility, onColorChange, onSubscribe, + onEditSubscription, client, }: CalendarSidebarPanelProps) { const t = useTranslations("calendar"); @@ -173,6 +175,16 @@ export function CalendarSidebarPanel({ ref={contextMenuRef} className="absolute left-6 top-full mt-1 z-50 bg-background border border-border rounded-lg shadow-lg py-1 w-48" > + diff --git a/components/settings/calendar-management-settings.tsx b/components/settings/calendar-management-settings.tsx index e662c030..a46f9111 100644 --- a/components/settings/calendar-management-settings.tsx +++ b/components/settings/calendar-management-settings.tsx @@ -164,6 +164,7 @@ export function CalendarManagementSettings() { const [colorPickerId, setColorPickerId] = useState(null); const [showImportModal, setShowImportModal] = useState(false); const [showSubscriptionModal, setShowSubscriptionModal] = useState(false); + const [editingSubscription, setEditingSubscription] = useState(null); const [deletingSubId, setDeletingSubId] = useState(null); const [refreshingSubId, setRefreshingSubId] = useState(null); const tImport = useTranslations('calendar.import'); @@ -629,6 +630,14 @@ export function CalendarManagementSettings() { )}
+