You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
185 lines
4.9 KiB
TypeScript
185 lines
4.9 KiB
TypeScript
/**
|
|
* Court Management Types
|
|
*
|
|
* Types for club profile and court inventory CRUD operations.
|
|
*/
|
|
|
|
export interface Court {
|
|
court_id: number;
|
|
name: string;
|
|
sport_variation_id?: number; // For backward compatibility (deprecated)
|
|
sport_variation?: {
|
|
sport_variation_id: number;
|
|
name: string;
|
|
slug: string;
|
|
sport: {
|
|
sport_id: number;
|
|
name: string;
|
|
slug: string;
|
|
};
|
|
};
|
|
created_at: string; // ISO 8601 timestamp
|
|
updated_at: string; // ISO 8601 timestamp
|
|
}
|
|
|
|
export interface CourtRequest {
|
|
name: string;
|
|
sport_variation_id: number;
|
|
}
|
|
|
|
export interface SportVariation {
|
|
sport_variation_id: number;
|
|
name: string;
|
|
slug: string;
|
|
}
|
|
|
|
export interface Sport {
|
|
sport_id: number;
|
|
name: string;
|
|
slug: string;
|
|
logo_url: string | null;
|
|
variations: SportVariation[];
|
|
}
|
|
|
|
export interface SportsResponse {
|
|
sports: Sport[];
|
|
}
|
|
|
|
export interface CourtDependencies {
|
|
court_id: number;
|
|
can_delete: boolean;
|
|
dependencies: {
|
|
slot_definitions: number;
|
|
slot_instances_future: number;
|
|
slot_instances_booked: number;
|
|
};
|
|
}
|
|
|
|
export interface ClubProfileSettings {
|
|
address?: {
|
|
line_1?: string;
|
|
line_2?: string;
|
|
city?: string;
|
|
postal_code?: string;
|
|
country?: string;
|
|
};
|
|
contact?: {
|
|
phone?: string;
|
|
email?: string;
|
|
website?: string;
|
|
};
|
|
// Other future settings can be added here
|
|
[key: string]: any; // Allow arbitrary JSONB data
|
|
}
|
|
|
|
export interface ClubProfile {
|
|
club_id: number;
|
|
name: string;
|
|
timezone: string; // IANA timezone
|
|
settings?: ClubProfileSettings;
|
|
created_at: string; // ISO 8601 timestamp
|
|
updated_at: string; // ISO 8601 timestamp
|
|
}
|
|
|
|
export interface ClubProfileUpdateRequest {
|
|
name?: string;
|
|
timezone?: string;
|
|
settings?: ClubProfileSettings;
|
|
}
|
|
|
|
export interface CourtError {
|
|
type: string;
|
|
title: string;
|
|
status: number;
|
|
detail: string;
|
|
code: string;
|
|
errors?: ValidationError[];
|
|
dependencies?: {
|
|
slot_definitions: number;
|
|
upcoming_bookings: number;
|
|
};
|
|
}
|
|
|
|
export interface ValidationError {
|
|
field: string;
|
|
message: string;
|
|
}
|
|
|
|
/**
|
|
* IANA Timezone list (common timezones)
|
|
* Full list can be expanded as needed
|
|
*/
|
|
export const COMMON_TIMEZONES = [
|
|
{ value: 'Europe/London', label: 'London (GMT/BST)' },
|
|
{ value: 'Europe/Paris', label: 'Paris (CET/CEST)' },
|
|
{ value: 'Europe/Berlin', label: 'Berlin (CET/CEST)' },
|
|
{ value: 'Europe/Madrid', label: 'Madrid (CET/CEST)' },
|
|
{ value: 'Europe/Rome', label: 'Rome (CET/CEST)' },
|
|
{ value: 'Europe/Amsterdam', label: 'Amsterdam (CET/CEST)' },
|
|
{ value: 'Europe/Brussels', label: 'Brussels (CET/CEST)' },
|
|
{ value: 'Europe/Vienna', label: 'Vienna (CET/CEST)' },
|
|
{ value: 'Europe/Zurich', label: 'Zurich (CET/CEST)' },
|
|
{ value: 'Europe/Stockholm', label: 'Stockholm (CET/CEST)' },
|
|
{ value: 'Europe/Copenhagen', label: 'Copenhagen (CET/CEST)' },
|
|
{ value: 'Europe/Oslo', label: 'Oslo (CET/CEST)' },
|
|
{ value: 'Europe/Helsinki', label: 'Helsinki (EET/EEST)' },
|
|
{ value: 'Europe/Athens', label: 'Athens (EET/EEST)' },
|
|
{ value: 'Europe/Istanbul', label: 'Istanbul (TRT)' },
|
|
{ value: 'Europe/Moscow', label: 'Moscow (MSK)' },
|
|
{ value: 'America/New_York', label: 'New York (EST/EDT)' },
|
|
{ value: 'America/Chicago', label: 'Chicago (CST/CDT)' },
|
|
{ value: 'America/Denver', label: 'Denver (MST/MDT)' },
|
|
{ value: 'America/Los_Angeles', label: 'Los Angeles (PST/PDT)' },
|
|
{ value: 'America/Toronto', label: 'Toronto (EST/EDT)' },
|
|
{ value: 'America/Vancouver', label: 'Vancouver (PST/PDT)' },
|
|
{ value: 'America/Mexico_City', label: 'Mexico City (CST/CDT)' },
|
|
{ value: 'America/Sao_Paulo', label: 'São Paulo (BRT/BRST)' },
|
|
{ value: 'America/Buenos_Aires', label: 'Buenos Aires (ART)' },
|
|
{ value: 'Asia/Dubai', label: 'Dubai (GST)' },
|
|
{ value: 'Asia/Kolkata', label: 'Kolkata (IST)' },
|
|
{ value: 'Asia/Bangkok', label: 'Bangkok (ICT)' },
|
|
{ value: 'Asia/Singapore', label: 'Singapore (SGT)' },
|
|
{ value: 'Asia/Hong_Kong', label: 'Hong Kong (HKT)' },
|
|
{ value: 'Asia/Shanghai', label: 'Shanghai (CST)' },
|
|
{ value: 'Asia/Tokyo', label: 'Tokyo (JST)' },
|
|
{ value: 'Asia/Seoul', label: 'Seoul (KST)' },
|
|
{ value: 'Australia/Sydney', label: 'Sydney (AEDT/AEST)' },
|
|
{ value: 'Australia/Melbourne', label: 'Melbourne (AEDT/AEST)' },
|
|
{ value: 'Australia/Brisbane', label: 'Brisbane (AEST)' },
|
|
{ value: 'Pacific/Auckland', label: 'Auckland (NZDT/NZST)' },
|
|
];
|
|
|
|
/**
|
|
* Helper to validate email format
|
|
*/
|
|
export function isValidEmail(email: string): boolean {
|
|
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
return emailRegex.test(email);
|
|
}
|
|
|
|
/**
|
|
* Helper to validate URL format
|
|
*/
|
|
export function isValidUrl(url: string): boolean {
|
|
try {
|
|
new URL(url);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper to format timestamp for display
|
|
*/
|
|
export function formatTimestamp(isoString: string): string {
|
|
const date = new Date(isoString);
|
|
return date.toLocaleString('en-GB', {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
});
|
|
}
|