- Rebrand all user-facing text to AgendaMax - Fix sidebar scrolling: card container no longer overflows html (flex h-full min-h-0) - Fix calendar toolbar hover: active buttons keep readable contrast - Sticky calendar toolbar (month/week/day always visible on scroll) - Seed guarantees 2-4 appointments per day for current week (Mon-Sat)
205 lines
4.4 KiB
TypeScript
205 lines
4.4 KiB
TypeScript
export type Role = "admin" | "owner" | "employee";
|
|
export type AppointmentStatus = "scheduled" | "completed" | "cancelled" | "no_show";
|
|
|
|
export interface Business {
|
|
id: number;
|
|
name: string;
|
|
industry: string;
|
|
currency: string;
|
|
currency_symbol: string;
|
|
phone: string | null;
|
|
address: string | null;
|
|
slug?: string | null;
|
|
plan?: string;
|
|
status?: string;
|
|
template?: string | null;
|
|
trial_ends_at?: string | null;
|
|
booking_enabled?: number | boolean;
|
|
cancel_window_hours?: number;
|
|
cancel_penalty_pct?: number;
|
|
require_deposit?: number | boolean;
|
|
deposit_pct?: number;
|
|
timezone?: string;
|
|
auto_assign_specialist?: number | boolean;
|
|
working_hours?: WorkingHoursMap | string | null;
|
|
created_at?: string;
|
|
}
|
|
|
|
export type WorkingDay = { start: string; end: string };
|
|
export type WorkingHoursMap = Record<number, WorkingDay | null>; // 1=Lun … 7=Dom
|
|
|
|
export interface User {
|
|
id: number;
|
|
business_id: number | null;
|
|
email: string;
|
|
name: string;
|
|
role: Role;
|
|
employee_id: number | null;
|
|
avatar_color: string;
|
|
}
|
|
|
|
export interface Employee {
|
|
id: number;
|
|
business_id: number;
|
|
name: string;
|
|
email: string | null;
|
|
phone: string | null;
|
|
color: string;
|
|
role: string;
|
|
active: 0 | 1;
|
|
rating: number;
|
|
hire_date: string | null;
|
|
service_ids?: number[];
|
|
specialties?: string[];
|
|
working_hours?: WorkingHoursMap | string | null;
|
|
efficiency_score?: number;
|
|
stats?: EmployeeStats;
|
|
}
|
|
|
|
export interface EmployeeStats {
|
|
appointments_total: number;
|
|
appointments_completed: number;
|
|
revenue_total: number;
|
|
avg_rating: number;
|
|
share_pct: number;
|
|
}
|
|
|
|
export interface Service {
|
|
id: number;
|
|
business_id: number;
|
|
name: string;
|
|
description: string | null;
|
|
category: string;
|
|
duration_min: number;
|
|
price: number;
|
|
color: string;
|
|
active: 0 | 1;
|
|
employee_ids?: number[];
|
|
}
|
|
|
|
export interface Client {
|
|
id: number;
|
|
business_id: number;
|
|
name: string;
|
|
email: string | null;
|
|
phone: string | null;
|
|
notes: string | null;
|
|
tags: string | null;
|
|
created_at: string;
|
|
stats?: ClientStats;
|
|
}
|
|
|
|
export interface ClientStats {
|
|
visits: number;
|
|
total_spent: number;
|
|
last_visit: string | null;
|
|
avg_ticket: number;
|
|
no_show_count: number;
|
|
}
|
|
|
|
export interface Appointment {
|
|
id: number;
|
|
business_id: number;
|
|
service_id: number;
|
|
employee_id: number;
|
|
client_id: number;
|
|
start_at: string;
|
|
end_at: string;
|
|
status: AppointmentStatus;
|
|
price: number;
|
|
notes: string | null;
|
|
created_by_user_id: number | null;
|
|
created_at: string;
|
|
updated_at: string;
|
|
// joined fields
|
|
service?: Service;
|
|
employee?: Pick<Employee, "id" | "name" | "color" | "role">;
|
|
client?: Pick<Client, "id" | "name" | "phone" | "email" | "tags">;
|
|
}
|
|
|
|
export interface Ticket {
|
|
id: number;
|
|
business_id: number;
|
|
appointment_id: number | null;
|
|
client_id: number;
|
|
employee_id: number;
|
|
service_id: number;
|
|
amount: number;
|
|
tip: number;
|
|
payment_method: string;
|
|
created_at: string;
|
|
service?: Pick<Service, "id" | "name" | "category" | "color">;
|
|
employee?: Pick<Employee, "id" | "name" | "color">;
|
|
client?: Pick<Client, "id" | "name">;
|
|
}
|
|
|
|
export interface DashboardOverview {
|
|
revenue_today: number;
|
|
revenue_range: number;
|
|
revenue_prev: number;
|
|
revenue_change_pct: number;
|
|
appts_today: number;
|
|
appts_week: number;
|
|
appts_upcoming: number;
|
|
active_clients: number;
|
|
avg_ticket: number;
|
|
cancel_rate: number;
|
|
no_show_rate: number;
|
|
completion_pct: number;
|
|
range: number;
|
|
}
|
|
|
|
export interface RankedEmployee {
|
|
employee: Pick<Employee, "id" | "name" | "color" | "role">;
|
|
appointments: number;
|
|
revenue: number;
|
|
avg_rating: number;
|
|
share_pct: number;
|
|
}
|
|
|
|
export interface RankedService {
|
|
service: Pick<Service, "id" | "name" | "category" | "color">;
|
|
count: number;
|
|
revenue: number;
|
|
}
|
|
|
|
export interface RankedClient {
|
|
client: Pick<Client, "id" | "name" | "tags" | "phone">;
|
|
visits: number;
|
|
total_spent: number;
|
|
last_visit: string | null;
|
|
}
|
|
|
|
export interface TopTicket {
|
|
ticket: Ticket;
|
|
}
|
|
|
|
export interface RevenuePoint {
|
|
date: string;
|
|
revenue: number;
|
|
appts: number;
|
|
}
|
|
|
|
export interface CategorySlice {
|
|
category: string;
|
|
revenue: number;
|
|
count: number;
|
|
}
|
|
|
|
export interface BookResponse {
|
|
appointment: {
|
|
id: number;
|
|
start_at: string;
|
|
end_at?: string;
|
|
price: number;
|
|
service_name: string;
|
|
employee_id: number;
|
|
employee_name: string;
|
|
reasons: string[];
|
|
};
|
|
business: { name: string; currency_symbol: string };
|
|
client_created: boolean;
|
|
no_show_count?: number;
|
|
risk_flag?: boolean;
|
|
}
|