Refactors calendar project structure and build configuration
Consolidates V2 codebase into main project directory Updates build script to support simplified entry points Removes redundant files and cleans up project organization Simplifies module imports and entry points for calendar application
This commit is contained in:
parent
9f360237cf
commit
863b433eba
200 changed files with 2331 additions and 16193 deletions
|
|
@ -1,92 +0,0 @@
|
|||
import { IBooking } from '../types/BookingTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { Configuration } from '../configurations/CalendarConfig';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
/**
|
||||
* ApiBookingRepository
|
||||
* Handles communication with backend API for bookings
|
||||
*
|
||||
* Implements IApiRepository<IBooking> for generic sync infrastructure.
|
||||
* Used by SyncManager to send queued booking operations to the server.
|
||||
*/
|
||||
export class ApiBookingRepository implements IApiRepository<IBooking> {
|
||||
readonly entityType: EntityType = 'Booking';
|
||||
private apiEndpoint: string;
|
||||
|
||||
constructor(config: Configuration) {
|
||||
this.apiEndpoint = config.apiEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send create operation to API
|
||||
*/
|
||||
async sendCreate(booking: IBooking): Promise<IBooking> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/bookings`, {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(booking)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API create failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiBookingRepository.sendCreate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send update operation to API
|
||||
*/
|
||||
async sendUpdate(id: string, updates: Partial<IBooking>): Promise<IBooking> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/bookings/${id}`, {
|
||||
// method: 'PATCH',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(updates)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API update failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiBookingRepository.sendUpdate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send delete operation to API
|
||||
*/
|
||||
async sendDelete(id: string): Promise<void> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/bookings/${id}`, {
|
||||
// method: 'DELETE'
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API delete failed: ${response.statusText}`);
|
||||
// }
|
||||
|
||||
throw new Error('ApiBookingRepository.sendDelete not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all bookings from API
|
||||
*/
|
||||
async fetchAll(): Promise<IBooking[]> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/bookings`);
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API fetch failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiBookingRepository.fetchAll not implemented yet');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import { ICustomer } from '../types/CustomerTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { Configuration } from '../configurations/CalendarConfig';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
/**
|
||||
* ApiCustomerRepository
|
||||
* Handles communication with backend API for customers
|
||||
*
|
||||
* Implements IApiRepository<ICustomer> for generic sync infrastructure.
|
||||
* Used by SyncManager to send queued customer operations to the server.
|
||||
*/
|
||||
export class ApiCustomerRepository implements IApiRepository<ICustomer> {
|
||||
readonly entityType: EntityType = 'Customer';
|
||||
private apiEndpoint: string;
|
||||
|
||||
constructor(config: Configuration) {
|
||||
this.apiEndpoint = config.apiEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send create operation to API
|
||||
*/
|
||||
async sendCreate(customer: ICustomer): Promise<ICustomer> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/customers`, {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(customer)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API create failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiCustomerRepository.sendCreate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send update operation to API
|
||||
*/
|
||||
async sendUpdate(id: string, updates: Partial<ICustomer>): Promise<ICustomer> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/customers/${id}`, {
|
||||
// method: 'PATCH',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(updates)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API update failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiCustomerRepository.sendUpdate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send delete operation to API
|
||||
*/
|
||||
async sendDelete(id: string): Promise<void> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/customers/${id}`, {
|
||||
// method: 'DELETE'
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API delete failed: ${response.statusText}`);
|
||||
// }
|
||||
|
||||
throw new Error('ApiCustomerRepository.sendDelete not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all customers from API
|
||||
*/
|
||||
async fetchAll(): Promise<ICustomer[]> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/customers`);
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API fetch failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiCustomerRepository.fetchAll not implemented yet');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,133 +0,0 @@
|
|||
import { ICalendarEvent, EntityType } from '../types/CalendarTypes';
|
||||
import { Configuration } from '../configurations/CalendarConfig';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
/**
|
||||
* ApiEventRepository
|
||||
* Handles communication with backend API for calendar events
|
||||
*
|
||||
* Implements IApiRepository<ICalendarEvent> for generic sync infrastructure.
|
||||
* Used by SyncManager to send queued operations to the server.
|
||||
* NOT used directly by EventManager (which uses IndexedDBEventRepository).
|
||||
*
|
||||
* Future enhancements:
|
||||
* - SignalR real-time updates
|
||||
* - Conflict resolution
|
||||
* - Batch operations
|
||||
*/
|
||||
export class ApiEventRepository implements IApiRepository<ICalendarEvent> {
|
||||
readonly entityType: EntityType = 'Event';
|
||||
private apiEndpoint: string;
|
||||
|
||||
constructor(config: Configuration) {
|
||||
this.apiEndpoint = config.apiEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send create operation to API
|
||||
*/
|
||||
async sendCreate(event: ICalendarEvent): Promise<ICalendarEvent> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/events`, {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(event)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API create failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiEventRepository.sendCreate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send update operation to API
|
||||
*/
|
||||
async sendUpdate(id: string, updates: Partial<ICalendarEvent>): Promise<ICalendarEvent> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/events/${id}`, {
|
||||
// method: 'PATCH',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(updates)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API update failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiEventRepository.sendUpdate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send delete operation to API
|
||||
*/
|
||||
async sendDelete(id: string): Promise<void> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/events/${id}`, {
|
||||
// method: 'DELETE'
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API delete failed: ${response.statusText}`);
|
||||
// }
|
||||
|
||||
throw new Error('ApiEventRepository.sendDelete not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all events from API
|
||||
*/
|
||||
async fetchAll(): Promise<ICalendarEvent[]> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/events`);
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API fetch failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiEventRepository.fetchAll not implemented yet');
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Future: SignalR Integration
|
||||
// ========================================
|
||||
|
||||
/**
|
||||
* Initialize SignalR connection
|
||||
* Placeholder for future implementation
|
||||
*/
|
||||
async initializeSignalR(): Promise<void> {
|
||||
// TODO: Setup SignalR connection
|
||||
// - Connect to hub
|
||||
// - Register event handlers
|
||||
// - Handle reconnection
|
||||
//
|
||||
// Example:
|
||||
// const connection = new signalR.HubConnectionBuilder()
|
||||
// .withUrl(`${this.apiEndpoint}/hubs/calendar`)
|
||||
// .build();
|
||||
//
|
||||
// connection.on('EventCreated', (event: ICalendarEvent) => {
|
||||
// // Handle remote create
|
||||
// });
|
||||
//
|
||||
// connection.on('EventUpdated', (event: ICalendarEvent) => {
|
||||
// // Handle remote update
|
||||
// });
|
||||
//
|
||||
// connection.on('EventDeleted', (eventId: string) => {
|
||||
// // Handle remote delete
|
||||
// });
|
||||
//
|
||||
// await connection.start();
|
||||
|
||||
throw new Error('SignalR not implemented yet');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
import { IResource } from '../types/ResourceTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { Configuration } from '../configurations/CalendarConfig';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
/**
|
||||
* ApiResourceRepository
|
||||
* Handles communication with backend API for resources
|
||||
*
|
||||
* Implements IApiRepository<IResource> for generic sync infrastructure.
|
||||
* Used by SyncManager to send queued resource operations to the server.
|
||||
*/
|
||||
export class ApiResourceRepository implements IApiRepository<IResource> {
|
||||
readonly entityType: EntityType = 'Resource';
|
||||
private apiEndpoint: string;
|
||||
|
||||
constructor(config: Configuration) {
|
||||
this.apiEndpoint = config.apiEndpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send create operation to API
|
||||
*/
|
||||
async sendCreate(resource: IResource): Promise<IResource> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/resources`, {
|
||||
// method: 'POST',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(resource)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API create failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiResourceRepository.sendCreate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send update operation to API
|
||||
*/
|
||||
async sendUpdate(id: string, updates: Partial<IResource>): Promise<IResource> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/resources/${id}`, {
|
||||
// method: 'PATCH',
|
||||
// headers: { 'Content-Type': 'application/json' },
|
||||
// body: JSON.stringify(updates)
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API update failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiResourceRepository.sendUpdate not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send delete operation to API
|
||||
*/
|
||||
async sendDelete(id: string): Promise<void> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/resources/${id}`, {
|
||||
// method: 'DELETE'
|
||||
// });
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API delete failed: ${response.statusText}`);
|
||||
// }
|
||||
|
||||
throw new Error('ApiResourceRepository.sendDelete not implemented yet');
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all resources from API
|
||||
*/
|
||||
async fetchAll(): Promise<IResource[]> {
|
||||
// TODO: Implement API call
|
||||
// const response = await fetch(`${this.apiEndpoint}/resources`);
|
||||
//
|
||||
// if (!response.ok) {
|
||||
// throw new Error(`API fetch failed: ${response.statusText}`);
|
||||
// }
|
||||
//
|
||||
// return await response.json();
|
||||
|
||||
throw new Error('ApiResourceRepository.fetchAll not implemented yet');
|
||||
}
|
||||
}
|
||||
|
|
@ -1,60 +1,33 @@
|
|||
import { EntityType } from '../types/CalendarTypes';
|
||||
|
||||
/**
|
||||
* IApiRepository<T> - Generic interface for backend API communication
|
||||
*
|
||||
* All entity-specific API repositories (Event, Booking, Customer, Resource)
|
||||
* must implement this interface to ensure consistent sync behavior.
|
||||
*
|
||||
* Used by SyncManager to route operations to the correct API endpoints
|
||||
* based on entity type (dataEntity.typename).
|
||||
*
|
||||
* Pattern:
|
||||
* - Each entity has its own concrete implementation (ApiEventRepository, ApiBookingRepository, etc.)
|
||||
* - SyncManager maintains a map of entityType → IApiRepository<T>
|
||||
* - Operations are routed at runtime based on IQueueOperation.dataEntity.typename
|
||||
*/
|
||||
export interface IApiRepository<T> {
|
||||
/**
|
||||
* Entity type discriminator - used for runtime routing
|
||||
* Must match EntityType values ('Event', 'Booking', 'Customer', 'Resource')
|
||||
*/
|
||||
readonly entityType: EntityType;
|
||||
|
||||
/**
|
||||
* Send create operation to backend API
|
||||
*
|
||||
* @param data - Entity data to create
|
||||
* @returns Promise<T> - Created entity from server (with server-generated fields)
|
||||
* @throws Error if API call fails
|
||||
*/
|
||||
sendCreate(data: T): Promise<T>;
|
||||
|
||||
/**
|
||||
* Send update operation to backend API
|
||||
*
|
||||
* @param id - Entity ID
|
||||
* @param updates - Partial entity data to update
|
||||
* @returns Promise<T> - Updated entity from server
|
||||
* @throws Error if API call fails
|
||||
*/
|
||||
sendUpdate(id: string, updates: Partial<T>): Promise<T>;
|
||||
|
||||
/**
|
||||
* Send delete operation to backend API
|
||||
*
|
||||
* @param id - Entity ID to delete
|
||||
* @returns Promise<void>
|
||||
* @throws Error if API call fails
|
||||
*/
|
||||
sendDelete(id: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Fetch all entities from backend API
|
||||
* Used for initial sync and full refresh
|
||||
*
|
||||
* @returns Promise<T[]> - Array of all entities
|
||||
* @throws Error if API call fails
|
||||
*/
|
||||
fetchAll(): Promise<T[]>;
|
||||
}
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
|
||||
/**
|
||||
* IApiRepository<T> - Generic interface for backend API communication
|
||||
*
|
||||
* Used by DataSeeder to fetch initial data and by SyncManager for sync operations.
|
||||
*/
|
||||
export interface IApiRepository<T> {
|
||||
/**
|
||||
* Entity type discriminator - used for runtime routing
|
||||
*/
|
||||
readonly entityType: EntityType;
|
||||
|
||||
/**
|
||||
* Send create operation to backend API
|
||||
*/
|
||||
sendCreate(data: T): Promise<T>;
|
||||
|
||||
/**
|
||||
* Send update operation to backend API
|
||||
*/
|
||||
sendUpdate(id: string, updates: Partial<T>): Promise<T>;
|
||||
|
||||
/**
|
||||
* Send delete operation to backend API
|
||||
*/
|
||||
sendDelete(id: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Fetch all entities from backend API
|
||||
*/
|
||||
fetchAll(): Promise<T[]>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export class MockAuditRepository implements IApiRepository<IAuditEntry> {
|
|||
return entity;
|
||||
}
|
||||
|
||||
async sendUpdate(_id: string, entity: IAuditEntry): Promise<IAuditEntry> {
|
||||
async sendUpdate(_id: string, _entity: IAuditEntry): Promise<IAuditEntry> {
|
||||
// Audit entries are immutable - updates should not happen
|
||||
throw new Error('Audit entries cannot be updated');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,90 +1,73 @@
|
|||
import { IBooking, IBookingService, BookingStatus } from '../types/BookingTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawBookingData {
|
||||
id: string;
|
||||
customerId: string;
|
||||
status: string;
|
||||
createdAt: string | Date;
|
||||
services: RawBookingService[];
|
||||
totalPrice?: number;
|
||||
tags?: string[];
|
||||
notes?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface RawBookingService {
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
baseDuration: number;
|
||||
basePrice: number;
|
||||
customPrice?: number;
|
||||
resourceId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockBookingRepository - Loads booking data from local JSON file
|
||||
*
|
||||
* This repository implementation fetches mock booking data from a static JSON file.
|
||||
* Used for development and testing instead of API calls.
|
||||
*
|
||||
* Data Source: data/mock-bookings.json
|
||||
*
|
||||
* NOTE: Create/Update/Delete operations are not supported - throws errors.
|
||||
* Only fetchAll() is implemented for loading initial mock data.
|
||||
*/
|
||||
export class MockBookingRepository implements IApiRepository<IBooking> {
|
||||
public readonly entityType: EntityType = 'Booking';
|
||||
private readonly dataUrl = 'data/mock-bookings.json';
|
||||
|
||||
/**
|
||||
* Fetch all bookings from mock JSON file
|
||||
*/
|
||||
public async fetchAll(): Promise<IBooking[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock bookings: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawBookingData[] = await response.json();
|
||||
|
||||
return this.processBookingData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load booking data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockBookingRepository is read-only
|
||||
*/
|
||||
public async sendCreate(booking: IBooking): Promise<IBooking> {
|
||||
throw new Error('MockBookingRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockBookingRepository is read-only
|
||||
*/
|
||||
public async sendUpdate(id: string, updates: Partial<IBooking>): Promise<IBooking> {
|
||||
throw new Error('MockBookingRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockBookingRepository is read-only
|
||||
*/
|
||||
public async sendDelete(id: string): Promise<void> {
|
||||
throw new Error('MockBookingRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processBookingData(data: RawBookingData[]): IBooking[] {
|
||||
return data.map((booking): IBooking => ({
|
||||
...booking,
|
||||
createdAt: new Date(booking.createdAt),
|
||||
status: booking.status as BookingStatus,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
import { IBooking, IBookingService, BookingStatus, EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawBookingData {
|
||||
id: string;
|
||||
customerId: string;
|
||||
status: string;
|
||||
createdAt: string | Date;
|
||||
services: RawBookingService[];
|
||||
totalPrice?: number;
|
||||
tags?: string[];
|
||||
notes?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
interface RawBookingService {
|
||||
serviceId: string;
|
||||
serviceName: string;
|
||||
baseDuration: number;
|
||||
basePrice: number;
|
||||
customPrice?: number;
|
||||
resourceId: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockBookingRepository - Loads booking data from local JSON file
|
||||
*/
|
||||
export class MockBookingRepository implements IApiRepository<IBooking> {
|
||||
public readonly entityType: EntityType = 'Booking';
|
||||
private readonly dataUrl = 'data/mock-bookings.json';
|
||||
|
||||
public async fetchAll(): Promise<IBooking[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock bookings: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawBookingData[] = await response.json();
|
||||
return this.processBookingData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load booking data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_booking: IBooking): Promise<IBooking> {
|
||||
throw new Error('MockBookingRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<IBooking>): Promise<IBooking> {
|
||||
throw new Error('MockBookingRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockBookingRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processBookingData(data: RawBookingData[]): IBooking[] {
|
||||
return data.map((booking): IBooking => ({
|
||||
id: booking.id,
|
||||
customerId: booking.customerId,
|
||||
status: booking.status as BookingStatus,
|
||||
createdAt: new Date(booking.createdAt),
|
||||
services: booking.services as IBookingService[],
|
||||
totalPrice: booking.totalPrice,
|
||||
tags: booking.tags,
|
||||
notes: booking.notes,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,76 +1,58 @@
|
|||
import { ICustomer } from '../types/CustomerTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawCustomerData {
|
||||
id: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
email?: string;
|
||||
metadata?: Record<string, any>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockCustomerRepository - Loads customer data from local JSON file
|
||||
*
|
||||
* This repository implementation fetches mock customer data from a static JSON file.
|
||||
* Used for development and testing instead of API calls.
|
||||
*
|
||||
* Data Source: data/mock-customers.json
|
||||
*
|
||||
* NOTE: Create/Update/Delete operations are not supported - throws errors.
|
||||
* Only fetchAll() is implemented for loading initial mock data.
|
||||
*/
|
||||
export class MockCustomerRepository implements IApiRepository<ICustomer> {
|
||||
public readonly entityType: EntityType = 'Customer';
|
||||
private readonly dataUrl = 'data/mock-customers.json';
|
||||
|
||||
/**
|
||||
* Fetch all customers from mock JSON file
|
||||
*/
|
||||
public async fetchAll(): Promise<ICustomer[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock customers: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawCustomerData[] = await response.json();
|
||||
|
||||
return this.processCustomerData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load customer data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockCustomerRepository is read-only
|
||||
*/
|
||||
public async sendCreate(customer: ICustomer): Promise<ICustomer> {
|
||||
throw new Error('MockCustomerRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockCustomerRepository is read-only
|
||||
*/
|
||||
public async sendUpdate(id: string, updates: Partial<ICustomer>): Promise<ICustomer> {
|
||||
throw new Error('MockCustomerRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockCustomerRepository is read-only
|
||||
*/
|
||||
public async sendDelete(id: string): Promise<void> {
|
||||
throw new Error('MockCustomerRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processCustomerData(data: RawCustomerData[]): ICustomer[] {
|
||||
return data.map((customer): ICustomer => ({
|
||||
...customer,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
import { ICustomer, EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawCustomerData {
|
||||
id: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
email?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockCustomerRepository - Loads customer data from local JSON file
|
||||
*/
|
||||
export class MockCustomerRepository implements IApiRepository<ICustomer> {
|
||||
public readonly entityType: EntityType = 'Customer';
|
||||
private readonly dataUrl = 'data/mock-customers.json';
|
||||
|
||||
public async fetchAll(): Promise<ICustomer[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock customers: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawCustomerData[] = await response.json();
|
||||
return this.processCustomerData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load customer data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_customer: ICustomer): Promise<ICustomer> {
|
||||
throw new Error('MockCustomerRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<ICustomer>): Promise<ICustomer> {
|
||||
throw new Error('MockCustomerRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockCustomerRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processCustomerData(data: RawCustomerData[]): ICustomer[] {
|
||||
return data.map((customer): ICustomer => ({
|
||||
id: customer.id,
|
||||
name: customer.name,
|
||||
phone: customer.phone,
|
||||
email: customer.email,
|
||||
metadata: customer.metadata,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
55
src/repositories/MockDepartmentRepository.ts
Normal file
55
src/repositories/MockDepartmentRepository.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { IDepartment, EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawDepartmentData {
|
||||
id: string;
|
||||
name: string;
|
||||
resourceIds: string[];
|
||||
syncStatus?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockDepartmentRepository - Loads department data from local JSON file
|
||||
*/
|
||||
export class MockDepartmentRepository implements IApiRepository<IDepartment> {
|
||||
public readonly entityType: EntityType = 'Department';
|
||||
private readonly dataUrl = 'data/mock-departments.json';
|
||||
|
||||
public async fetchAll(): Promise<IDepartment[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock departments: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawDepartmentData[] = await response.json();
|
||||
return this.processDepartmentData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load department data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_department: IDepartment): Promise<IDepartment> {
|
||||
throw new Error('MockDepartmentRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<IDepartment>): Promise<IDepartment> {
|
||||
throw new Error('MockDepartmentRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockDepartmentRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processDepartmentData(data: RawDepartmentData[]): IDepartment[] {
|
||||
return data.map((dept): IDepartment => ({
|
||||
id: dept.id,
|
||||
name: dept.name,
|
||||
resourceIds: dept.resourceIds,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +1,26 @@
|
|||
import { ICalendarEvent, EntityType } from '../types/CalendarTypes';
|
||||
import { CalendarEventType } from '../types/BookingTypes';
|
||||
import { ICalendarEvent, EntityType, CalendarEventType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawEventData {
|
||||
// Core fields (required)
|
||||
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
|
||||
bookingId?: string;
|
||||
resourceId?: string;
|
||||
customerId?: string;
|
||||
description?: string;
|
||||
recurringId?: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockEventRepository - Loads event data from local JSON file
|
||||
*
|
||||
* This repository implementation fetches mock event data from a static JSON file.
|
||||
* Used for development and testing instead of API calls.
|
||||
*
|
||||
* 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.
|
||||
* Used for development and testing. Only fetchAll() is implemented.
|
||||
*/
|
||||
export class MockEventRepository implements IApiRepository<ICalendarEvent> {
|
||||
public readonly entityType: EntityType = 'Event';
|
||||
|
|
@ -53,7 +38,6 @@ export class MockEventRepository implements IApiRepository<ICalendarEvent> {
|
|||
}
|
||||
|
||||
const rawData: RawEventData[] = await response.json();
|
||||
|
||||
return this.processCalendarData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load event data:', error);
|
||||
|
|
@ -61,40 +45,25 @@ export class MockEventRepository implements IApiRepository<ICalendarEvent> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockEventRepository is read-only
|
||||
*/
|
||||
public async sendCreate(event: ICalendarEvent): Promise<ICalendarEvent> {
|
||||
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> {
|
||||
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> {
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockEventRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processCalendarData(data: RawEventData[]): ICalendarEvent[] {
|
||||
return data.map((event): ICalendarEvent => {
|
||||
// Validate event type constraints
|
||||
// Validate customer event 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`);
|
||||
}
|
||||
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 {
|
||||
|
|
@ -105,16 +74,11 @@ export class MockEventRepository implements IApiRepository<ICalendarEvent> {
|
|||
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
|
||||
};
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,80 +1,66 @@
|
|||
import { IResource, ResourceType } from '../types/ResourceTypes';
|
||||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawResourceData {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
type: string;
|
||||
avatarUrl?: string;
|
||||
color?: string;
|
||||
isActive?: boolean;
|
||||
metadata?: Record<string, any>;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockResourceRepository - Loads resource data from local JSON file
|
||||
*
|
||||
* This repository implementation fetches mock resource data from a static JSON file.
|
||||
* Used for development and testing instead of API calls.
|
||||
*
|
||||
* Data Source: data/mock-resources.json
|
||||
*
|
||||
* NOTE: Create/Update/Delete operations are not supported - throws errors.
|
||||
* Only fetchAll() is implemented for loading initial mock data.
|
||||
*/
|
||||
export class MockResourceRepository implements IApiRepository<IResource> {
|
||||
public readonly entityType: EntityType = 'Resource';
|
||||
private readonly dataUrl = 'data/mock-resources.json';
|
||||
|
||||
/**
|
||||
* Fetch all resources from mock JSON file
|
||||
*/
|
||||
public async fetchAll(): Promise<IResource[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock resources: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawResourceData[] = await response.json();
|
||||
|
||||
return this.processResourceData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load resource data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockResourceRepository is read-only
|
||||
*/
|
||||
public async sendCreate(resource: IResource): Promise<IResource> {
|
||||
throw new Error('MockResourceRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockResourceRepository is read-only
|
||||
*/
|
||||
public async sendUpdate(id: string, updates: Partial<IResource>): Promise<IResource> {
|
||||
throw new Error('MockResourceRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
/**
|
||||
* NOT SUPPORTED - MockResourceRepository is read-only
|
||||
*/
|
||||
public async sendDelete(id: string): Promise<void> {
|
||||
throw new Error('MockResourceRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processResourceData(data: RawResourceData[]): IResource[] {
|
||||
return data.map((resource): IResource => ({
|
||||
...resource,
|
||||
type: resource.type as ResourceType,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
import { IResource, ResourceType, EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
import { IWeekSchedule } from '../types/ScheduleTypes';
|
||||
|
||||
interface RawResourceData {
|
||||
id: string;
|
||||
name: string;
|
||||
displayName: string;
|
||||
type: string;
|
||||
avatarUrl?: string;
|
||||
color?: string;
|
||||
isActive?: boolean;
|
||||
defaultSchedule?: IWeekSchedule;
|
||||
metadata?: Record<string, unknown>;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockResourceRepository - Loads resource data from local JSON file
|
||||
*/
|
||||
export class MockResourceRepository implements IApiRepository<IResource> {
|
||||
public readonly entityType: EntityType = 'Resource';
|
||||
private readonly dataUrl = 'data/mock-resources.json';
|
||||
|
||||
public async fetchAll(): Promise<IResource[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock resources: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawResourceData[] = await response.json();
|
||||
return this.processResourceData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load resource data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_resource: IResource): Promise<IResource> {
|
||||
throw new Error('MockResourceRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<IResource>): Promise<IResource> {
|
||||
throw new Error('MockResourceRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockResourceRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processResourceData(data: RawResourceData[]): IResource[] {
|
||||
return data.map((resource): IResource => ({
|
||||
id: resource.id,
|
||||
name: resource.name,
|
||||
displayName: resource.displayName,
|
||||
type: resource.type as ResourceType,
|
||||
avatarUrl: resource.avatarUrl,
|
||||
color: resource.color,
|
||||
isActive: resource.isActive,
|
||||
defaultSchedule: resource.defaultSchedule,
|
||||
metadata: resource.metadata,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
46
src/repositories/MockSettingsRepository.ts
Normal file
46
src/repositories/MockSettingsRepository.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { TenantSetting } from '../types/SettingsTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
/**
|
||||
* MockSettingsRepository - Loads tenant settings from local JSON file
|
||||
*
|
||||
* Settings are stored as separate records per section (workweek, grid, etc.).
|
||||
* The JSON file is already an array of TenantSetting records.
|
||||
*/
|
||||
export class MockSettingsRepository implements IApiRepository<TenantSetting> {
|
||||
public readonly entityType: EntityType = 'Settings';
|
||||
private readonly dataUrl = 'data/tenant-settings.json';
|
||||
|
||||
public async fetchAll(): Promise<TenantSetting[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load tenant settings: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const settings: TenantSetting[] = await response.json();
|
||||
// Ensure syncStatus is set on each record
|
||||
return settings.map(s => ({
|
||||
...s,
|
||||
syncStatus: s.syncStatus || 'synced'
|
||||
}));
|
||||
} catch (error) {
|
||||
console.error('Failed to load tenant settings:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_settings: TenantSetting): Promise<TenantSetting> {
|
||||
throw new Error('MockSettingsRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<TenantSetting>): Promise<TenantSetting> {
|
||||
throw new Error('MockSettingsRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockSettingsRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
}
|
||||
55
src/repositories/MockTeamRepository.ts
Normal file
55
src/repositories/MockTeamRepository.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
import { ITeam, EntityType } from '../types/CalendarTypes';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
interface RawTeamData {
|
||||
id: string;
|
||||
name: string;
|
||||
resourceIds: string[];
|
||||
syncStatus?: string;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* MockTeamRepository - Loads team data from local JSON file
|
||||
*/
|
||||
export class MockTeamRepository implements IApiRepository<ITeam> {
|
||||
public readonly entityType: EntityType = 'Team';
|
||||
private readonly dataUrl = 'data/mock-teams.json';
|
||||
|
||||
public async fetchAll(): Promise<ITeam[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load mock teams: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData: RawTeamData[] = await response.json();
|
||||
return this.processTeamData(rawData);
|
||||
} catch (error) {
|
||||
console.error('Failed to load team data:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_team: ITeam): Promise<ITeam> {
|
||||
throw new Error('MockTeamRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<ITeam>): Promise<ITeam> {
|
||||
throw new Error('MockTeamRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockTeamRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
|
||||
private processTeamData(data: RawTeamData[]): ITeam[] {
|
||||
return data.map((team): ITeam => ({
|
||||
id: team.id,
|
||||
name: team.name,
|
||||
resourceIds: team.resourceIds,
|
||||
syncStatus: 'synced' as const
|
||||
}));
|
||||
}
|
||||
}
|
||||
41
src/repositories/MockViewConfigRepository.ts
Normal file
41
src/repositories/MockViewConfigRepository.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { EntityType } from '../types/CalendarTypes';
|
||||
import { ViewConfig } from '../core/ViewConfig';
|
||||
import { IApiRepository } from './IApiRepository';
|
||||
|
||||
export class MockViewConfigRepository implements IApiRepository<ViewConfig> {
|
||||
public readonly entityType: EntityType = 'ViewConfig';
|
||||
private readonly dataUrl = 'data/viewconfigs.json';
|
||||
|
||||
public async fetchAll(): Promise<ViewConfig[]> {
|
||||
try {
|
||||
const response = await fetch(this.dataUrl);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to load viewconfigs: ${response.status} ${response.statusText}`);
|
||||
}
|
||||
|
||||
const rawData = await response.json();
|
||||
// Ensure syncStatus is set on each config
|
||||
const configs: ViewConfig[] = rawData.map((config: ViewConfig) => ({
|
||||
...config,
|
||||
syncStatus: config.syncStatus || 'synced'
|
||||
}));
|
||||
return configs;
|
||||
} catch (error) {
|
||||
console.error('Failed to load viewconfigs:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
public async sendCreate(_config: ViewConfig): Promise<ViewConfig> {
|
||||
throw new Error('MockViewConfigRepository does not support sendCreate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendUpdate(_id: string, _updates: Partial<ViewConfig>): Promise<ViewConfig> {
|
||||
throw new Error('MockViewConfigRepository does not support sendUpdate. Mock data is read-only.');
|
||||
}
|
||||
|
||||
public async sendDelete(_id: string): Promise<void> {
|
||||
throw new Error('MockViewConfigRepository does not support sendDelete. Mock data is read-only.');
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue