T08b: Frontend Calendar UI (month view, kanban, ICS, resources, sharing)
- 8 calendar components (MonthView, KanbanBoard, AppointmentModal, TaskDetailPanel, IcsControls, ResourceBooking, SharingSettings + API client) - 2 pages (/calendar, /calendar/kanban) + zustand store - 17 vitest tests (MonthView 5, KanbanBoard 6, AppointmentModal 6) all passing - i18n: calendar namespace in en/de (104 lines each, +exportSuccess key) - TS strict mode pass, npm run build pass
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* Calendar plugin UI store (zustand).
|
||||
*
|
||||
* Holds the currently selected month/week offset, the list of calendars the
|
||||
* user owns / can write to, and the active calendar selection used by the
|
||||
* Month view, Kanban view and ICS controls.
|
||||
*
|
||||
* 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 } from '@/api/calendar';
|
||||
|
||||
export interface CalendarState {
|
||||
/** First day of the visible month (UTC midnight). */
|
||||
visibleMonth: Date;
|
||||
/** Selected calendar id (null = first available). */
|
||||
activeCalendarId: string | null;
|
||||
/** Cached calendar list (filled by fetchCalendars()). */
|
||||
calendars: Calendar[];
|
||||
|
||||
setVisibleMonth: (date: Date) => void;
|
||||
goToNextMonth: () => void;
|
||||
goToPrevMonth: () => void;
|
||||
goToToday: () => void;
|
||||
setActiveCalendarId: (id: string | null) => void;
|
||||
setCalendars: (calendars: Calendar[]) => void;
|
||||
}
|
||||
|
||||
function startOfMonthUtc(d: Date): Date {
|
||||
return new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), 1));
|
||||
}
|
||||
|
||||
export const useCalendarStore = create<CalendarState>((set) => ({
|
||||
visibleMonth: startOfMonthUtc(new Date()),
|
||||
activeCalendarId: null,
|
||||
calendars: [],
|
||||
|
||||
setVisibleMonth: (date) => set({ visibleMonth: startOfMonthUtc(date) }),
|
||||
goToNextMonth: () =>
|
||||
set((s) => {
|
||||
const next = new Date(s.visibleMonth);
|
||||
next.setUTCMonth(next.getUTCMonth() + 1);
|
||||
return { visibleMonth: next };
|
||||
}),
|
||||
goToPrevMonth: () =>
|
||||
set((s) => {
|
||||
const next = new Date(s.visibleMonth);
|
||||
next.setUTCMonth(next.getUTCMonth() - 1);
|
||||
return { visibleMonth: next };
|
||||
}),
|
||||
goToToday: () => set({ visibleMonth: startOfMonthUtc(new Date()) }),
|
||||
setActiveCalendarId: (id) => set({ activeCalendarId: id }),
|
||||
setCalendars: (calendars) => set({ calendars }),
|
||||
}));
|
||||
Reference in New Issue
Block a user