From 23c8297f885da4343ba3d2f99996cdf9f10c33ed Mon Sep 17 00:00:00 2001 From: Sinan Date: Sun, 22 Sep 2024 14:33:46 +0530 Subject: [PATCH] Notification on slot deletion complted --- .../repositories/IAppointmentRepository.ts | 2 +- .../repositories/AppointmentRepository.ts | 7 +++- .../presentation/routers/slots/SlotsRoutes.ts | 8 ++-- server/src/use_case/slot/DeleteSlotUseCase.ts | 37 ++++++++++++++----- 4 files changed, 39 insertions(+), 15 deletions(-) diff --git a/server/src/domain/interface/repositories/IAppointmentRepository.ts b/server/src/domain/interface/repositories/IAppointmentRepository.ts index 77665ae6..4c51bfee 100644 --- a/server/src/domain/interface/repositories/IAppointmentRepository.ts +++ b/server/src/domain/interface/repositories/IAppointmentRepository.ts @@ -4,7 +4,7 @@ import IAppointment, { AppointmentStatus, IExtendedAppointment } from "../../ent export default interface IAppointmentRepository { create(appointment: IAppointment): Promise; update(appointment: IAppointment): Promise; - updateManyBySlotIds(slotIds: string[], fields: IAppointment): Promise; + updateManyBySlotIdsNotInStatuses(slotIds: string[], fields: IAppointment, notInStatuses:AppointmentStatus[]): Promise; findByDateAndSlot(appointmentDate: string, slotId: string): Promise; findManyByDateAndDoctorId(appointmentDate: string, doctorId: string): Promise; updateAppointmentStatusToConfirmed(appointmentId: string): Promise; diff --git a/server/src/infrastructure/repositories/AppointmentRepository.ts b/server/src/infrastructure/repositories/AppointmentRepository.ts index 4f7431fb..6e41c2ba 100644 --- a/server/src/infrastructure/repositories/AppointmentRepository.ts +++ b/server/src/infrastructure/repositories/AppointmentRepository.ts @@ -107,10 +107,13 @@ export default class AppointmentRepository implements IAppointmentRepository { return await this.model.findOne({ appointmentDate, slotId }); } - async updateManyBySlotIds(slotIds: string[], fields: Partial): Promise { - await this.model.updateMany({ slotId: { $in: slotIds } }, fields); + async updateManyBySlotIdsNotInStatuses(slotIds: string[], fields: Partial, notInStatuses:AppointmentStatus[]): Promise { + const appointments = await this.model.find({ slotId: { $in: slotIds }, status: { $nin: notInStatuses } }); + await this.model.updateMany({ slotId: { $in: slotIds }, status: { $nin: notInStatuses } }, fields); + return appointments } + async updateAppointmentStatusToConfirmed(appointmentId: string): Promise { await this.model.findByIdAndUpdate(appointmentId, { status: AppointmentStatus.PENDING }); } diff --git a/server/src/presentation/routers/slots/SlotsRoutes.ts b/server/src/presentation/routers/slots/SlotsRoutes.ts index cc507ae4..713288ed 100644 --- a/server/src/presentation/routers/slots/SlotsRoutes.ts +++ b/server/src/presentation/routers/slots/SlotsRoutes.ts @@ -9,17 +9,19 @@ import CreateSlotUseCase from "../../../use_case/slot/CreateSlotUseCase"; import DeleteSlotUseCase from "../../../use_case/slot/DeleteSlotUseCase"; import GetSlotUseCase from "../../../use_case/slot/GetSlotUseCase"; import UpdateSlotUseCase from "../../../use_case/slot/UpdateSlotUseCase"; +import NotificationRepository from "../../../infrastructure/repositories/NotificationRepository"; const router = express.Router(); -const slotRepository = new SlotRepository(); const tokenService = new TokenService(); const authorizeDoctor = new DoctorAuthMiddleware(tokenService); -const appointmentRepository = new AppointmentRepository(); const validatorService = new JoiService(); +const slotRepository = new SlotRepository(); +const notificationRepository = new NotificationRepository() +const appointmentRepository = new AppointmentRepository(); const createSlotUseCase = new CreateSlotUseCase(slotRepository, validatorService); -const deleteSlotUseCase = new DeleteSlotUseCase(slotRepository, appointmentRepository, validatorService); +const deleteSlotUseCase = new DeleteSlotUseCase(slotRepository, appointmentRepository, validatorService, notificationRepository); const getSlotUseCase = new GetSlotUseCase(slotRepository, appointmentRepository, validatorService); const updateSlotUseCase = new UpdateSlotUseCase(slotRepository, validatorService); diff --git a/server/src/use_case/slot/DeleteSlotUseCase.ts b/server/src/use_case/slot/DeleteSlotUseCase.ts index 618ecc64..13158def 100644 --- a/server/src/use_case/slot/DeleteSlotUseCase.ts +++ b/server/src/use_case/slot/DeleteSlotUseCase.ts @@ -5,20 +5,22 @@ import { AppointmentStatus } from "../../domain/entities/IAppointment"; import CustomError from "../../domain/entities/CustomError"; import { StatusCode } from "../../types"; import IValidatorService from "../../domain/interface/services/IValidatorService"; +import INotificationRepository from "../../domain/interface/repositories/INotificationRepository"; +import { NotificationTypes } from "../../domain/entities/INotification"; export default class DeleteSlotUseCase { constructor( private slotRepository: ISlotRepository, private appointmentRepository: IAppointmentRepository, - private validatorService: IValidatorService - ) {} + private validatorService: IValidatorService, + private notificationRepository: INotificationRepository + ) { } async deleteManyByDay(doctorId: string, slots: ISlot[], day: Days): Promise { this.validateSlotStartTimes(slots); this.validatorService.validateEnum(day, Object.values(Days)); const startTimes = slots.map((el) => el.startTime!); - const bookedSlots = await this.slotRepository.findManyByDay(doctorId, day, "booked"); if (bookedSlots?.length) { @@ -28,11 +30,10 @@ export default class DeleteSlotUseCase { .filter((id): id is string => id !== undefined); if (bookedSlotIds.length > 0) { - await this.appointmentRepository.updateManyBySlotIds(bookedSlotIds, { - status: AppointmentStatus.CANCELLED, - }); + await this.handleAppointmentUpdates(bookedSlotIds); } } + await this.slotRepository.deleteManyByDayAndTime(doctorId, day, startTimes); } @@ -53,14 +54,31 @@ export default class DeleteSlotUseCase { .filter((id): id is string => id !== undefined); if (bookedSlotIds.length > 0) { - await this.appointmentRepository.updateManyBySlotIds(bookedSlotIds, { - status: AppointmentStatus.CANCELLED, - }); + await this.handleAppointmentUpdates(bookedSlotIds); } await this.slotRepository.deleteManyByDaysAndTimes(doctorId, days, startTimes); } } + private async handleAppointmentUpdates(bookedSlotIds: string[]): Promise { + const appointments = await this.appointmentRepository.updateManyBySlotIdsNotInStatuses( + bookedSlotIds, + { status: AppointmentStatus.CANCELLED }, + [AppointmentStatus.CANCELLED, AppointmentStatus.COMPLETED] + ); + + if (appointments) { + for (const appointment of appointments) { + await this.notificationRepository.create({ + appointmentId: appointment._id, + message: `Your appointment has been canceled. If you have any questions, please contact your doctor.`, + patientId: appointment.patientId, + type: NotificationTypes.APPOINTMENT_CANCELED, + }); + } + } + } + private validateSlotStartTimes(slots: ISlot[]): void { slots.forEach((slot) => { if (!slot.startTime) { @@ -70,4 +88,5 @@ export default class DeleteSlotUseCase { this.validatorService.validateLength(slot.startTime, 7, 11); }); } + }