Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -414,7 +414,7 @@ model Slots {
mentor Mentor @relation(fields: [mentorId], references: [userId])
lockedBy String
user User @relation(fields: [lockedBy], references: [id])
date DateTime
date DateTime @db.Date
startTime Int
endTime Int
expiresAt DateTime
Expand Down
19 changes: 15 additions & 4 deletions src/application/useCases/booking/CreateBookingIntent.usecase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { IPaymentService } from "@application/ports/services/IPaymentServic
import type { ICreateBookingIntentUsecase } from "@application/ports/usecase/booking/ICreateBookingIntent.usecase";
import type { CreateOrderResponse } from "@application/types/PaymentService.types";
import { TYPES } from "@config/DI-container/TYPES";
import { ConflictError } from "@domain/errors/ConflictError";
import { DayOfWeekIndex } from "@domain/mentor/entities/availability.entity";
import { inject, injectable } from "inversify";
@injectable()
Expand All @@ -31,17 +32,26 @@ export class CreateBookingIntentUsecase implements ICreateBookingIntentUsecase {
);

if (!availability) {
throw new Error("Requested time slot is not available.");
throw new ConflictError("Mentor is unavailable for the requested time");
}
console.log("date", data.date.toLocaleDateString("en-CA"));
// store the day with same time to avoid issues with data comparison
const date = new Date(
`${data.date.toLocaleDateString("en-CA")}T00:00:00.000Z`,
);
console.log(date);

const slot = await this._slotRepository.checkOverlap(
data.mentorId,
data.date,
date,
data.startTime,
data.endTime,
);

console.log("slot", slot);
if (slot) {
throw new Error("Requested time slot overlaps with an existing booking.");
throw new ConflictError(
"Requested time slot overlaps with an existing booking.",
);
}

const order = await this._paymentService.createOrder({
Expand All @@ -50,6 +60,7 @@ export class CreateBookingIntentUsecase implements ICreateBookingIntentUsecase {
});
const finalData = {
...data,
date,
orderId: order.orderId,
provider: this._paymentService.getPaymentProviderName(),
};
Expand Down
12 changes: 12 additions & 0 deletions src/domain/errors/ConflictError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { DomainError } from "./DomainError.abstract";
import { DomainErrorCode } from "./DomainErrorCode";

export class ConflictError extends DomainError {
serialize(): { message: string; field?: string }[] {
return [{ message: this.message }];
}

constructor(message: string = "Resource already exists") {
super(DomainErrorCode.CONFLICT, message);
}
}
1 change: 1 addition & 0 deletions src/domain/errors/DomainErrorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export const DomainErrorCode = {
BAD_REQUEST: "BAD_REQUEST",
UNAUTHORIZED: "UNAUTHORIZED",
FORBIDDEN: "FORBIDDEN",
CONFLICT: "CONFLICT",
} as const;

// This extracts the values into a strict TypeScript type
Expand Down
1 change: 1 addition & 0 deletions src/presentation/constants/httpStatusForErrorCode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ const errorCodeToHttpStatusMap: Record<ErrorCode, HTTPSTATUSTYPE> = {
[DomainErrorCode.NOT_FOUND]: HTTPSTATUS.NOT_FOUND,
[DomainErrorCode.ALREADY_EXISTS]: HTTPSTATUS.CONFLICT,
[AppErrorCode.INVALID_CREDENTIALS]: HTTPSTATUS.BAD_REQUEST,
[DomainErrorCode.CONFLICT]: HTTPSTATUS.CONFLICT,
};

export const getHttpStatusForErrorCode = (code: ErrorCode): HTTPSTATUSTYPE => {
Expand Down