The appointment system is the core feature of BarberApp, allowing clients to book appointments with specialists and specialists to manage their schedules.
Appointment model
Appointments contain comprehensive information about the booking:
appointment.model.ts:4-20
export interface Appointment {
id : string ;
clientId : string ;
specialistId : string ;
specialistFirstName : string ,
specialistLastName : string ,
clientFirstName : string ,
clientLastName : string ,
status : AppointmentStatus ;
date : Date ;
specialty : Specialty ;
creationDate : Date ;
cancellationReason ?: string ;
canceledBy ?: UserRoles ;
diagnosis ?: Diagnosis ;
rating ?: Rating ;
}
Appointment statuses
Every appointment has one of three statuses:
appointment-status.enum.ts:1-5
export enum AppointmentStatus {
PENDING = 'pending' ,
CANCELED = 'canceled' ,
COMPLETED = 'completed' ,
}
Pending
Canceled
Completed
The appointment is scheduled and awaiting the scheduled date. Both clients and specialists can view and manage pending appointments.
The appointment was canceled by either the client or specialist. The canceledBy field indicates who canceled it, and cancellationReason stores the reason.
The appointment took place. Specialists can add a diagnosis, and clients can rate the service.
Creating appointments
Clients create appointments through a multi-step booking form:
Select specialty
Choose the service needed (e.g., haircut, beard trim, coloring)
Select specialist
Pick a preferred specialist or let the system suggest one based on availability
Choose date and time
Select from available time slots based on the specialist’s schedule
Confirm appointment
Review all details and confirm the booking
Booking flow implementation
The RequestAppointmentFormComponent manages the step-by-step booking process:
request-appointment-form.component.ts:51-75
public steps : Step [] = [
{
number: 1 ,
title: 'Elegir Servicio' ,
description: 'Seleccioná el servicio que necesites.' ,
},
{
number: 2 ,
title: 'Elegir Especialista' ,
description:
'Podés elegir al especialista en caso de tener alguna preferencia.' ,
},
{
number: 3 ,
title: 'Elegir Fecha y Hora' ,
description:
'Seleccioná la fecha y hora del turno, basado en la disponibilidad actual.' ,
},
{
number: 4 ,
title: 'Confirmar Turno' ,
description:
'Revisá la información del turno antes de confirmar la solicitud.' ,
},
];
Creating an appointment
The AppointmentFacade handles appointment creation:
appointment.facade.ts:42-78
async createAppointment (
specialty : Specialty ,
specialist : Specialist ,
date : Date
): Promise < Appointment | null > {
this._loading.set(true);
this._error.set(null);
const client = this . authFacade . user ();
if (! client || client.role !== 'client' ) {
this . _error . set ( 'Usuario no autenticado, o no es cliente.' );
this . _loading . set ( false );
return null ;
}
const newAppointment: Appointment = {
id: AutoId . newId (),
clientId: client . id ,
specialistId: specialist . id ,
specialistFirstName: specialist . firstName ,
specialistLastName: specialist . lastName ,
clientFirstName: client . firstName ,
clientLastName: client . lastName ,
specialty ,
date ,
status: AppointmentStatus . PENDING ,
creationDate: new Date (),
};
await this . appointmentService . create ( newAppointment );
const updatedAppointments = [ ... this . _appointments (), newAppointment ]. sort (
( a , b ) => a . date . getTime () - b . date . getTime ()
);
this . _appointments . set ( updatedAppointments );
this . _loading . set ( false );
return newAppointment ;
}
Only authenticated clients can create appointments. The system automatically populates client and specialist information.
Loading appointments
Appointments are loaded differently based on user role:
appointment.facade.ts:80-105
async loadUserAppointments (): Promise < void > {
console.log( 'loadUserAppointments Started' );
const user = this.authFacade.user();
if (!user) {
this._appointments.set([]);
return;
}
this._loading.set(true);
this._error.set(null);
try {
let appointments: Appointment [] = [];
if ( user . role === UserRoles . CLIENT ) {
console.log(user.id)
appointments = await this . appointmentService . getForClient ( user . id );
} else if ( user . role === UserRoles . SPECIALIST ) {
appointments = await this . appointmentService . getForSpecialist ( user . id );
}
this . _appointments . set ( appointments );
} catch ( err : any ) {
this . _error . set ( err . message || 'Error al obtener los turnos' );
} finally {
this . _loading . set ( false );
}
}
Managing appointments
Updating appointments
Both clients and specialists can update appointments:
appointment.facade.ts:129-151
async updateAppointment (
id : string ,
updates : Partial < Appointment >
): Promise < void > {
this._loading.set(true);
this._error.set(null);
try {
await this . appointmentService . update ({ id , ... updates });
const currentAppointments = this . _appointments ();
const updatedAppointments = currentAppointments . map (( app ) =>
app . id === id ? { ... app , ... updates } : app
);
this . _appointments . set ( updatedAppointments );
if ( this . _selectedAppointment ()?. id === id ) {
this . _selectedAppointment . update (( app ) => ({ ... app ! , ... updates }));
}
} catch (err: any) {
this._error. set (err.message || 'Error al actualizar el turno' );
} finally {
this . _loading . set ( false );
}
}
Filtering by status
Specialists can filter appointments by status:
appointment.facade.ts:168-185
async getSpecialistAppointmentsByStatus (
specialistId : string ,
statuses : AppointmentStatus []
): Promise < Appointment [] > {
this._loading.set(true);
this._error.set(null);
try {
return await this . appointmentService . getForSpecialistByStatuses (
specialistId ,
statuses
);
} catch (err: any) {
this._error. set (err.message || 'Error al obtener los turnos por estado' );
return [];
} finally {
this._loading.set(false);
}
}
Specialty selection
Specialties define the type of service:
export interface Specialty {
id : string ;
name : string ;
description : string ;
active : boolean ;
}
Diagnosis and ratings
Adding a diagnosis
Specialists can add diagnoses to completed appointments:
export interface Diagnosis {
details : string ;
anotations ?: string ;
}
Rating appointments
Clients can rate completed appointments:
export interface Rating {
score : AllowedScore ;
comment ?: string ;
}
export type AllowedScore = 1 | 2 | 3 | 4 | 5 ;
Diagnoses can only be added by specialists, and ratings can only be submitted by clients for completed appointments.
Date range queries
The system supports querying appointments by date range:
For specialists
appointment.facade.ts:187-206
async getAppointmentsBySpecialistAndDateRange (
specialistId : string ,
startDate : Date ,
endDate : Date
): Promise < Appointment [] > {
this._loading.set(true);
this._error.set(null);
try {
return await this . appointmentService . getAppointmentsBySpecialistAndDateRange (
specialistId ,
startDate ,
endDate
);
} catch (err: any) {
this._error. set (err.message || 'Error al obtener los turnos del especialista' );
return [];
} finally {
this._loading.set(false);
}
}
For clients
appointment.facade.ts:208-227
async getAppointmentsByClientAndDateRange (
clientId : string ,
startDate : Date ,
endDate : Date
): Promise < Appointment [] > {
this._loading.set(true);
this._error.set(null);
try {
return await this . appointmentService . getAppointmentsByClientAndDateRange (
clientId ,
startDate ,
endDate
);
} catch (err: any) {
this._error. set (err.message || 'Error al obtener los turnos del cliente' );
return [];
} finally {
this._loading.set(false);
}
}
Next steps
Client Dashboard Learn how clients manage their appointments
Specialist Dashboard Discover specialist appointment management tools