Skip to main content
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',
}
The appointment is scheduled and awaiting the scheduled date. Both clients and specialists can view and manage pending appointments.

Creating appointments

Clients create appointments through a multi-step booking form:
1

Select specialty

Choose the service needed (e.g., haircut, beard trim, coloring)
2

Select specialist

Pick a preferred specialist or let the system suggest one based on availability
3

Choose date and time

Select from available time slots based on the specialist’s schedule
4

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:
specialty.model.ts:1-7
export interface Specialty {
  id: string;
  name: string;
  description: string;
  active: boolean;
}

Diagnosis and ratings

Adding a diagnosis

Specialists can add diagnoses to completed appointments:
diagnosis.model.ts:1-4
export interface Diagnosis {
  details: string;
  anotations?: string;
}

Rating appointments

Clients can rate completed appointments:
rating.model.ts:1-6
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

Build docs developers (and LLMs) love