Files
leocrm/frontend/src/store/calendarStore.ts
T
Agent Zero 9f89cb17a0 fix(UI-Overhaul-Phase5): Kalender Visibility-Toggle fix
5.1: Toolbar already has PluginToolbar with navigation, view mode, actions — no changes needed
5.2: Calendar visibility toggle fix:
  - calendarStore.setCalendars now initializes visibleCalendarIds with all calendar IDs
  - CalendarTree.tsx visibility check simplified to visibleCalendarIds.has(cal.id)
  - No more empty-set-means-all-visible confusion

tsc clean
2026-08-21 13:38:20 +02:00

161 lines
5.2 KiB
TypeScript

/**
* Calendar plugin UI store (zustand).
*
* Holds view-mode state (day/week/month/range), navigation dates, the list of
* calendars the user owns / can write to, the active calendar selection,
* which calendars are visible in the grid, and the currently selected entry
* for the right-hand detail panel.
*
* Server state (entries, kanban board) lives in the API hooks layer - this
* store only carries view/UI selection state.
*/
import { create } from 'zustand';
import type { Calendar, CalendarEntry } from '@/api/calendar';
export type CalendarViewMode = 'day' | 'week' | 'month' | 'range';
export interface CalendarState {
/** First day of the visible month (local midnight). */
visibleMonth: Date;
/** First day (Monday) of the visible week. */
visibleWeek: Date;
/** The visible day in day-view mode. */
visibleDay: Date;
/** Start of the date-range view (inclusive). */
rangeStart: Date | null;
/** End of the date-range view (inclusive). */
rangeEnd: Date | null;
/** Current view mode. */
viewMode: CalendarViewMode;
/** Selected calendar id (null = first available). */
activeCalendarId: string | null;
/** Cached calendar list (filled by fetchCalendars()). */
calendars: Calendar[];
/** Currently selected entry for the detail panel. */
selectedEntry: CalendarEntry | null;
/** Set of calendar ids whose entries are shown in the grid (empty = all). */
visibleCalendarIds: Set<string>;
setVisibleMonth: (date: Date) => void;
setVisibleWeek: (date: Date) => void;
setVisibleDay: (date: Date) => void;
setRangeStart: (date: Date | null) => void;
setRangeEnd: (date: Date | null) => void;
setViewMode: (mode: CalendarViewMode) => void;
goToNextMonth: () => void;
goToPrevMonth: () => void;
goToNextWeek: () => void;
goToPrevWeek: () => void;
goToNextDay: () => void;
goToPrevDay: () => void;
goToToday: () => void;
setActiveCalendarId: (id: string | null) => void;
setCalendars: (calendars: Calendar[]) => void;
setSelectedEntry: (entry: CalendarEntry | null) => void;
toggleCalendarVisibility: (id: string) => void;
}
function startOfMonth(d: Date): Date {
return new Date(d.getFullYear(), d.getMonth(), 1);
}
/** Return the Monday of the week containing `d`. */
function startOfWeek(d: Date): Date {
const dayOfWeek = (d.getDay() + 6) % 7; // 0 = Monday
const start = new Date(d);
start.setDate(d.getDate() - dayOfWeek);
start.setHours(0, 0, 0, 0);
return start;
}
function startOfDay(d: Date): Date {
return new Date(d.getFullYear(), d.getMonth(), d.getDate());
}
const today = new Date();
export const useCalendarStore = create<CalendarState>((set) => ({
visibleMonth: startOfMonth(today),
visibleWeek: startOfWeek(today),
visibleDay: startOfDay(today),
rangeStart: startOfDay(today),
rangeEnd: new Date(today.getFullYear(), today.getMonth(), today.getDate() + 30),
viewMode: 'month',
activeCalendarId: null,
calendars: [],
selectedEntry: null,
visibleCalendarIds: new Set<string>(),
setVisibleMonth: (date) => set({ visibleMonth: startOfMonth(date) }),
setVisibleWeek: (date) => set({ visibleWeek: startOfWeek(date) }),
setVisibleDay: (date) => set({ visibleDay: startOfDay(date) }),
setRangeStart: (date) => set({ rangeStart: date ? startOfDay(date) : null }),
setRangeEnd: (date) => set({ rangeEnd: date ? startOfDay(date) : null }),
setViewMode: (mode) => set({ viewMode: mode }),
goToNextMonth: () =>
set((s) => {
const next = new Date(s.visibleMonth);
next.setMonth(next.getMonth() + 1);
return { visibleMonth: next };
}),
goToPrevMonth: () =>
set((s) => {
const next = new Date(s.visibleMonth);
next.setMonth(next.getMonth() - 1);
return { visibleMonth: next };
}),
goToNextWeek: () =>
set((s) => {
const next = new Date(s.visibleWeek);
next.setDate(next.getDate() + 7);
return { visibleWeek: next };
}),
goToPrevWeek: () =>
set((s) => {
const next = new Date(s.visibleWeek);
next.setDate(next.getDate() - 7);
return { visibleWeek: next };
}),
goToNextDay: () =>
set((s) => {
const next = new Date(s.visibleDay);
next.setDate(next.getDate() + 1);
return { visibleDay: next };
}),
goToPrevDay: () =>
set((s) => {
const next = new Date(s.visibleDay);
next.setDate(next.getDate() - 1);
return { visibleDay: next };
}),
goToToday: () =>
set({
visibleMonth: startOfMonth(new Date()),
visibleWeek: startOfWeek(new Date()),
visibleDay: startOfDay(new Date()),
}),
setActiveCalendarId: (id) => set({ activeCalendarId: id }),
setCalendars: (calendars) => set((s) => {
// Initialize visibleCalendarIds with all calendar IDs if empty
const visibleCalendarIds = s.visibleCalendarIds.size === 0
? new Set(calendars.map((c) => c.id))
: s.visibleCalendarIds;
return { calendars, visibleCalendarIds };
}),
setSelectedEntry: (entry) => set({ selectedEntry: entry }),
toggleCalendarVisibility: (id) =>
set((s) => {
const next = new Set(s.visibleCalendarIds);
if (next.has(id)) {
next.delete(id);
} else {
next.add(id);
}
return { visibleCalendarIds: next };
}),
}));