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:
@@ -1,27 +1,51 @@
|
||||
import { CalendarEvent, CreateEventDTO, UpdateEventDTO } from "@caldav/shared";
|
||||
import {
|
||||
CalendarEvent,
|
||||
CreateEventDTO,
|
||||
UpdateEventDTO,
|
||||
ExpandedEvent,
|
||||
} from "@caldav/shared";
|
||||
import { EventRepository } from "./interfaces";
|
||||
import { expandRecurringEvents } from "../utils/recurrenceExpander";
|
||||
|
||||
export class EventService {
|
||||
constructor(private eventRepo: EventRepository) {}
|
||||
|
||||
async create(userId: string, data: CreateEventDTO): Promise<CalendarEvent> {
|
||||
throw new Error("Not implemented");
|
||||
return this.eventRepo.create(userId, data);
|
||||
}
|
||||
|
||||
async getById(id: string, userId: string): Promise<CalendarEvent | null> {
|
||||
throw new Error("Not implemented");
|
||||
const event = await this.eventRepo.findById(id);
|
||||
if (!event || event.userId !== userId) {
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
async getAll(userId: string): Promise<CalendarEvent[]> {
|
||||
throw new Error("Not implemented");
|
||||
return this.eventRepo.findByUserId(userId);
|
||||
}
|
||||
|
||||
async getByDateRange(
|
||||
userId: string,
|
||||
startDate: Date,
|
||||
endDate: Date,
|
||||
): Promise<CalendarEvent[]> {
|
||||
throw new Error("Not implemented");
|
||||
): Promise<ExpandedEvent[]> {
|
||||
// Get all events for the user
|
||||
const allEvents = await this.eventRepo.findByUserId(userId);
|
||||
|
||||
// Separate recurring and non-recurring events
|
||||
const recurringEvents = allEvents.filter((e) => e.isRecurring);
|
||||
const nonRecurringEvents = allEvents.filter((e) => !e.isRecurring);
|
||||
|
||||
// Expand all events (recurring get multiple instances, non-recurring stay as-is)
|
||||
const expanded = expandRecurringEvents(
|
||||
[...nonRecurringEvents, ...recurringEvents],
|
||||
startDate,
|
||||
endDate,
|
||||
);
|
||||
|
||||
return expanded;
|
||||
}
|
||||
|
||||
async update(
|
||||
@@ -29,10 +53,18 @@ export class EventService {
|
||||
userId: string,
|
||||
data: UpdateEventDTO,
|
||||
): Promise<CalendarEvent | null> {
|
||||
throw new Error("Not implemented");
|
||||
const event = await this.eventRepo.findById(id);
|
||||
if (!event || event.userId !== userId) {
|
||||
return null;
|
||||
}
|
||||
return this.eventRepo.update(id, data);
|
||||
}
|
||||
|
||||
async delete(id: string, userId: string): Promise<boolean> {
|
||||
throw new Error("Not implemented");
|
||||
const event = await this.eventRepo.findById(id);
|
||||
if (!event || event.userId !== userId) {
|
||||
return false;
|
||||
}
|
||||
return this.eventRepo.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user