Calendar/src/repositories/MockEventRepository.ts

123 lines
3.9 KiB
TypeScript
Raw Normal View History

import { ICalendarEvent, EntityType } from '../types/CalendarTypes';
import { CalendarEventType } from '../types/BookingTypes';
import { IApiRepository } from './IApiRepository';
2025-11-03 14:54:57 +01:00
interface RawEventData {
// Core fields (required)
2025-11-03 14:54:57 +01:00
id: string;
title: string;
start: string | Date;
end: string | Date;
type: string;
allDay?: boolean;
// Denormalized references (CRITICAL for booking architecture)
bookingId?: string; // Reference to booking (customer events only)
resourceId?: string; // Which resource owns this slot
customerId?: string; // Customer reference (denormalized from booking)
// Optional fields
description?: string; // Detailed event notes
recurringId?: string; // For recurring events
metadata?: Record<string, any>; // Flexible metadata
// Legacy (deprecated, keep for backward compatibility)
color?: string; // UI-specific field
2025-11-03 14:54:57 +01:00
[key: string]: unknown;
}
/**
* MockEventRepository - Loads event data from local JSON file
2025-11-03 14:54:57 +01:00
*
* This repository implementation fetches mock event data from a static JSON file.
* Used for development and testing instead of API calls.
2025-11-03 14:54:57 +01:00
*
* Data Source: data/mock-events.json
*
* NOTE: Create/Update/Delete operations are not supported - throws errors.
* Only fetchAll() is implemented for loading initial mock data.
2025-11-03 14:54:57 +01:00
*/
export class MockEventRepository implements IApiRepository<ICalendarEvent> {
public readonly entityType: EntityType = 'Event';
2025-11-03 14:54:57 +01:00
private readonly dataUrl = 'data/mock-events.json';
/**
* Fetch all events from mock JSON file
*/
public async fetchAll(): Promise<ICalendarEvent[]> {
2025-11-03 14:54:57 +01:00
try {
const response = await fetch(this.dataUrl);
if (!response.ok) {
throw new Error(`Failed to load mock events: ${response.status} ${response.statusText}`);
}
const rawData: RawEventData[] = await response.json();
return this.processCalendarData(rawData);
} catch (error) {
console.error('Failed to load event data:', error);
throw error;
}
}
/**
* NOT SUPPORTED - MockEventRepository is read-only
*/
public async sendCreate(event: ICalendarEvent): Promise<ICalendarEvent> {
throw new Error('MockEventRepository does not support sendCreate. Mock data is read-only.');
}
/**
* NOT SUPPORTED - MockEventRepository is read-only
*/
public async sendUpdate(id: string, updates: Partial<ICalendarEvent>): Promise<ICalendarEvent> {
throw new Error('MockEventRepository does not support sendUpdate. Mock data is read-only.');
}
/**
* NOT SUPPORTED - MockEventRepository is read-only
*/
public async sendDelete(id: string): Promise<void> {
throw new Error('MockEventRepository does not support sendDelete. Mock data is read-only.');
}
2025-11-03 21:30:50 +01:00
private processCalendarData(data: RawEventData[]): ICalendarEvent[] {
return data.map((event): ICalendarEvent => {
// Validate event type constraints
if (event.type === 'customer') {
if (!event.bookingId) {
console.warn(`Customer event ${event.id} missing bookingId`);
}
if (!event.resourceId) {
console.warn(`Customer event ${event.id} missing resourceId`);
}
if (!event.customerId) {
console.warn(`Customer event ${event.id} missing customerId`);
}
}
return {
id: event.id,
title: event.title,
description: event.description,
start: new Date(event.start),
end: new Date(event.end),
type: event.type as CalendarEventType,
allDay: event.allDay || false,
// Denormalized references (CRITICAL for booking architecture)
bookingId: event.bookingId,
resourceId: event.resourceId,
customerId: event.customerId,
// Optional fields
recurringId: event.recurringId,
metadata: event.metadata,
syncStatus: 'synced' as const
};
});
2025-11-03 14:54:57 +01:00
}
}