Phase 0.5+0.6: consolidate store dirs and save frontend gap analysis
- 0.5: Moved calendarStore.ts from stores/ to store/, removed stores/ dir, updated import - 0.6: Saved complete frontend gap analysis as frontend-gap-analysis.md (176 lines) - All stores now in src/store/ (5 stores: authStore, uiStore, commStore, pluginToolbarStore, calendarStore)
This commit is contained in:
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* 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({ calendars }),
|
||||
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 };
|
||||
}),
|
||||
}));
|
||||
Reference in New Issue
Block a user