improve exception saving
This commit is contained in:
@@ -1,12 +1,13 @@
|
|||||||
import { Component, inject, input } from '@angular/core';
|
import { Component, inject, input } from '@angular/core';
|
||||||
import { CalendarEventDto } from '../../../models/events-in-range-dto.model';
|
import { CalendarEventDto, EventExceptionDto } from '../../../models/events-in-range-dto.model';
|
||||||
import {
|
import {
|
||||||
SingleEventDashboardEventDetailsView
|
SingleEventDashboardEventDetailsView,
|
||||||
} from '../single-event-dashboard-event-details-view/single-event-dashboard-event-details-view';
|
} from '../single-event-dashboard-event-details-view/single-event-dashboard-event-details-view';
|
||||||
import { Button } from '@rschneider/ng-daisyui';
|
import { Button } from '@rschneider/ng-daisyui';
|
||||||
import { SvgIcons } from '../../../../../svg-icons';
|
import { SvgIcons } from '../../../../../svg-icons';
|
||||||
import { SafeHtmlPipe } from '../../../../../pipes/safe-html-pipe';
|
import { SafeHtmlPipe } from '../../../../../pipes/safe-html-pipe';
|
||||||
import { CalendarService } from '../../../services/calendar.service';
|
import { CalendarService } from '../../../services/calendar.service';
|
||||||
|
import { CreateExceptionDto } from '../../../models/event-exception.model';
|
||||||
|
|
||||||
export type ACTIVATION_TYPE = 'cancel' | 'activate';
|
export type ACTIVATION_TYPE = 'cancel' | 'activate';
|
||||||
|
|
||||||
@@ -32,32 +33,49 @@ export class SingleEventDashboardEventActivation {
|
|||||||
|
|
||||||
protected setEventOccurrenceActivation(activated: boolean) {
|
protected setEventOccurrenceActivation(activated: boolean) {
|
||||||
|
|
||||||
|
const event = this.event();
|
||||||
|
console.info('setEventOccurrenceActivation', event);
|
||||||
const eventId = this.event()?.id!;
|
const eventId = this.event()?.id!;
|
||||||
const startTime = this.event()?.startTime!;
|
const startTime = this.event()?.startTime!;
|
||||||
|
let payload: CreateExceptionDto | undefined = undefined;
|
||||||
this.calendarService.applyException(eventId,{
|
const eventException = event?.exceptions ? event.exceptions[0] : undefined;
|
||||||
|
if (eventException) {
|
||||||
|
payload = {
|
||||||
|
...eventException,
|
||||||
|
originalStartTime: new Date(eventException.originalStartTime),
|
||||||
|
newStartTime: eventException.newStartTime ? new Date(eventException.newStartTime) : undefined,
|
||||||
|
newEndTime: eventException.newEndTime ? new Date(eventException.newEndTime) :undefined,
|
||||||
|
isCancelled: !activated,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
payload = {
|
||||||
originalStartTime: new Date(startTime),
|
originalStartTime: new Date(startTime),
|
||||||
isCancelled: !activated,
|
isCancelled: !activated,
|
||||||
}).subscribe(
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
this.calendarService.applyException(eventId, payload ).subscribe(
|
||||||
{
|
{
|
||||||
next: () => {
|
next: () => {
|
||||||
this.onAction()('close');
|
this.onAction()('close');
|
||||||
},
|
},
|
||||||
error: err => {
|
error: err => {
|
||||||
alert("Failed to change event");
|
alert('Failed to change event');
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected cancelEventOccurrence() {
|
protected cancelEventOccurrence() {
|
||||||
this.setEventOccurrenceActivation(false);
|
this.setEventOccurrenceActivation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected activateEventOccurrence() {
|
protected activateEventOccurrence() {
|
||||||
this.setEventOccurrenceActivation(true);
|
this.setEventOccurrenceActivation(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected closeDialog() {
|
protected closeDialog() {
|
||||||
this.onAction()('close')
|
this.onAction()('close');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,18 @@ export type BookingWithUserDto = {
|
|||||||
id: number;
|
id: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export interface EventExceptionDto{
|
||||||
|
id: number,
|
||||||
|
description: string;
|
||||||
|
eventId: number;
|
||||||
|
isCancelled: boolean;
|
||||||
|
newEndTime: string;
|
||||||
|
newStartTime: string;
|
||||||
|
originalStartTime: string;
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// The final shape of a calendar event occurrence
|
// The final shape of a calendar event occurrence
|
||||||
export type CalendarEventDto = {
|
export type CalendarEventDto = {
|
||||||
id: number;
|
id: number;
|
||||||
@@ -29,4 +41,5 @@ export type CalendarEventDto = {
|
|||||||
|
|
||||||
isRecurring: boolean;
|
isRecurring: boolean;
|
||||||
eventType: EventType
|
eventType: EventType
|
||||||
|
exceptions: EventExceptionDto[]
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -65,7 +65,10 @@ export class CalendarController {
|
|||||||
@Param('id', ParseIntPipe) eventId: number,
|
@Param('id', ParseIntPipe) eventId: number,
|
||||||
@Body() createExceptionDto: CreateExceptionDto,
|
@Body() createExceptionDto: CreateExceptionDto,
|
||||||
) {
|
) {
|
||||||
return this.calendarService.createException(eventId, createExceptionDto);
|
return this.calendarService.createOrUpdateException(
|
||||||
|
eventId,
|
||||||
|
createExceptionDto,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a booking for a specific event occurrence
|
// Create a booking for a specific event occurrence
|
||||||
|
|||||||
@@ -335,6 +335,102 @@ export class CalendarService {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
async createOrUpdateException(
|
||||||
|
eventId: number,
|
||||||
|
createExceptionDto: CreateExceptionDto,
|
||||||
|
): Promise<EventException> {
|
||||||
|
const { originalStartTime, newStartTime } = createExceptionDto;
|
||||||
|
|
||||||
|
const event = await this.eventRepository.findOneBy({ id: eventId });
|
||||||
|
if (!event) {
|
||||||
|
throw new NotFoundException(`Event with ID ${eventId} not found`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This logic now requires a transaction
|
||||||
|
return this.dataSource.manager.transaction(
|
||||||
|
async (transactionalEntityManager) => {
|
||||||
|
let oldNewStartTime: Date | null = null;
|
||||||
|
// Check if an exception for this originalStartTime already exists
|
||||||
|
let existingException = await transactionalEntityManager.findOne(
|
||||||
|
EventException,
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
eventId: eventId,
|
||||||
|
originalStartTime: originalStartTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
if (existingException) {
|
||||||
|
oldNewStartTime = existingException.newStartTime;
|
||||||
|
existingException.title = createExceptionDto.title!;
|
||||||
|
existingException.description = createExceptionDto.description!;
|
||||||
|
existingException.isCancelled = createExceptionDto.isCancelled!;
|
||||||
|
existingException.newStartTime = createExceptionDto.newStartTime!;
|
||||||
|
existingException.newEndTime = createExceptionDto.newEndTime!;
|
||||||
|
|
||||||
|
// More complex logic might be needed here depending on exact requirements.
|
||||||
|
} else {
|
||||||
|
// Create new exception
|
||||||
|
existingException = transactionalEntityManager.create(
|
||||||
|
EventException,
|
||||||
|
{
|
||||||
|
...createExceptionDto,
|
||||||
|
event: event,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const savedException =
|
||||||
|
await transactionalEntityManager.save(existingException);
|
||||||
|
// Step 1: Create and save the new exception
|
||||||
|
// const exception = transactionalEntityManager.create(EventException, {
|
||||||
|
// ...createExceptionDto,
|
||||||
|
// event: event,
|
||||||
|
// });
|
||||||
|
// const savedException = await transactionalEntityManager.save(exception);
|
||||||
|
|
||||||
|
// Step 2: Check if this is a RESCHEDULE operation
|
||||||
|
// A reschedule happens when there is a new start time.
|
||||||
|
let startTimeChanged = false;
|
||||||
|
if (newStartTime && !oldNewStartTime) {
|
||||||
|
startTimeChanged = true;
|
||||||
|
} else if (!newStartTime && oldNewStartTime) {
|
||||||
|
startTimeChanged = true;
|
||||||
|
} else if (newStartTime && oldNewStartTime) {
|
||||||
|
if (oldNewStartTime.getTime() !== newStartTime.getTime()) {
|
||||||
|
startTimeChanged = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (startTimeChanged) {
|
||||||
|
// Step 3: Find all existing bookings for the ORIGINAL time
|
||||||
|
const bookingsToMigrate = await transactionalEntityManager.find(
|
||||||
|
Booking,
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
eventId: eventId,
|
||||||
|
occurrenceStartTime: originalStartTime,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// Step 4: If we found any bookings, update their start time to the NEW time
|
||||||
|
if (bookingsToMigrate.length > 0) {
|
||||||
|
const bookingIds = bookingsToMigrate.map((b) => b.id);
|
||||||
|
|
||||||
|
await transactionalEntityManager.update(
|
||||||
|
Booking,
|
||||||
|
bookingIds, // Update these specific bookings
|
||||||
|
{ occurrenceStartTime: newStartTime }, // Set their time to the new value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return savedException;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
async getEventById(id: number): Promise<Event> {
|
async getEventById(id: number): Promise<Event> {
|
||||||
const event = await this.eventRepository.findOne({
|
const event = await this.eventRepository.findOne({
|
||||||
|
|||||||
Reference in New Issue
Block a user