Skip to content

Commit

Permalink
Notification on slot deletion complted
Browse files Browse the repository at this point in the history
  • Loading branch information
sinanptm committed Sep 22, 2024
1 parent b9b5819 commit 23c8297
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import IAppointment, { AppointmentStatus, IExtendedAppointment } from "../../ent
export default interface IAppointmentRepository {
create(appointment: IAppointment): Promise<string>;
update(appointment: IAppointment): Promise<IAppointment | null>;
updateManyBySlotIds(slotIds: string[], fields: IAppointment): Promise<void>;
updateManyBySlotIdsNotInStatuses(slotIds: string[], fields: IAppointment, notInStatuses:AppointmentStatus[]): Promise<IAppointment[] | null>;
findByDateAndSlot(appointmentDate: string, slotId: string): Promise<IAppointment | null>;
findManyByDateAndDoctorId(appointmentDate: string, doctorId: string): Promise<IAppointment[] | null>;
updateAppointmentStatusToConfirmed(appointmentId: string): Promise<void>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,13 @@ export default class AppointmentRepository implements IAppointmentRepository {
return await this.model.findOne({ appointmentDate, slotId });
}

async updateManyBySlotIds(slotIds: string[], fields: Partial<IAppointment>): Promise<void> {
await this.model.updateMany({ slotId: { $in: slotIds } }, fields);
async updateManyBySlotIdsNotInStatuses(slotIds: string[], fields: Partial<IAppointment>, notInStatuses:AppointmentStatus[]): Promise<IAppointment[] | null> {
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<void> {
await this.model.findByIdAndUpdate(appointmentId, { status: AppointmentStatus.PENDING });
}
Expand Down
8 changes: 5 additions & 3 deletions server/src/presentation/routers/slots/SlotsRoutes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
37 changes: 28 additions & 9 deletions server/src/use_case/slot/DeleteSlotUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<void> {
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) {
Expand All @@ -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);
}

Expand All @@ -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<void> {
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) {
Expand All @@ -70,4 +88,5 @@ export default class DeleteSlotUseCase {
this.validatorService.validateLength(slot.startTime, 7, 11);
});
}

}

1 comment on commit 23c8297

@vercel
Copy link

@vercel vercel bot commented on 23c8297 Sep 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.