feat: Implement event dashboard with activation, cancellation, editing, and booking management functionalities.

This commit is contained in:
Schneider Roland
2025-12-31 12:00:05 +01:00
parent 90c192c881
commit 7ed3367ed8
21 changed files with 441 additions and 274 deletions

View File

@@ -31,7 +31,7 @@ import { CalenderControllerGetBookingResponse } from './dto/booking.response.dto
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.Admin)
export class CalendarController {
constructor(private readonly calendarService: CalendarService) {}
constructor(private readonly calendarService: CalendarService) { }
@Get()
getCalendarEvents(@Query() getCalendarDto: GetCalendarDto) {
@@ -110,6 +110,7 @@ export class CalendarController {
@ApiCreatedResponse({ type: CalenderControllerGetBookingResponse }) // Removed <Booking> generic for cleaner syntax unless defined elsewhere
// Ensure ValidationPipe is enabled with transform: true (Global or Method scoped)
// @UsePipes(new ValidationPipe({ transform: true }))
@Roles(Role.Admin, Role.User)
async getBookings(
@User() user: types.AppUser,
@Param('eventId', ParseIntPipe) eventId: number,
@@ -117,7 +118,7 @@ export class CalendarController {
@Query() calendarGetBookingDto: CalendarGetBookingDto,
) {
return this.calendarService.getBookings(
user.user!.userId,
user,
eventId,
calendarGetBookingDto,
);

View File

@@ -28,6 +28,8 @@ import {
BookingResponseDto,
CalenderControllerGetBookingResponse,
} from './dto/booking.response.dto';
import { AppUser } from 'src/types';
import { Role } from '../auth/role.enum';
// --- Type-Safe Maps ---
const frequencyMap: Record<string, RRule.Frequency> = {
@@ -82,7 +84,7 @@ export class CalendarService {
private readonly eventExceptionRepository: Repository<EventException>,
@InjectRepository(Booking)
private readonly bookingRepository: Repository<Booking>,
) {}
) { }
async getEventsInRange(
startDate: Date,
@@ -606,7 +608,7 @@ export class CalendarService {
}
async getBookings(
userId: number,
user: AppUser,
eventId: number,
queryParams: CalendarGetBookingDto,
): Promise<CalenderControllerGetBookingResponse> {
@@ -621,6 +623,13 @@ export class CalendarService {
['createdAt']: order!,
},
};
if (!user.user?.roles.includes(Role.Admin)) {
findOptions.where = {
...findOptions.where,
userId: user.user!.userId,
};
}
const paginated = limit > 0;
const [data, totalItems] =
await this.bookingRepository.findAndCount(findOptions);

View File

@@ -32,6 +32,9 @@ export class BookingResponseDto {
})
user?: UserResponseDto;
@ApiProperty({ required: false })
status?: string;
constructor(booking: Booking) {
this.id = Number(booking.id); // Handle BigInt conversion
this.eventId = Number(booking.eventId);
@@ -46,6 +49,14 @@ export class BookingResponseDto {
// Assuming User entity has firstName/lastName
this.user = new UserResponseDto(booking.user);
}
this.status = 'active';
if (booking.canceledAt) {
if (booking.canceledReason == 'customer_cancelled') {
this.status = 'customer_cancelled';
} else {
this.status = 'cancelled';
}
}
}
}

View File

@@ -1,14 +1,12 @@
import {
IsInt,
IsNotEmpty,
IsOptional,
IsString,
MaxLength,
} from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';
export class CancelBookingDto {
@ApiProperty()
@IsOptional()
@IsString()
@MaxLength(50)