improve calendar event creation

This commit is contained in:
Roland Schneider 2025-11-26 16:48:20 +01:00
parent 2934e099b1
commit 71a8e267dc
8 changed files with 88 additions and 34 deletions

View File

@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="dev:gui" type="ShConfigurationType">
<option name="SCRIPT_TEXT" value="cd dvbooking &amp;&amp; npm run start" />
<option name="SCRIPT_TEXT" value="cd admin &amp;&amp; npm run start" />
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
<option name="SCRIPT_PATH" value="" />
<option name="SCRIPT_OPTIONS" value="" />

View File

@ -7,7 +7,7 @@
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
</div>
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
@if (isOpen()){
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()" [id]="selectedEventId()"></app-create-event-form>
}

View File

@ -1,6 +1,6 @@
<!-- Generated by the CLI -->
<div class="p-4 md:p-8">
<div class="card bg-base-100 shadow-xl max-w-2xl mx-auto">
<div class="card bg-base-100 shadow-xl mx-auto">
<div class="card-body">
<h2 class="card-title text-3xl">
Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }}
@ -39,7 +39,7 @@
</label></div>
@if (isRecurring?.value) {
<div formGroupName="recurringRule" class="space-y-4 p-4 border border-base-300 rounded-lg">
<div formGroupName="recurrenceRule" class="space-y-4 p-4 border border-base-300 rounded-lg">
<h3 class="text-lg font-semibold">Ismétlődés</h3>
<div class="form-control">

View File

@ -1,4 +1,4 @@
import { Component, input, OnInit, output, signal } from '@angular/core';
import { Component, effect, input, OnInit, output, signal } from '@angular/core';
import { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { EventService } from '../../../events/services/event.service';
@ -31,10 +31,9 @@ export class CreateEventForm implements OnInit {
ready = output<void>();
id= input<number | undefined>() ;
date = input<Date|undefined>();
eventTypes = signal<EventType[]>([])
private numericFields = ["event_type_id"];
private numericFields: (keyof EventFormDTO)[] = ["event_type_id"];
frequencyOptions: FrequencyOption[] = [
{
@ -78,9 +77,9 @@ export class CreateEventForm implements OnInit {
startTime: [null,Validators.required],
endTime: [null,Validators.required],
is_recurring: [false],
recurringRule: this.fb.group({
frequency: [null] ,//'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
interval: [null] ,//number
recurrenceRule: this.fb.group({
frequency: ['DAILY'] ,//'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
interval: [1] ,//number
endDate: [null], // Date
count: [null], // number
byDay: [null], // string
@ -89,11 +88,18 @@ export class CreateEventForm implements OnInit {
})
});
effect(() => {
console.info("effect run")
});
}
ngOnInit(): void {
console.info("oninit run")
this.isRecurring?.valueChanges.subscribe(isRecurring => {
const recurringRule = this.form.get('recurringRule');
const recurringRule = this.form.get('recurrenceRule');
const frequency = recurringRule?.get('frequency');
const interval = recurringRule?.get('interval');
@ -183,24 +189,25 @@ export class CreateEventForm implements OnInit {
return;
}
const payload: EventFormDTO|any = { ...this.form.value };
const payload: EventFormDTO = { ...this.form.value };
if (!payload.is_recurring) {
delete payload.recurringRule;
delete payload.recurrenceRule;
}
for (const field of this.numericFields) {
if (payload[field] != null && payload[field] !== '') {
payload[field] = parseFloat(payload[field]);
if ( typeof payload[field] !== 'number'){
payload[field] = parseFloat(payload[field] as string) as never;
}
}
}
let action$: Observable<Event>;
let action$: Observable<Event|undefined>;
if (this.isEditMode && this.id()) {
console.info("rong branch")
// action$ = this.calendarService.update(this.id()!, payload);
action$ = of(payload);
action$ = this.calendarService.update(this.id()!, payload);
// action$ = of(undefined);
} else {
action$ = this.calendarService.create(payload);
}
@ -233,31 +240,31 @@ export class CreateEventForm implements OnInit {
}
get recurringRule(){
return this.form.get('recurringRule');
return this.form.get('recurrenceRule');
}
get frequency(){
return this.form.get('recurringRule')?.get('frequency');
return this.form.get('recurrenceRule')?.get('frequency');
}
get interval(){
return this.form.get('recurringRule')?.get('interval');
return this.form.get('recurrenceRule')?.get('interval');
}
get endDate(){
return this.form.get('recurringRule')?.get('endDate');
return this.form.get('recurrenceRule')?.get('endDate');
}
get byDay() {
return this.form.get('recurringRule')?.get('byDay');
return this.form.get('recurrenceRule')?.get('byDay');
}
get byMonthDay() {
return this.form.get('recurringRule')?.get('byMonthDay');
return this.form.get('recurrenceRule')?.get('byMonthDay');
}
get byMonth() {
return this.form.get('recurringRule')?.get('byMonth');
return this.form.get('recurrenceRule')?.get('byMonth');
}
doReady(){

View File

@ -1,5 +1,19 @@
// dvbooking-cli/src/templates/angular/model.ts.tpl
export interface RecurrenceRuleDto {
frequency: 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
interval: number;
byDay?: string; // e.g., 'MO,TU,WE,TH,FR'
endDate?: Date;
count?: number;
}
// Generated by the CLI
export interface EventFormDTO {
id?: number;
@ -9,4 +23,7 @@ export interface EventFormDTO {
start_time?: Date;
end_time?: Date;
is_recurring: boolean;
recurrenceRule?: RecurrenceRuleDto;
}
export interface UpdateEventFormDTO extends Partial<EventFormDTO>{}

View File

@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
import { ConfigurationService } from '../../../services/configuration.service';
import { EventFormDTO } from '../models/event-form-dto.model';
import { EventFormDTO, UpdateEventFormDTO } from '../models/event-form-dto.model';
import { Event } from '../../events/models/event.model';
import { CalendarEventDto, EventsInRangeDTO } from '../models/events-in-range-dto.model';
@ -36,4 +36,8 @@ export class CalendarService {
return this.http.post<Event>(this.apiUrl+'/events', data);
}
public update(id: number,data: UpdateEventFormDTO): Observable<Event> {
return this.http.put<Event>(this.apiUrl+'/events', data);
}
}

View File

@ -148,10 +148,15 @@ export class CalendarService {
if (!freq) continue;
let untilDate: Date|undefined = undefined;
// typeorm does not convert postgres type 'date' to javascript date object
if (event?.recurrenceRule?.endDate) {
untilDate = new Date(event.recurrenceRule.endDate);
}
const rrule = new RRule({
freq,
dtstart: event.startTime,
until: event.recurrenceRule.endDate,
until: untilDate,
count: event.recurrenceRule.count,
interval: event.recurrenceRule.interval,
byweekday: byweekday?.length > 0 ? byweekday : undefined,
@ -199,7 +204,9 @@ export class CalendarService {
// --- Other service methods (createEvent, etc.) remain unchanged ---
async createEvent(createEventDto: CreateEventDto): Promise<Event> {
console.info('createEvent', createEventDto);
console.log('[CalendarService] Entering createEvent method.');
console.log('[CalendarService] Received DTO:', JSON.stringify(createEventDto, null, 2));
const { recurrenceRule, ...eventData } = createEventDto;
const newEvent: Omit<
@ -211,36 +218,52 @@ export class CalendarService {
updatedAt: new Date(),
timezone: 'Europe/Budapest',
eventType: undefined,
isRecurring: recurrenceRule ? true : false,
isRecurring: !!recurrenceRule,
};
console.log('[CalendarService] Prepared base event object:', newEvent);
// check if event type exists
if (eventData.eventTypeId) {
console.info('eventTypeId found');
console.log(`[CalendarService] Event has eventTypeId: ${eventData.eventTypeId}. Fetching event type...`);
const eventType = await this.eventTypeRepository.findOneBy({
id: eventData.eventTypeId,
});
if (!eventType) {
console.error(`[CalendarService] Event type with ID ${eventData.eventTypeId} not found.`);
throw new BadRequestException(
{},
'Event type not found ' + eventData.eventTypeId,
);
}
newEvent.eventType = eventType;
console.log('[CalendarService] Successfully attached event type:', eventType);
} else {
console.log('[CalendarService] No eventTypeId provided.');
}
console.log('[CalendarService] Creating event entity...');
const event = this.eventRepository.create(newEvent);
const savedEvent = await this.eventRepository.save(event);
if (event.isRecurring && recurrenceRule) {
console.log('[CalendarService] Saving event entity to the database...');
const savedEvent = await this.eventRepository.save(event);
console.log('[CalendarService] Event saved successfully. Saved event ID:', savedEvent.id);
if (savedEvent.isRecurring && recurrenceRule) {
console.log(`[CalendarService] Event is recurring. Creating recurrence rule...`);
const rule = this.recurrenceRuleRepository.create({
...recurrenceRule,
event: savedEvent,
});
await this.recurrenceRuleRepository.save(rule);
console.log('[CalendarService] Recurrence rule saved successfully.');
} else {
console.log('[CalendarService] Event is not recurring or no recurrence rule provided.');
}
return this.getEventById(savedEvent.id);
console.log(`[CalendarService] Fetching final event by ID ${savedEvent.id} to return.`);
const finalEvent = await this.getEventById(savedEvent.id);
console.log('[CalendarService] Exiting createEvent method.');
return finalEvent;
}
async createException(

View File

@ -52,7 +52,10 @@ export class EventsController {
}
@Patch(':id')
update(@Param('id', ParseIntPipe) id: number, @Body() updateEventDto: UpdateEventDto) {
update(
@Param('id', ParseIntPipe) id: number,
@Body() updateEventDto: UpdateEventDto,
) {
return this.eventsService.update(id, updateEventDto);
}