Initial scaffold: tablet-checkin app
Staff-push guest check-in tablet. Fastify backend + React/Vite frontend, three-tier auth (staff JWT, terminal API key, kiosk cookie), NewBook integration via bookings_get/guests_update/bookings_update, pdfkit-based regcard generation, marketing opt-in with Sendy/Mailchimp adapters. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
commit
3b2e25df3f
51 changed files with 10296 additions and 0 deletions
140
frontend/src/types.ts
Normal file
140
frontend/src/types.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
export type DeviceStatus = 'idle' | 'busy'
|
||||
|
||||
export interface Device {
|
||||
device_id: string
|
||||
name: string
|
||||
status: DeviceStatus
|
||||
last_seen: string | null
|
||||
created_at: string
|
||||
}
|
||||
|
||||
export interface Terminal {
|
||||
terminal_id: string
|
||||
name: string
|
||||
created_at: string
|
||||
last_used_at: string | null
|
||||
revoked_at: string | null
|
||||
}
|
||||
|
||||
export interface CreatedTerminal extends Terminal {
|
||||
api_key: string // present only in the create response — never again
|
||||
}
|
||||
|
||||
export type CheckinStatus = 'pending' | 'complete' | 'failed'
|
||||
|
||||
export interface MarketingSyncSummary {
|
||||
provider: string
|
||||
status: 'pending' | 'success' | 'failed'
|
||||
error: string | null
|
||||
}
|
||||
|
||||
export interface Checkin {
|
||||
id: number
|
||||
booking_id: string
|
||||
guest_id: string | null
|
||||
hotel_id: string
|
||||
device_id: string | null
|
||||
device_name: string | null
|
||||
guest_name: string | null
|
||||
guest_email: string | null
|
||||
pdf_path: string | null
|
||||
opted_in: boolean
|
||||
status: CheckinStatus
|
||||
error: string | null
|
||||
submitted_at: string
|
||||
marketing_sync: MarketingSyncSummary[] | null
|
||||
}
|
||||
|
||||
export type MarketingProviderId = 'sendy' | 'mailchimp'
|
||||
|
||||
export interface SendyConfig {
|
||||
api_key?: string
|
||||
install_url?: string
|
||||
list_id?: string
|
||||
}
|
||||
|
||||
export interface MailchimpConfig {
|
||||
api_key?: string
|
||||
server_prefix?: string
|
||||
audience_id?: string
|
||||
}
|
||||
|
||||
export interface MarketingProvider {
|
||||
provider: MarketingProviderId
|
||||
active: boolean
|
||||
config: SendyConfig | MailchimpConfig
|
||||
updated_at: string
|
||||
implemented: boolean
|
||||
}
|
||||
|
||||
export interface MarketingSyncRow {
|
||||
id: number
|
||||
checkin_id: number
|
||||
provider: string
|
||||
status: 'pending' | 'success' | 'failed'
|
||||
attempts: number
|
||||
last_attempt_at: string | null
|
||||
error: string | null
|
||||
created_at: string
|
||||
booking_id: string
|
||||
guest_name: string | null
|
||||
guest_email: string | null
|
||||
}
|
||||
|
||||
export interface AppSettings {
|
||||
newbook_hotel_id: string
|
||||
regcard_custom_field_id: string
|
||||
online_checkin_complete_custom_field_id: string
|
||||
terms_and_conditions_text: string
|
||||
}
|
||||
|
||||
// ── Guest-facing token flow (routes/checkin.js) ─────────────────────────────
|
||||
export interface CheckinBooking {
|
||||
booking_id: string
|
||||
arrival: string | null
|
||||
departure: string | null
|
||||
site_name: string | null
|
||||
tariff_total: number | string | null
|
||||
nights: number | null
|
||||
}
|
||||
|
||||
export interface ExistingEmail {
|
||||
content: string
|
||||
is_relay: boolean
|
||||
}
|
||||
|
||||
export interface CheckinGuest {
|
||||
guest_id: string | null
|
||||
name: string
|
||||
address: string
|
||||
phone: string
|
||||
existing_emails: ExistingEmail[]
|
||||
car_rego: string
|
||||
}
|
||||
|
||||
export interface CheckinTokenData {
|
||||
booking: CheckinBooking
|
||||
guest: CheckinGuest
|
||||
terms_text: string
|
||||
}
|
||||
|
||||
export interface SubmitCheckinPayload {
|
||||
email: string
|
||||
car_rego: string
|
||||
opted_in: boolean
|
||||
accepted_terms: boolean
|
||||
signature_png_base64: string
|
||||
}
|
||||
|
||||
// ── Staff auth ──────────────────────────────────────────────────────────────
|
||||
export interface User {
|
||||
user_id: number
|
||||
name: string
|
||||
email: string
|
||||
is_admin: boolean
|
||||
caps: string[] // bare slugs — verify?app=tablet-checkin strips the prefix
|
||||
}
|
||||
|
||||
export function can(user: User, cap: string): boolean {
|
||||
return user.is_admin || user.caps.includes(cap)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue