Files
tennis-book/src/shared/contracts.ts
2026-07-16 11:03:32 +08:00

237 lines
5.6 KiB
TypeScript

export type CourtStatus = 'online' | 'maintenance' | 'login-required'
export interface CourtSummary {
id: string
name: string
shortName: string
district?: string
address?: string
distanceKm?: number
surface?: string
indoor?: boolean
accent: string
status: CourtStatus
}
export type SlotStatus = 'available' | 'limited' | 'booked' | 'blocked'
export interface BookingContact {
name?: string
phone?: string
}
export interface EnrollmentActivity {
id: string
title: string
startTime: string
endTime: string
feeCents: number
enrolledCount: number
capacity: number
participantNames: string[]
enrollmentDeadline?: string
}
export interface BookingSlot {
id: string
courtLabel: string
startTime: string
endTime: string
priceCents: number
status: SlotStatus
unavailableLabel?: string
bookedBy?: BookingContact[]
enrollment?: EnrollmentActivity
providerReference?: {
classroomUid: string
beginDatetime: string
endDatetime: string
}
sourceLabel?: string
}
export interface AvailabilityDay {
courtId: string
date: string
updatedAt: string
slots: BookingSlot[]
}
export interface AvailabilityQuery {
courtId: string
date: string
}
export interface CourtSettings {
courtId: string
visitorId?: string
visitorIdConfigured: boolean
}
export interface UpdateCourtSettingsInput {
courtId: string
visitorId?: string
}
export interface CreateBookingInput {
courtId: string
date: string
slotId?: string
slotIds?: string[]
expectedPriceCents: number
expectedStartTime?: string
expectedEndTime?: string
}
export interface CancelBookingInput {
courtId: string
orderId: string
}
export interface PendingBooking {
courtId: string
orderId: string
venueAppointmentIds: string[]
amountCents: number
courtLabel: string
startTime: string
endTime: string
expiresAt?: string
status:
| 'submitting-uncertain'
| 'pending-payment'
| 'release-uncertain'
| 'release-confirmed'
}
export interface MonitorTask {
id: string
courtId: string
targetDate?: string
startTime: string
endTime: string
enabled: boolean
createdAt: string
lastCheckedAt?: string
lastError?: string
availableCount: number
stats: MonitorTaskStats
autoBooking: MonitorAutoBookingState
}
export type MonitorAutoBookingStatus =
| 'disabled'
| 'armed'
| 'attempting'
| 'pending-payment'
| 'blocked'
| 'stopped'
export interface MonitorAutoBookingState {
enabled: boolean
status: MonitorAutoBookingStatus
attemptCount: number
lastAttemptAt?: string
lastError?: string
orderId?: string
bookedAt?: string
bookedDate?: string
bookedSlotLabel?: string
}
export interface MonitorTaskStats {
totalChecks: number
successfulChecks: number
partialFailureChecks: number
failedChecks: number
alertsSent: number
availableObservations: number
lastAlertAt?: string
}
export interface MonitorDailyStats {
date: string
checks: number
failedChecks: number
alerts: number
availableObservations: number
maxAvailable: number
}
export interface MonitorTaskLog {
id: string
occurredAt: string
type: 'check' | 'alert' | 'error' | 'lifecycle' | 'booking'
level: 'info' | 'warning' | 'success'
message: string
availableCount?: number
checkedDateCount?: number
failedDates?: string[]
}
export interface MonitorTaskDetail {
task: MonitorTask
dailyStats: MonitorDailyStats[]
logs: MonitorTaskLog[]
}
export interface CreateMonitorTaskInput {
courtId: string
targetDate?: string
startTime: string
endTime: string
autoBookingEnabled?: boolean
}
export interface MonitorAlert {
taskId: string
courtId: string
targetDate: string
startTime: string
endTime: string
slotLabels: string[]
occurredAt: string
}
export interface TennisBookApi {
listCourts(): Promise<CourtSummary[]>
getAvailability(query: AvailabilityQuery): Promise<AvailabilityDay>
getCourtSettings(courtId: string): Promise<CourtSettings>
updateCourtSettings(input: UpdateCourtSettingsInput): Promise<CourtSettings>
createBooking(input: CreateBookingInput): Promise<PendingBooking>
cancelBooking(input: CancelBookingInput): Promise<void>
getPendingBooking(courtId: string): Promise<PendingBooking | null>
listMonitorTasks(): Promise<MonitorTask[]>
getMonitorTaskDetail(taskId: string): Promise<MonitorTaskDetail>
createMonitorTask(input: CreateMonitorTaskInput): Promise<MonitorTask>
setMonitorTaskEnabled(taskId: string, enabled: boolean): Promise<MonitorTask>
setMonitorTaskAutoBooking(taskId: string, enabled: boolean): Promise<MonitorTask>
deleteMonitorTask(taskId: string): Promise<void>
takeMonitorAlerts(): Promise<MonitorAlert[]>
listUnreadMonitorAlerts(): Promise<MonitorAlert[]>
acknowledgeMonitorAlerts(taskId?: string): Promise<void>
onMonitorAlert(listener: () => void): () => void
onShowMonitorTask(listener: (taskId: string) => void): () => void
}
export const IPC_CHANNELS = {
listCourts: 'courts:list',
getAvailability: 'courts:availability',
getCourtSettings: 'court-settings:get',
updateCourtSettings: 'court-settings:update',
createBooking: 'bookings:create',
cancelBooking: 'bookings:cancel',
getPendingBooking: 'bookings:pending',
listMonitorTasks: 'monitors:list',
getMonitorTaskDetail: 'monitors:detail',
createMonitorTask: 'monitors:create',
setMonitorTaskEnabled: 'monitors:set-enabled',
setMonitorTaskAutoBooking: 'monitors:set-auto-booking',
deleteMonitorTask: 'monitors:delete',
takeMonitorAlerts: 'monitors:take-alerts',
listUnreadMonitorAlerts: 'monitors:list-unread-alerts',
acknowledgeMonitorAlerts: 'monitors:acknowledge-alerts',
monitorAlert: 'monitors:alert',
showMonitorTask: 'monitors:show-task'
} as const