improve calendar event creation
This commit is contained in:
parent
2934e099b1
commit
71a8e267dc
@ -1,6 +1,6 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<component name="ProjectRunConfigurationManager">
|
||||||
<configuration default="false" name="dev:gui" type="ShConfigurationType">
|
<configuration default="false" name="dev:gui" type="ShConfigurationType">
|
||||||
<option name="SCRIPT_TEXT" value="cd dvbooking && npm run start" />
|
<option name="SCRIPT_TEXT" value="cd admin && npm run start" />
|
||||||
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
<option name="SCRIPT_PATH" value="" />
|
<option name="SCRIPT_PATH" value="" />
|
||||||
<option name="SCRIPT_OPTIONS" value="" />
|
<option name="SCRIPT_OPTIONS" value="" />
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
|
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
|
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
|
||||||
@if (isOpen()){
|
@if (isOpen()){
|
||||||
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()" [id]="selectedEventId()"></app-create-event-form>
|
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()" [id]="selectedEventId()"></app-create-event-form>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
<!-- Generated by the CLI -->
|
<!-- Generated by the CLI -->
|
||||||
<div class="p-4 md:p-8">
|
<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">
|
<div class="card-body">
|
||||||
<h2 class="card-title text-3xl">
|
<h2 class="card-title text-3xl">
|
||||||
Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }}
|
Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }}
|
||||||
@ -39,7 +39,7 @@
|
|||||||
</label></div>
|
</label></div>
|
||||||
|
|
||||||
@if (isRecurring?.value) {
|
@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>
|
<h3 class="text-lg font-semibold">Ismétlődés</h3>
|
||||||
|
|
||||||
<div class="form-control">
|
<div class="form-control">
|
||||||
|
|||||||
@ -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 { FormBuilder, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
||||||
import { ActivatedRoute, Router } from '@angular/router';
|
import { ActivatedRoute, Router } from '@angular/router';
|
||||||
import { EventService } from '../../../events/services/event.service';
|
import { EventService } from '../../../events/services/event.service';
|
||||||
@ -31,10 +31,9 @@ export class CreateEventForm implements OnInit {
|
|||||||
ready = output<void>();
|
ready = output<void>();
|
||||||
id= input<number | undefined>() ;
|
id= input<number | undefined>() ;
|
||||||
date = input<Date|undefined>();
|
date = input<Date|undefined>();
|
||||||
|
|
||||||
eventTypes = signal<EventType[]>([])
|
eventTypes = signal<EventType[]>([])
|
||||||
|
|
||||||
private numericFields = ["event_type_id"];
|
private numericFields: (keyof EventFormDTO)[] = ["event_type_id"];
|
||||||
|
|
||||||
frequencyOptions: FrequencyOption[] = [
|
frequencyOptions: FrequencyOption[] = [
|
||||||
{
|
{
|
||||||
@ -78,9 +77,9 @@ export class CreateEventForm implements OnInit {
|
|||||||
startTime: [null,Validators.required],
|
startTime: [null,Validators.required],
|
||||||
endTime: [null,Validators.required],
|
endTime: [null,Validators.required],
|
||||||
is_recurring: [false],
|
is_recurring: [false],
|
||||||
recurringRule: this.fb.group({
|
recurrenceRule: this.fb.group({
|
||||||
frequency: [null] ,//'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
frequency: ['DAILY'] ,//'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
||||||
interval: [null] ,//number
|
interval: [1] ,//number
|
||||||
endDate: [null], // Date
|
endDate: [null], // Date
|
||||||
count: [null], // number
|
count: [null], // number
|
||||||
byDay: [null], // string
|
byDay: [null], // string
|
||||||
@ -89,11 +88,18 @@ export class CreateEventForm implements OnInit {
|
|||||||
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
|
effect(() => {
|
||||||
|
console.info("effect run")
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
console.info("oninit run")
|
||||||
this.isRecurring?.valueChanges.subscribe(isRecurring => {
|
this.isRecurring?.valueChanges.subscribe(isRecurring => {
|
||||||
const recurringRule = this.form.get('recurringRule');
|
const recurringRule = this.form.get('recurrenceRule');
|
||||||
const frequency = recurringRule?.get('frequency');
|
const frequency = recurringRule?.get('frequency');
|
||||||
const interval = recurringRule?.get('interval');
|
const interval = recurringRule?.get('interval');
|
||||||
|
|
||||||
@ -183,24 +189,25 @@ export class CreateEventForm implements OnInit {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const payload: EventFormDTO|any = { ...this.form.value };
|
const payload: EventFormDTO = { ...this.form.value };
|
||||||
|
|
||||||
if (!payload.is_recurring) {
|
if (!payload.is_recurring) {
|
||||||
delete payload.recurringRule;
|
delete payload.recurrenceRule;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const field of this.numericFields) {
|
for (const field of this.numericFields) {
|
||||||
if (payload[field] != null && payload[field] !== '') {
|
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()) {
|
if (this.isEditMode && this.id()) {
|
||||||
console.info("rong branch")
|
action$ = this.calendarService.update(this.id()!, payload);
|
||||||
// action$ = this.calendarService.update(this.id()!, payload);
|
// action$ = of(undefined);
|
||||||
action$ = of(payload);
|
|
||||||
} else {
|
} else {
|
||||||
action$ = this.calendarService.create(payload);
|
action$ = this.calendarService.create(payload);
|
||||||
}
|
}
|
||||||
@ -233,31 +240,31 @@ export class CreateEventForm implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get recurringRule(){
|
get recurringRule(){
|
||||||
return this.form.get('recurringRule');
|
return this.form.get('recurrenceRule');
|
||||||
}
|
}
|
||||||
|
|
||||||
get frequency(){
|
get frequency(){
|
||||||
return this.form.get('recurringRule')?.get('frequency');
|
return this.form.get('recurrenceRule')?.get('frequency');
|
||||||
}
|
}
|
||||||
|
|
||||||
get interval(){
|
get interval(){
|
||||||
return this.form.get('recurringRule')?.get('interval');
|
return this.form.get('recurrenceRule')?.get('interval');
|
||||||
}
|
}
|
||||||
|
|
||||||
get endDate(){
|
get endDate(){
|
||||||
return this.form.get('recurringRule')?.get('endDate');
|
return this.form.get('recurrenceRule')?.get('endDate');
|
||||||
}
|
}
|
||||||
|
|
||||||
get byDay() {
|
get byDay() {
|
||||||
return this.form.get('recurringRule')?.get('byDay');
|
return this.form.get('recurrenceRule')?.get('byDay');
|
||||||
}
|
}
|
||||||
|
|
||||||
get byMonthDay() {
|
get byMonthDay() {
|
||||||
return this.form.get('recurringRule')?.get('byMonthDay');
|
return this.form.get('recurrenceRule')?.get('byMonthDay');
|
||||||
}
|
}
|
||||||
|
|
||||||
get byMonth() {
|
get byMonth() {
|
||||||
return this.form.get('recurringRule')?.get('byMonth');
|
return this.form.get('recurrenceRule')?.get('byMonth');
|
||||||
}
|
}
|
||||||
|
|
||||||
doReady(){
|
doReady(){
|
||||||
|
|||||||
@ -1,5 +1,19 @@
|
|||||||
// dvbooking-cli/src/templates/angular/model.ts.tpl
|
// 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
|
// Generated by the CLI
|
||||||
export interface EventFormDTO {
|
export interface EventFormDTO {
|
||||||
id?: number;
|
id?: number;
|
||||||
@ -9,4 +23,7 @@ export interface EventFormDTO {
|
|||||||
start_time?: Date;
|
start_time?: Date;
|
||||||
end_time?: Date;
|
end_time?: Date;
|
||||||
is_recurring: boolean;
|
is_recurring: boolean;
|
||||||
|
recurrenceRule?: RecurrenceRuleDto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface UpdateEventFormDTO extends Partial<EventFormDTO>{}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { Injectable } from '@angular/core';
|
|||||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { ConfigurationService } from '../../../services/configuration.service';
|
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 { Event } from '../../events/models/event.model';
|
||||||
import { CalendarEventDto, EventsInRangeDTO } from '../models/events-in-range-dto.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);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -148,10 +148,15 @@ export class CalendarService {
|
|||||||
|
|
||||||
if (!freq) continue;
|
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({
|
const rrule = new RRule({
|
||||||
freq,
|
freq,
|
||||||
dtstart: event.startTime,
|
dtstart: event.startTime,
|
||||||
until: event.recurrenceRule.endDate,
|
until: untilDate,
|
||||||
count: event.recurrenceRule.count,
|
count: event.recurrenceRule.count,
|
||||||
interval: event.recurrenceRule.interval,
|
interval: event.recurrenceRule.interval,
|
||||||
byweekday: byweekday?.length > 0 ? byweekday : undefined,
|
byweekday: byweekday?.length > 0 ? byweekday : undefined,
|
||||||
@ -199,7 +204,9 @@ export class CalendarService {
|
|||||||
// --- Other service methods (createEvent, etc.) remain unchanged ---
|
// --- Other service methods (createEvent, etc.) remain unchanged ---
|
||||||
|
|
||||||
async createEvent(createEventDto: CreateEventDto): Promise<Event> {
|
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 { recurrenceRule, ...eventData } = createEventDto;
|
||||||
|
|
||||||
const newEvent: Omit<
|
const newEvent: Omit<
|
||||||
@ -211,36 +218,52 @@ export class CalendarService {
|
|||||||
updatedAt: new Date(),
|
updatedAt: new Date(),
|
||||||
timezone: 'Europe/Budapest',
|
timezone: 'Europe/Budapest',
|
||||||
eventType: undefined,
|
eventType: undefined,
|
||||||
isRecurring: recurrenceRule ? true : false,
|
isRecurring: !!recurrenceRule,
|
||||||
};
|
};
|
||||||
|
console.log('[CalendarService] Prepared base event object:', newEvent);
|
||||||
|
|
||||||
// check if event type exists
|
// check if event type exists
|
||||||
if (eventData.eventTypeId) {
|
if (eventData.eventTypeId) {
|
||||||
console.info('eventTypeId found');
|
console.log(`[CalendarService] Event has eventTypeId: ${eventData.eventTypeId}. Fetching event type...`);
|
||||||
const eventType = await this.eventTypeRepository.findOneBy({
|
const eventType = await this.eventTypeRepository.findOneBy({
|
||||||
id: eventData.eventTypeId,
|
id: eventData.eventTypeId,
|
||||||
});
|
});
|
||||||
if (!eventType) {
|
if (!eventType) {
|
||||||
|
console.error(`[CalendarService] Event type with ID ${eventData.eventTypeId} not found.`);
|
||||||
throw new BadRequestException(
|
throw new BadRequestException(
|
||||||
{},
|
{},
|
||||||
'Event type not found ' + eventData.eventTypeId,
|
'Event type not found ' + eventData.eventTypeId,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
newEvent.eventType = eventType;
|
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 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({
|
const rule = this.recurrenceRuleRepository.create({
|
||||||
...recurrenceRule,
|
...recurrenceRule,
|
||||||
event: savedEvent,
|
event: savedEvent,
|
||||||
});
|
});
|
||||||
await this.recurrenceRuleRepository.save(rule);
|
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(
|
async createException(
|
||||||
|
|||||||
@ -52,7 +52,10 @@ export class EventsController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Patch(':id')
|
@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);
|
return this.eventsService.update(id, updateEventDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user