import { Injectable } from '@nestjs/common' import { isNil } from 'lodash' import { MailService, MessagingService, PushNotificationTemplate } from '../../../services' import { Appointment, BioimpedanceAnalysis, Patient, User } from '../../../models' import { AppointmentRepository, PatientRepository, UserRepository } from '../../../repositories' import { NotFoundError, UserNotFoundError } from '../../../errors' import { TranslateNotificationsHelper } from '../i18n' const NOTIFY_NUTRI_UNAVAILABLE_CHANGE = 'nutri_unavailable_change' const NOTIFY_NUTRI_UNAVAILABLE_CANCEL = 'nutri_unavailable_cancel' const NOTIFY_NUTRI_CANCEL = 'nutri_cancel' const BIOIMPEDANCE_ANALYSIS_FINISHED = 'bioimpedance_analysis_finished' type NotifyArgs = { patient: Patient oldNutri?: User newNutri?: User template: string emailTemplate?: string } @Injectable() export class Patients { constructor( private readonly messagingService: MessagingService, private readonly userRepository: UserRepository, private readonly patientRepository: PatientRepository, private readonly appointmentRepository: AppointmentRepository, private readonly mailService: MailService, private readonly translator: TranslateNotificationsHelper, ) {} async nutriChanged(patient: Patient, oldNutriId: string, newNutriId: string): Promise { if (isNil(oldNutriId)) return const oldNutri = await this.getNutritionist(oldNutriId) if (isNil(oldNutri.inactivated_at)) return if (await this.appointmentRepository.existsScheduledAppointmentBy(patient.id, oldNutriId)) return this.notifyNutriUnavailableChange(patient, oldNutri, await this.getNutritionist(newNutriId)) } async appointmentBlocked(appointment: Appointment): Promise { const [patient, nutri] = await Promise.all([ this.getPatient(appointment.patient_id), this.getNutritionist(appointment.user_id), ]) if (!isNil(nutri.inactivated_at)) return this.notifyAppointmentUnavailableBlocked(patient, nutri) await this.notifyAppointmentBlocked(patient) } async bioimpedanceAnalysisFinished(bioimpedanceAnalysis: BioimpedanceAnalysis): Promise { const patient = await this.getPatient(bioimpedanceAnalysis.patient_id) if (!patient) throw new NotFoundError('Patient not found') await this.notify({ patient, template: BIOIMPEDANCE_ANALYSIS_FINISHED, }) } private async notifyNutriUnavailableChange(patient: Patient, oldNutri: User, newNutri: User): Promise { await this.notify({ patient, oldNutri, newNutri, template: NOTIFY_NUTRI_UNAVAILABLE_CHANGE, }) } private async notifyAppointmentUnavailableBlocked(patient: Patient, nutri: User): Promise { await this.notify({ patient, oldNutri: nutri, template: NOTIFY_NUTRI_UNAVAILABLE_CANCEL, }) } private async notifyAppointmentBlocked(patient: Patient): Promise { await this.notify({ patient, template: NOTIFY_NUTRI_CANCEL, }) } private async notify({ patient, oldNutri, newNutri, template }: NotifyArgs): Promise { const pushTemplate = this.translator.get( patient.country_code, `pushes.${template}` as any, ) if (!template) throw new Error('Push notification template not found') const notifiesMethods = [] notifiesMethods.push(this.messagingService.sendPushNotificationByTemplate(pushTemplate, patient.device_id)) const emailTemplate = this.translator.get(patient.country_code, `email_templates.${template}` as any) if (!emailTemplate) throw new Error('Email notification template not found') notifiesMethods.push( this.mailService.send({ to: patient.email, templateId: emailTemplate, dynamicTemplateData: { nome: patient.name, nutricionista: oldNutri?.name, nutricionista1: oldNutri?.name, nutricionista2: newNutri?.name, }, }), ) await Promise.all(notifiesMethods) } private async getNutritionist(id: string): Promise { const nutri = await this.userRepository.get(id) if (!nutri) throw new UserNotFoundError(`id: ${id}`) return nutri } private async getPatient(id: string): Promise { const patient = await this.patientRepository.get(id) if (!patient) throw new UserNotFoundError(`id: ${id}`) return patient } }