implement calendar event display with day indicators and overlay

- Add ExpandedEvent type to shared package for recurring event instances
- Implement EventController and EventService with full CRUD operations
- Server-side recurring event expansion via recurrenceExpander
- Calendar grid shows orange dot indicator for days with events
- Tap on day opens modal overlay with EventCards
- EventCard component with Feather icons (calendar, clock, repeat, edit, trash)
- EventsStore with Zustand for client-side event state management
- Load events for visible grid range including adjacent month days
- Add textPrimary, borderPrimary, eventIndicator to theme
- Update test responses for multiple events on Saturdays
This commit is contained in:
2026-01-04 17:19:58 +01:00
parent e3f7a778c7
commit 1532acab78
12 changed files with 601 additions and 99 deletions

View File

@@ -1,26 +1,30 @@
import { create } from "zustand";
import { CalendarEvent } from "@caldav/shared";
import { ExpandedEvent } from "@caldav/shared";
interface EventsState {
events: CalendarEvent[];
setEvents: (events: CalendarEvent[]) => void;
addEvent: (event: CalendarEvent) => void;
updateEvent: (id: string, event: Partial<CalendarEvent>) => void;
events: ExpandedEvent[];
setEvents: (events: ExpandedEvent[]) => void;
addEvent: (event: ExpandedEvent) => void;
updateEvent: (id: string, event: Partial<ExpandedEvent>) => void;
deleteEvent: (id: string) => void;
}
export const useEventsStore = create<EventsState>((set) => ({
events: [],
setEvents: (_events: CalendarEvent[]) => {
throw new Error("Not implemented");
setEvents: (events: ExpandedEvent[]) => {
set({ events });
},
addEvent: (_event: CalendarEvent) => {
throw new Error("Not implemented");
addEvent: (event: ExpandedEvent) => {
set((state) => ({ events: [...state.events, event] }));
},
updateEvent: (_id: string, _event: Partial<CalendarEvent>) => {
throw new Error("Not implemented");
updateEvent: (id: string, updates: Partial<ExpandedEvent>) => {
set((state) => ({
events: state.events.map((e) => (e.id === id ? { ...e, ...updates } : e)),
}));
},
deleteEvent: (_id: string) => {
throw new Error("Not implemented");
deleteEvent: (id: string) => {
set((state) => ({
events: state.events.filter((e) => e.id !== id),
}));
},
}));