diff --git a/server/src/calendar/calendar.service.ts b/server/src/calendar/calendar.service.ts index 6f502fe..03b88e2 100644 --- a/server/src/calendar/calendar.service.ts +++ b/server/src/calendar/calendar.service.ts @@ -4,7 +4,14 @@ import { NotFoundException, } from '@nestjs/common'; import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; -import { Repository, Between, IsNull, DataSource, In } from 'typeorm'; +import { + Repository, + Between, + IsNull, + DataSource, + In, + FindManyOptions, +} from 'typeorm'; import { RRule } from 'rrule'; // Corrected import import { Event } from '../entity/event.entity'; @@ -16,6 +23,7 @@ import { Booking } from '../entity/booking.entity'; import { CancelBookingDto } from './dto/cancel-booking.dto'; import { CalendarCreateBookingDto } from './dto/create-booking.dto'; import { EventType } from '../entity/event-type.entity'; +import { CalendarGetBookingDto } from './dto/calendar.get.booking.dto'; // --- Type-Safe Maps --- const frequencyMap: Record = { @@ -593,10 +601,35 @@ export class CalendarService { async getBookings( userId: number, eventId: number, - startTime: Date, + queryParams: CalendarGetBookingDto, ): Promise { - console.info('getBookings', userId, eventId, startTime); + console.info('getBookings', userId, eventId); await Promise.resolve(); + const { page = 1, limit = 0, sortBy, order } = queryParams; + const findOptions: FindManyOptions = {}; + const paginated = limit > 0; + if (paginated) { + findOptions.skip = (page - 1) * limit; + findOptions.take = limit; + } + if (sortBy && order) { + findOptions.order = { [sortBy]: order }; + } + const [data, totalItems] = + await this.bookingRepository.findAndCount(findOptions); + if (!paginated) { + return { data, total: data.length }; + } + return { + data, + meta: { + totalItems, + itemCount: data.length, + itemsPerPage: limit, + totalPages: Math.ceil(totalItems / limit), + currentPage: page, + }, + }; // const booking = await this.bookingRepository.findOneBy({ id: bookingId }); // if (!booking) { // throw new NotFoundException(`Booking with ID ${bookingId} not found.`); diff --git a/server/src/calendar/dto/calendar.get.booking.dto.ts b/server/src/calendar/dto/calendar.get.booking.dto.ts new file mode 100644 index 0000000..55b92d2 --- /dev/null +++ b/server/src/calendar/dto/calendar.get.booking.dto.ts @@ -0,0 +1,16 @@ +import { + IsOptional, + IsString, + IsNumber, + IsIn, + IsBoolean, +} from 'class-validator'; +import { Type } from 'class-transformer'; + +export class CalendarGetBookingDto { + @IsOptional() @Type(() => Number) @IsNumber() page?: number; + @IsOptional() @Type(() => Number) @IsNumber() limit?: number; + @IsOptional() @IsString() sortBy?: string; + @IsOptional() @IsIn(['ASC', 'DESC']) order?: 'ASC' | 'DESC'; + @IsString() startTime: string; +} diff --git a/server/src/types.ts b/server/src/types.ts index d25a9d8..63bbab6 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -18,3 +18,15 @@ export interface UserPayload { username: string; roles: string[]; } +export interface PaginatedResponse { + data: T[]; + meta: PaginatedResponseMeta; +} + +export interface PaginatedResponseMeta { + totalItems: number; + itemCount: number; + itemsPerPage: number; + totalPages: number; + currentPage: number; +} diff --git a/server/src/util.ts b/server/src/util.ts new file mode 100644 index 0000000..bdb9803 --- /dev/null +++ b/server/src/util.ts @@ -0,0 +1,39 @@ +import { PaginatedResponse } from './types'; +import { FindManyOptions, FindOptions, FindOptionsOrder } from 'typeorm'; + +export const createPaginatedResponse = ( + data: T[], + totalItems: number, + limit: number, + page: number, +) => { + return { + data, + meta: { + totalItems, + itemCount: data.length, + itemsPerPage: limit, + totalPages: Math.ceil(totalItems / limit), + currentPage: page, + }, + } as PaginatedResponse; +}; + +export const createFindOptions = ( + page: number, + limit: number, + sortBy?: string, + order?: 'ASC' | 'DESC', +): FindManyOptions => { + const findOptions: FindManyOptions = {}; + + const paginated = limit > 0; + if (paginated) { + findOptions.skip = (page - 1) * limit; + findOptions.take = limit; + } + if (sortBy && order) { + findOptions.order = { [sortBy]: order } as FindOptionsOrder; + } + return findOptions; +};