Redesigns booking and resource architecture
Fundamentally refactors booking system to support: - Split-resource bookings - Service-level resource assignment - Clear separation between booking and calendar events Introduces new interfaces and type definitions to model complex booking scenarios, enabling more flexible and accurate resource management Improves type safety by removing ambiguous type annotations
This commit is contained in:
parent
f86ae09ec3
commit
a360fad265
7 changed files with 1557 additions and 2 deletions
63
src/types/BookingTypes.ts
Normal file
63
src/types/BookingTypes.ts
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* Booking entity - represents customer service bookings ONLY
|
||||
*
|
||||
* IMPORTANT ARCHITECTURE:
|
||||
* - Booking = Customer + Services (business container)
|
||||
* - Booking does NOT have start/end - timing is on CalendarEvent
|
||||
* - Booking does NOT have resourceId - resources assigned per service
|
||||
* - One booking can have multiple CalendarEvents (split sessions or resources)
|
||||
* - Booking can exist without events (queued/pending state)
|
||||
* - Vacation/break/meeting are NOT bookings - only CalendarEvents
|
||||
*
|
||||
* Resource Assignment:
|
||||
* - Resources are assigned at SERVICE level (IBookingService.resourceId)
|
||||
* - One service can be performed by one resource
|
||||
* - Multiple services can be performed by different resources
|
||||
* - Example: Hårvask by Student, Bundfarve by Master (same booking, 2 resources)
|
||||
*
|
||||
* Matches backend Booking table structure
|
||||
*/
|
||||
export interface IBooking {
|
||||
id: string;
|
||||
customerId: string; // REQUIRED - booking is always for a customer
|
||||
status: BookingStatus;
|
||||
createdAt: Date;
|
||||
|
||||
// Services (REQUIRED - booking always has services)
|
||||
services: IBookingService[];
|
||||
|
||||
// Payment
|
||||
totalPrice?: number; // Can differ from sum of service prices
|
||||
|
||||
// Metadata
|
||||
tags?: string[];
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* CalendarEventType - Used by ICalendarEvent.type
|
||||
* Note: Only 'customer' events have associated IBooking
|
||||
* Other types (vacation/break/meeting/blocked) are CalendarEvents without bookings
|
||||
*/
|
||||
export type CalendarEventType =
|
||||
| 'customer' // Customer appointment (HAS booking)
|
||||
| 'vacation' // Vacation/time off (NO booking)
|
||||
| 'break' // Lunch/break (NO booking)
|
||||
| 'meeting' // Meeting (NO booking)
|
||||
| 'blocked'; // Blocked time (NO booking)
|
||||
|
||||
export type BookingStatus =
|
||||
| 'created' // AftaleOprettet
|
||||
| 'arrived' // Ankommet
|
||||
| 'paid' // Betalt
|
||||
| 'noshow' // Udeblevet
|
||||
| 'cancelled'; // Aflyst
|
||||
|
||||
export interface IBookingService {
|
||||
serviceId: string;
|
||||
serviceName: string; // Denormalized for display
|
||||
baseDuration: number; // Minutes (from Service.duration)
|
||||
basePrice: number; // From Service.basePrice
|
||||
customPrice?: number; // Override if different from basePrice
|
||||
resourceId: string; // Resource who performs THIS service
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
// Calendar type definitions
|
||||
import { CalendarEventType } from './BookingTypes';
|
||||
|
||||
// Time period view types (how much time to display)
|
||||
export type ViewPeriod = 'day' | 'week' | 'month';
|
||||
|
|
@ -20,10 +21,15 @@ export interface ICalendarEvent {
|
|||
description?: string;
|
||||
start: Date;
|
||||
end: Date;
|
||||
type: string; // Flexible event type - can be any string value
|
||||
type: CalendarEventType; // Event type - only 'customer' has associated booking
|
||||
allDay: boolean;
|
||||
syncStatus: SyncStatus;
|
||||
|
||||
// References (denormalized for IndexedDB performance)
|
||||
bookingId?: string; // Reference to booking (only if type = 'customer')
|
||||
resourceId?: string; // Resource who owns this time slot
|
||||
customerId?: string; // Denormalized from Booking.customerId
|
||||
|
||||
recurringId?: string;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import { IResource } from './ResourceTypes';
|
||||
|
||||
/**
|
||||
* Column information container
|
||||
* Contains both identifier and actual data for a column
|
||||
*/
|
||||
export interface IColumnInfo {
|
||||
identifier: string; // "2024-11-13" (date mode) or "person-1" (resource mode)
|
||||
data: Date | any; // Date for date-mode, IResource for resource-mode
|
||||
data: Date | IResource; // Date for date-mode, IResource for resource-mode
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
11
src/types/CustomerTypes.ts
Normal file
11
src/types/CustomerTypes.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Customer entity
|
||||
* Matches backend Customer table structure
|
||||
*/
|
||||
export interface ICustomer {
|
||||
id: string;
|
||||
name: string;
|
||||
phone: string;
|
||||
email?: string;
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
21
src/types/ResourceTypes.ts
Normal file
21
src/types/ResourceTypes.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
/**
|
||||
* Resource entity - represents people, rooms, equipment, etc.
|
||||
* Matches backend Resource table structure
|
||||
*/
|
||||
export interface IResource {
|
||||
id: string; // Primary key (e.g., "EMP001", "ROOM-A")
|
||||
name: string; // Machine name (e.g., "karina.knudsen")
|
||||
displayName: string; // Human-readable name (e.g., "Karina Knudsen")
|
||||
type: ResourceType; // Resource category
|
||||
avatarUrl?: string; // Avatar/icon URL (e.g., "/avatars/karina.jpg")
|
||||
color?: string; // Color for visual distinction in calendar
|
||||
isActive?: boolean; // Whether resource is currently active
|
||||
metadata?: Record<string, any>; // Flexible extension point
|
||||
}
|
||||
|
||||
export type ResourceType =
|
||||
| 'person' // Employees, team members
|
||||
| 'room' // Meeting rooms, offices
|
||||
| 'equipment' // Shared equipment, tools
|
||||
| 'vehicle' // Company vehicles
|
||||
| 'custom'; // User-defined types
|
||||
Loading…
Add table
Add a link
Reference in a new issue