import { BadRequestException, Body, Controller, Post, UseGuards } from '@nestjs/common' import { plainToClass } from 'class-transformer' import { isNil } from 'lodash' import { BasicAuthorizationGuard } from '../../../guards' import { Appointment, AppointmentCancellationReasons } from '../../../models' import { BaseEventParams } from '../../../params' import { Bookings, Nutritionists, Patients } from '../domain' const APPOINTMENT_CREATED_EVENT = 'notify_appointment_created' const APPOINTMENT_CANCELLED_EVENT = 'notify_cancelled_appointment' const APPOINTMENT_TRANSFERRED_EVENT = 'notify_transferred_appointment' const APPOINTMENT_BLOCKED_EVENT = 'notify_blocked_appointment' @Controller('notification/booking') export class BookingController { constructor(private bookings: Bookings, private nutritionists: Nutritionists, private patients: Patients) {} @UseGuards(BasicAuthorizationGuard) @Post('start') async notifyAppointmentStart(): Promise { const errors = ( await Promise.allSettled([ this.bookings.notifyAppointmentStart(), this.nutritionists.notifyAppointmentsLeftToStart(), this.nutritionists.notifyPendingFoodPlanWithOneDayLeft(), ]) ) .filter(result => result.status === 'rejected') .map(result => result['reason']) if (errors.length === 1) throw errors.shift() if (errors.length > 0) throw new BadRequestException(null, errors.map(error => error.message).join(' - ')) } @UseGuards(BasicAuthorizationGuard) @Post('creation') async notifyAppointmentCreation(@Body() { event, trigger }: BaseEventParams): Promise { const appointment = plainToClass(Appointment, event.data.new) if (trigger.name !== APPOINTMENT_CREATED_EVENT) return if (isNil(event.data.new.scheduled_to)) return await Promise.all([ this.bookings.notifyAppointmentCreation(appointment), this.nutritionists.notifyAppointmentScheduled(appointment), ]) } @UseGuards(BasicAuthorizationGuard) @Post('transferred') async notifyAppointmentTransfer(@Body() { event, trigger }: BaseEventParams): Promise { const oldAppointment = plainToClass(Appointment, event.data.old) const appointment = plainToClass(Appointment, event.data.new) if (trigger.name !== APPOINTMENT_TRANSFERRED_EVENT || oldAppointment.user_id === appointment.user_id) return await this.nutritionists.notifyAppointmentTransferred(appointment, oldAppointment.user_id) } @UseGuards(BasicAuthorizationGuard) @Post('cancellation') async notifyAppointmentCancelled(@Body() { event, trigger }: BaseEventParams): Promise { const appointment = plainToClass(Appointment, event.data.new) if (trigger.name !== APPOINTMENT_CANCELLED_EVENT) return if (!isNil(event.data.old.canceled_at)) return if (isNil(appointment.canceled_at)) return if (!appointment.isCancelled) return if (appointment.cancellation_reason === AppointmentCancellationReasons.PATIENT_RESCHEDULED) return await Promise.all([ this.bookings.notifyAppointmentCancelled(appointment), this.nutritionists.notifyAppointmentCancelled(appointment), ]) } @UseGuards(BasicAuthorizationGuard) @Post('blocking') async notifyAppointmentBlocked(@Body() { event, trigger }: BaseEventParams): Promise { const appointment = plainToClass(Appointment, event.data.new) if (trigger.name !== APPOINTMENT_BLOCKED_EVENT) return if (event.data.old.state === 'blocked') return if (appointment.state !== 'blocked') return await Promise.all([ this.patients.appointmentBlocked(appointment), this.nutritionists.notifyAppointmentCancelled(appointment), ]) } @UseGuards(BasicAuthorizationGuard) @Post('return') async notifyToBookReturnAppointment(): Promise { await this.bookings.notifyToBookReturnAppointment() } }