add calendar dashboard edit
This commit is contained in:
parent
a043d64229
commit
fa098f4a1b
@ -1,18 +1,18 @@
|
||||
<div>
|
||||
<h1>Naptár</h1>
|
||||
<div>
|
||||
<input type="text" name="startHour" id="starthour" #startHour>
|
||||
<a class="btn" (click)="addEvent($event)">add</a>
|
||||
</div>
|
||||
<!-- <div>-->
|
||||
<!-- <input type="text" name="startHour" id="starthour" #startHour>-->
|
||||
<!-- <a class="btn" (click)="addEvent($event)">add</a>-->
|
||||
<!-- </div>-->
|
||||
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
|
||||
</div>
|
||||
|
||||
<rs-daisy-modal [isOpen]="workflow() == 'create'" (closeClick)="closeDialog()">
|
||||
@if (workflow() == 'create') {
|
||||
@if (workflow() == 'event-create') {
|
||||
<rs-daisy-modal [isOpen]="true" (closeClick)="closeDialog()" [modalBoxStyleClass]="'max-w-none w-2xl'">
|
||||
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()"
|
||||
[id]="undefined"></app-create-event-form>
|
||||
}
|
||||
</rs-daisy-modal>
|
||||
}
|
||||
|
||||
@if (workflow() == 'event-dashboard' && selectedEvent()) {
|
||||
<rs-daisy-modal [isOpen]="true" (closeClick)="closeDialog()" [modalBoxStyleClass]="'max-w-none w-2xl'">
|
||||
@ -27,7 +27,7 @@
|
||||
@if (dialogDefinition.isRendered()) {
|
||||
<rs-daisy-modal [isOpen]="true" (closeClick)="closeDialog()" [modalBoxStyleClass]="'max-w-none w-2xl'">
|
||||
<ng-container
|
||||
*ngComponentOutlet="dialogDefinition.component; inputs: dialogDefinition.componentInputs ? dialogDefinition.componentInputs() : {}; injector: dialogDefinition.componentOutputs()"
|
||||
*ngComponentOutlet="dialogDefinition.component; inputs: dialogDefinition.componentInputs ? dialogDefinition.componentInputs() : {}; "
|
||||
></ng-container>
|
||||
</rs-daisy-modal>
|
||||
}
|
||||
|
||||
@ -1,11 +1,7 @@
|
||||
import {
|
||||
AfterViewInit,
|
||||
Component,
|
||||
effect,
|
||||
ElementRef,
|
||||
inject,
|
||||
Injector,
|
||||
OnInit,
|
||||
signal,
|
||||
Type,
|
||||
ViewChild,
|
||||
@ -17,27 +13,28 @@ import dayGridPlugin from '@fullcalendar/daygrid';
|
||||
import timeGridPlugin from '@fullcalendar/timegrid';
|
||||
import listPlugin from '@fullcalendar/list';
|
||||
import interactionPlugin from '@fullcalendar/interaction';
|
||||
import { Button, Modal } from '@rschneider/ng-daisyui';
|
||||
import { Modal } from '@rschneider/ng-daisyui';
|
||||
import { CreateEventForm } from '../create-event-form/create-event-form';
|
||||
import { CalendarService } from '../../services/calendar.service';
|
||||
import { CalendarEventDto, EventsInRangeDTO } from '../../models/events-in-range-dto.model';
|
||||
import { CalendarEventDto } from '../../models/events-in-range-dto.model';
|
||||
import { map } from 'rxjs';
|
||||
import { SingleEventDashboard } from './single-event-dashboard/single-event-dashboard';
|
||||
import { CommonModule, JsonPipe, NgComponentOutlet } from '@angular/common';
|
||||
import { CommonModule, NgComponentOutlet } from '@angular/common';
|
||||
import {
|
||||
SingleEventDashboardEventDelete
|
||||
SingleEventDashboardEventDelete,
|
||||
} from './single-event-dashboard-event-delete/single-event-dashboard-event-delete';
|
||||
import {
|
||||
SingleEventDashboardEventCancel
|
||||
SingleEventDashboardEventCancel,
|
||||
} from './single-event-dashboard-event-cancel/single-event-dashboard-event-cancel';
|
||||
import { SingleEventDashboardEventEdit } from './single-event-dashboard-event-edit/single-event-dashboard-event-edit';
|
||||
|
||||
@Component({
|
||||
selector: 'app-calendar-view',
|
||||
imports: [FullCalendarModule, CommonModule, Modal,NgComponentOutlet, CreateEventForm, SingleEventDashboard, JsonPipe],
|
||||
imports: [FullCalendarModule, CommonModule, Modal, NgComponentOutlet, CreateEventForm, SingleEventDashboard],
|
||||
templateUrl: './calendar-view.html',
|
||||
styleUrl: './calendar-view.css',
|
||||
})
|
||||
export class CalendarView implements OnInit, AfterViewInit {
|
||||
export class CalendarView {
|
||||
|
||||
@ViewChild('startHour') startHour!: ElementRef;
|
||||
@ViewChild('calendar') calendarComponent: FullCalendarComponent | undefined;
|
||||
@ -46,7 +43,7 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
|
||||
workflow = signal<string>('');
|
||||
selectedDate = signal<Date | undefined>(undefined);
|
||||
selectedEvent = signal<CalendarEventDto|undefined>(undefined)
|
||||
selectedEvent = signal<CalendarEventDto | undefined>(undefined);
|
||||
|
||||
calendarOptions: CalendarOptions;
|
||||
dialogs: DialogConfig[] = [];
|
||||
@ -69,26 +66,17 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
eventClick: (info) => {
|
||||
this.selectedEvent.set(info.event.extendedProps['event']);
|
||||
this.workflow.set('event-dashboard');
|
||||
this.selectedDate.set(undefined);
|
||||
},
|
||||
|
||||
dateClick: (info) => {
|
||||
console.info('create new evet for day ',info);
|
||||
this.workflow.set('create');
|
||||
this.workflow.set('event-create');
|
||||
this.selectedDate.set(info.date);
|
||||
this.selectedEvent.set(undefined);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
const injector = Injector.create({
|
||||
providers: [
|
||||
{
|
||||
provide: 'closeDialog',
|
||||
useValue: () => this.closeDialog()
|
||||
}
|
||||
]
|
||||
});
|
||||
this.dialogs = [
|
||||
{
|
||||
component: SingleEventDashboardEventDelete,
|
||||
@ -99,10 +87,9 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
componentInputs: () => {
|
||||
return {
|
||||
'event': this.selectedEvent(),
|
||||
'onAction': this.handleAction
|
||||
}
|
||||
'onAction': this.handleAction,
|
||||
};
|
||||
},
|
||||
componentOutputs: () => injector
|
||||
|
||||
},
|
||||
|
||||
@ -115,13 +102,24 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
componentInputs: () => {
|
||||
return {
|
||||
'event': this.selectedEvent(),
|
||||
'onAction': this.handleAction
|
||||
}
|
||||
'onAction': this.handleAction,
|
||||
};
|
||||
},
|
||||
componentOutputs: () => injector
|
||||
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
component: SingleEventDashboardEventEdit,
|
||||
isRendered: () => this.workflow() == 'event-edit',
|
||||
// isRendered: () => true,
|
||||
closeClick: () => this.closeDialog(),
|
||||
modalBoxStyleClass: 'max-w-none w-2xl',
|
||||
componentInputs: () => {
|
||||
return {
|
||||
'event': this.selectedEvent(),
|
||||
'onAction': this.handleAction,
|
||||
};
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
fetchEvents(fetchInfo: any, successCallback: (events: EventInput[]) => void, failureCallback: (error: any) => void): void {
|
||||
@ -129,39 +127,33 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
console.info('fetching events', fetchInfo);
|
||||
const start = fetchInfo.start;
|
||||
const end = fetchInfo.end;
|
||||
// if ( fetchInfo ){
|
||||
// console.info("fetchinfo", fetchInfo);
|
||||
// successCallback([]);
|
||||
// return;
|
||||
// }
|
||||
this.calendarService.getEventsInRange({
|
||||
startTime: start,
|
||||
endTime: end,
|
||||
})
|
||||
.pipe(
|
||||
map(value => {
|
||||
console.info("vent got" , value );
|
||||
const events: EventInput[] = value.map((model) => {
|
||||
const calendarEvent: EventInput = {
|
||||
start: new Date(model.startTime),
|
||||
// end: model.end_time,
|
||||
title: model.title,
|
||||
extendedProps: {
|
||||
event: model
|
||||
}
|
||||
event: model,
|
||||
},
|
||||
};
|
||||
if (model.eventType) {
|
||||
calendarEvent.borderColor = model.eventType.color;
|
||||
}
|
||||
// calendarEvent.backgroundColor = "#00ff00"
|
||||
return calendarEvent;
|
||||
})
|
||||
});
|
||||
return events;
|
||||
}),
|
||||
)
|
||||
.subscribe({
|
||||
next: (events) => {
|
||||
console.info("calendar events", events);
|
||||
console.info('calendar events', events);
|
||||
successCallback(events);
|
||||
}
|
||||
,
|
||||
@ -173,44 +165,38 @@ export class CalendarView implements OnInit, AfterViewInit {
|
||||
);
|
||||
}
|
||||
|
||||
ngAfterViewInit(): void {
|
||||
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
|
||||
}
|
||||
|
||||
protected addEvent($event: PointerEvent) {
|
||||
let hourStr = this.startHour.nativeElement.value;
|
||||
const hour = parseInt(hourStr, 10);
|
||||
const date = new Date();
|
||||
const start = new Date(date.getTime());
|
||||
start.setHours(hour, 0, 0);
|
||||
const end = new Date(date.getTime());
|
||||
// end.setHours(3,0,0)
|
||||
|
||||
this.calendarComponent?.getApi().addEvent({
|
||||
title: 'Event at ' + hour,
|
||||
start,
|
||||
});
|
||||
}
|
||||
// protected addEvent($event: PointerEvent) {
|
||||
// let hourStr = this.startHour.nativeElement.value;
|
||||
// const hour = parseInt(hourStr, 10);
|
||||
// const date = new Date();
|
||||
// const start = new Date(date.getTime());
|
||||
// start.setHours(hour, 0, 0);
|
||||
// const end = new Date(date.getTime());
|
||||
// // end.setHours(3,0,0)
|
||||
//
|
||||
// this.calendarComponent?.getApi().addEvent({
|
||||
// title: 'Event at ' + hour,
|
||||
// start,
|
||||
// });
|
||||
// }
|
||||
|
||||
closeDialog() {
|
||||
this.workflow.set('');
|
||||
}
|
||||
|
||||
onDashboardAction(action: string) {
|
||||
console.info("dashboard event", action);
|
||||
console.info('dashboard event', action);
|
||||
switch (action) {
|
||||
case 'event_delete':
|
||||
this.workflow.set('event-delete');
|
||||
break;
|
||||
|
||||
case 'event_cancel':
|
||||
console.info("event cancel clicked");
|
||||
this.workflow.set('event-cancel');
|
||||
break;
|
||||
case 'event_edit':
|
||||
this.workflow.set('event-edit');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -232,5 +218,4 @@ export interface DialogConfig{
|
||||
closeClick: () => void,
|
||||
modalBoxStyleClass: string
|
||||
isRendered: () => boolean;
|
||||
componentOutputs: () => Injector
|
||||
}
|
||||
|
||||
@ -0,0 +1,3 @@
|
||||
<app-create-event-form (ready)="onAction()" [date]="selectedDate()"
|
||||
|
||||
[id]="event()?.id"></app-create-event-form>
|
||||
@ -0,0 +1,28 @@
|
||||
import { Component, input, signal } from '@angular/core';
|
||||
import { CalendarEventDto } from '../../../models/events-in-range-dto.model';
|
||||
import { SvgIcons } from '../../../../../svg-icons';
|
||||
import { CreateEventForm } from '../../create-event-form/create-event-form';
|
||||
import { Modal } from '@rschneider/ng-daisyui';
|
||||
|
||||
@Component({
|
||||
selector: 'app-single-event-dashboard-event-edit',
|
||||
imports: [
|
||||
CreateEventForm,
|
||||
Modal,
|
||||
],
|
||||
templateUrl: './single-event-dashboard-event-edit.html',
|
||||
styleUrl: './single-event-dashboard-event-edit.css',
|
||||
})
|
||||
export class SingleEventDashboardEventEdit {
|
||||
|
||||
selectedDate = signal<Date | undefined>(undefined);
|
||||
event = input<CalendarEventDto>();
|
||||
onAction = input.required<(msg: string) => void>();
|
||||
|
||||
protected readonly SvgIcons = SvgIcons;
|
||||
|
||||
protected triggerAction() {
|
||||
|
||||
this.onAction()('close')
|
||||
}
|
||||
}
|
||||
@ -1,7 +1,5 @@
|
||||
<!-- Generated by the CLI -->
|
||||
<div class="p-4 md:p-8">
|
||||
<div class="card bg-base-100 shadow-xl mx-auto">
|
||||
<div class="card-body">
|
||||
<div class="">
|
||||
<h2 class="card-title text-3xl">
|
||||
Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }}
|
||||
</h2>
|
||||
@ -38,7 +36,7 @@
|
||||
<input type="checkbox" formControlName="is_recurring" class="checkbox" />
|
||||
</label></div>
|
||||
|
||||
@if (isRecurring?.value) {
|
||||
@if (isRecurring?.value === true) {
|
||||
<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>
|
||||
|
||||
@ -115,5 +113,3 @@
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
import { Component, effect, input, OnInit, output, signal } from '@angular/core';
|
||||
import { Component, 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';
|
||||
@ -9,6 +9,7 @@ import { EventType } from '../../../event-type/models/event-type.model';
|
||||
import { EventTypeService } from '../../../event-type/services/event-type.service';
|
||||
import { CalendarService } from '../../services/calendar.service';
|
||||
import { EventFormDTO } from '../../models/event-form-dto.model';
|
||||
import { format } from 'date-fns';
|
||||
|
||||
export type Frequency = 'DAILY' | 'WEEKLY' | 'MONTHLY' | 'YEARLY';
|
||||
export type FrequencyOption = {
|
||||
@ -16,11 +17,10 @@ export type FrequencyOption = {
|
||||
label: string;
|
||||
}
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'app-create-event-form',
|
||||
imports: [
|
||||
ReactiveFormsModule
|
||||
ReactiveFormsModule,
|
||||
],
|
||||
templateUrl: './create-event-form.html',
|
||||
styleUrl: './create-event-form.css',
|
||||
@ -31,25 +31,25 @@ export class CreateEventForm implements OnInit {
|
||||
ready = output<void>();
|
||||
id = input<number | undefined>();
|
||||
date = input<Date | undefined>();
|
||||
eventTypes = signal<EventType[]>([])
|
||||
eventTypes = signal<EventType[]>([]);
|
||||
|
||||
private numericFields: (keyof EventFormDTO)[] = ["event_type_id"];
|
||||
private numericFields: (keyof EventFormDTO)[] = ['event_type_id'];
|
||||
|
||||
frequencyOptions: FrequencyOption[] = [
|
||||
{
|
||||
frequency: 'DAILY',
|
||||
label: 'Napi'
|
||||
label: 'Napi',
|
||||
},
|
||||
{
|
||||
frequency: 'WEEKLY',
|
||||
label: 'Heti'
|
||||
label: 'Heti',
|
||||
}, {
|
||||
frequency: 'MONTHLY',
|
||||
label: 'Havi'
|
||||
label: 'Havi',
|
||||
}, {
|
||||
frequency: 'YEARLY',
|
||||
label: 'Éves'
|
||||
}
|
||||
label: 'Éves',
|
||||
},
|
||||
];
|
||||
|
||||
weekDayOptions = [
|
||||
@ -68,7 +68,7 @@ export class CreateEventForm implements OnInit {
|
||||
private router: Router,
|
||||
private eventService: EventService,
|
||||
private calendarService: CalendarService,
|
||||
private eventTypeService: EventTypeService
|
||||
private eventTypeService: EventTypeService,
|
||||
) {
|
||||
this.form = this.fb.group({
|
||||
eventTypeId: [null, Validators.required],
|
||||
@ -86,18 +86,11 @@ export class CreateEventForm implements OnInit {
|
||||
byMonthDay: [null], // string
|
||||
byMonth: [null], // string
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
effect(() => {
|
||||
console.info("effect run")
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
ngOnInit(): void {
|
||||
console.info("oninit run")
|
||||
this.isRecurring?.valueChanges.subscribe(isRecurring => {
|
||||
const recurringRule = this.form.get('recurrenceRule');
|
||||
const frequency = recurringRule?.get('frequency');
|
||||
@ -118,51 +111,83 @@ export class CreateEventForm implements OnInit {
|
||||
of(this.id()).pipe(
|
||||
tap(id => {
|
||||
if (id) {
|
||||
console.info("edit mode", 'edit')
|
||||
this.isEditMode = true;
|
||||
}else{
|
||||
|
||||
const start = this.date() || new Date();
|
||||
const end = this.date() || new Date();
|
||||
|
||||
console.info("staring form with date", start,end);
|
||||
start.setMinutes(0,0);
|
||||
end.setHours(start.getHours()+1,0,0);
|
||||
start.setMinutes(start.getMinutes() - start.getTimezoneOffset());
|
||||
const startString = start.toISOString().slice(0,16);
|
||||
|
||||
end.setMinutes(end.getMinutes() - end.getTimezoneOffset());
|
||||
const endTime = end.toISOString().slice(0,16);
|
||||
|
||||
console.info("Date start",start.toLocaleString("hu-HU", {timeStyle: 'short', dateStyle: 'short'}));
|
||||
this.form.patchValue({
|
||||
// start_time: new Date().getTime().toString(),
|
||||
startTime: startString,
|
||||
endTime: endTime
|
||||
})
|
||||
}
|
||||
}),
|
||||
mergeMap(() => {
|
||||
return this.eventTypeService.find({});
|
||||
}
|
||||
},
|
||||
),
|
||||
tap(eventTypes => {
|
||||
this.eventTypes.set(eventTypes.data);
|
||||
}),
|
||||
switchMap(() => {
|
||||
if (this.isEditMode && this.id()) {
|
||||
console.info('edit mode', 'edit', this.id());
|
||||
return this.eventService.findOne(this.id()!);
|
||||
}
|
||||
return of(null);
|
||||
}),
|
||||
).subscribe(event => {
|
||||
console.info("subscribe form done")
|
||||
if (event) {
|
||||
this.form.patchValue(event);
|
||||
const startTime = this.formatIsoStringForInput(event.startTime);
|
||||
const endTime = this.formatIsoStringForInput(event.endTime);
|
||||
this.form.patchValue(
|
||||
{
|
||||
title: event.title,
|
||||
description: event.description,
|
||||
startTime,
|
||||
endTime,
|
||||
eventTypeId: event?.eventType?.id,
|
||||
is_recurring: event.isRecurring ,
|
||||
recurrenceRule: {
|
||||
frequency: event.recurrenceRule?.frequency,
|
||||
interval: event.recurrenceRule?.interval,
|
||||
endDate: event.recurrenceRule?.endDate,
|
||||
count: event.recurrenceRule?.count,
|
||||
byDay: event.recurrenceRule?.byDay,
|
||||
byMonthDay: event.recurrenceRule?.byMonthDay,
|
||||
byMonth: event.recurrenceRule?.byMonth,
|
||||
|
||||
},
|
||||
},
|
||||
);
|
||||
} else {
|
||||
|
||||
const start = this.createDate(this.date());
|
||||
const end = this.createDate(this.date(), start.getHours() + 1);
|
||||
|
||||
const startTime = this.formatDateForInput(start);
|
||||
const endTime = this.formatDateForInput(end);
|
||||
|
||||
this.form.patchValue({
|
||||
startTime,
|
||||
endTime,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
createDate(date?: Date, hours?: number) {
|
||||
const start = date ? new Date(date?.getTime()) : new Date();
|
||||
if (hours != undefined) {
|
||||
start.setHours(start.getHours() + hours, 0, 0);
|
||||
} else {
|
||||
start.setMinutes(0, 0);
|
||||
}
|
||||
return start;
|
||||
}
|
||||
|
||||
formatDateForInput(dateObject: Date) {
|
||||
return format(dateObject, 'yyyy-MM-dd\'T\'HH:mm');
|
||||
}
|
||||
|
||||
formatIsoStringForInput(dateString: string) {
|
||||
const date = new Date(dateString);
|
||||
return this.formatDateForInput(date);
|
||||
}
|
||||
|
||||
onByDayChange(event: any) {
|
||||
const target = event.target as HTMLInputElement;
|
||||
const day = target.value;
|
||||
@ -213,8 +238,8 @@ export class CreateEventForm implements OnInit {
|
||||
}
|
||||
|
||||
action$.subscribe({
|
||||
next: () => this.router.navigate(['/events']),
|
||||
error: (err) => console.error('Failed to save event', err)
|
||||
next: () => this.router.navigate(['/calendar']),
|
||||
error: (err) => console.error('Failed to save event', err),
|
||||
});
|
||||
}
|
||||
|
||||
@ -225,12 +250,15 @@ export class CreateEventForm implements OnInit {
|
||||
get title() {
|
||||
return this.form.get('title');
|
||||
}
|
||||
|
||||
get description() {
|
||||
return this.form.get('description');
|
||||
}
|
||||
|
||||
get startTime() {
|
||||
return this.form.get('startTime');
|
||||
}
|
||||
|
||||
get endTime() {
|
||||
return this.form.get('endTime');
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ export class CalendarService {
|
||||
}
|
||||
|
||||
public update(id: number,data: UpdateEventFormDTO): Observable<Event> {
|
||||
return this.http.put<Event>(this.apiUrl+'/events', data);
|
||||
return this.http.patch<Event>(this.apiUrl+'/events/'+id, data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -1,15 +1,35 @@
|
||||
// dvbooking-cli/src/templates/angular/model.ts.tpl
|
||||
|
||||
// Generated by the CLI
|
||||
|
||||
export interface Event {
|
||||
id: number;
|
||||
event_type_id: number;
|
||||
title: string;
|
||||
description: string;
|
||||
start_time: Date;
|
||||
end_time: Date;
|
||||
startTime: string;
|
||||
endTime: string;
|
||||
timezone: string;
|
||||
is_recurring: boolean;
|
||||
created_at: Date;
|
||||
updated_at: Date;
|
||||
isRecurring: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
eventType: EventType;
|
||||
recurrenceRule: RecurrenceRule
|
||||
}
|
||||
export interface EventType{
|
||||
id: number;
|
||||
description:string;
|
||||
name: string;
|
||||
color: string;
|
||||
}
|
||||
|
||||
|
||||
export interface RecurrenceRule{
|
||||
|
||||
frequency?: string,
|
||||
interval?: number,
|
||||
endDate?: string,
|
||||
count?: number,
|
||||
byDay?: string,
|
||||
byMonthDay?: string,
|
||||
byMonth?: string,
|
||||
}
|
||||
|
||||
@ -59,7 +59,8 @@ export class EventService {
|
||||
* Find a single record by its ID.
|
||||
*/
|
||||
public findOne(id: number): Observable<Event> {
|
||||
return this.http.get<Event>(`${this.apiUrl}/${id}`);
|
||||
return this.http.get<Event>(`${this.apiUrl}/${id}`
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -27,24 +27,6 @@ import { CancelBookingDto } from './dto/cancel-booking.dto';
|
||||
export class CalendarController {
|
||||
constructor(private readonly calendarService: CalendarService) {}
|
||||
|
||||
@Get('test')
|
||||
getCalendarTest(
|
||||
@Query('startDate') startDate: string,
|
||||
@Query('endDate') endDate: string,
|
||||
) {
|
||||
console.log('--- TEST ENDPOINT ---');
|
||||
console.log('startDate received:', startDate, '| Type:', typeof startDate);
|
||||
console.log('endDate received:', endDate, '| Type:', typeof endDate);
|
||||
return {
|
||||
message: 'Test successful. Check your server console logs.',
|
||||
received: {
|
||||
startDate,
|
||||
endDate,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// The primary endpoint to get event occurrences
|
||||
@Get()
|
||||
getCalendarEvents(@Query() getCalendarDto: GetCalendarDto) {
|
||||
return this.calendarService.getEventsInRange(
|
||||
|
||||
@ -204,9 +204,6 @@ export class CalendarService {
|
||||
// --- Other service methods (createEvent, etc.) remain unchanged ---
|
||||
|
||||
async createEvent(createEventDto: CreateEventDto): Promise<Event> {
|
||||
console.log('[CalendarService] Entering createEvent method.');
|
||||
console.log('[CalendarService] Received DTO:', JSON.stringify(createEventDto, null, 2));
|
||||
|
||||
const { recurrenceRule, ...eventData } = createEventDto;
|
||||
|
||||
const newEvent: Omit<
|
||||
@ -224,19 +221,26 @@ export class CalendarService {
|
||||
|
||||
// check if event type exists
|
||||
if (eventData.eventTypeId) {
|
||||
console.log(`[CalendarService] Event has eventTypeId: ${eventData.eventTypeId}. Fetching event type...`);
|
||||
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.`);
|
||||
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);
|
||||
console.log(
|
||||
'[CalendarService] Successfully attached event type:',
|
||||
eventType,
|
||||
);
|
||||
} else {
|
||||
console.log('[CalendarService] No eventTypeId provided.');
|
||||
}
|
||||
@ -246,10 +250,15 @@ export class CalendarService {
|
||||
|
||||
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);
|
||||
console.log(
|
||||
'[CalendarService] Event saved successfully. Saved event ID:',
|
||||
savedEvent.id,
|
||||
);
|
||||
|
||||
if (savedEvent.isRecurring && recurrenceRule) {
|
||||
console.log(`[CalendarService] Event is recurring. Creating recurrence rule...`);
|
||||
console.log(
|
||||
`[CalendarService] Event is recurring. Creating recurrence rule...`,
|
||||
);
|
||||
const rule = this.recurrenceRuleRepository.create({
|
||||
...recurrenceRule,
|
||||
event: savedEvent,
|
||||
@ -257,10 +266,14 @@ export class CalendarService {
|
||||
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.');
|
||||
console.log(
|
||||
'[CalendarService] Event is not recurring or no recurrence rule provided.',
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`[CalendarService] Fetching final event by ID ${savedEvent.id} to return.`);
|
||||
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;
|
||||
@ -333,7 +346,59 @@ export class CalendarService {
|
||||
id: number,
|
||||
updateEventDto: CreateEventDto,
|
||||
): Promise<Event> {
|
||||
await this.eventRepository.update(id, updateEventDto);
|
||||
// 1. Fetch the existing event (ensure relations are loaded if needed)
|
||||
const event = await this.getEventById(id);
|
||||
|
||||
// 2. Update basic fields
|
||||
event.updatedAt = new Date();
|
||||
event.title = updateEventDto.title;
|
||||
event.description = updateEventDto.description;
|
||||
event.startTime = updateEventDto.startTime;
|
||||
event.endTime = updateEventDto.endTime;
|
||||
event.isRecurring = !!updateEventDto.isRecurring;
|
||||
|
||||
// 3. Handle Event Type Relationship
|
||||
if (updateEventDto.eventTypeId) {
|
||||
const eventType = await this.eventTypeRepository.findOneBy({
|
||||
id: updateEventDto.eventTypeId,
|
||||
});
|
||||
if (!eventType) {
|
||||
throw new NotFoundException(
|
||||
`EventType with ID ${updateEventDto.eventTypeId} not found`,
|
||||
);
|
||||
}
|
||||
// FIX: You forgot to assign this in your original code
|
||||
event.eventType = eventType;
|
||||
} else {
|
||||
// Handle case where event type is removed/null
|
||||
event.eventType = undefined;
|
||||
}
|
||||
|
||||
// 4. Handle Recurrence Rule
|
||||
// Because your entity has @OneToOne(..., { cascade: true }),
|
||||
// modifying event.recurrenceRule and calling eventRepository.save(event)
|
||||
// will automatically save/update the rule.
|
||||
if (event.isRecurring && updateEventDto.recurrenceRule) {
|
||||
const updateRRule = updateEventDto.recurrenceRule;
|
||||
|
||||
// If no rule exists yet, initialize a new one
|
||||
if (!event.recurrenceRule) {
|
||||
event.recurrenceRule = this.recurrenceRuleRepository.create({});
|
||||
}
|
||||
|
||||
// Update the properties on the relation object
|
||||
event.recurrenceRule.frequency = updateRRule.frequency;
|
||||
event.recurrenceRule.interval = updateRRule.interval;
|
||||
event.recurrenceRule.byDay = updateRRule.byDay as string;
|
||||
event.recurrenceRule.endDate = updateRRule.endDate as Date;
|
||||
event.recurrenceRule.count = updateRRule.count as number;
|
||||
}
|
||||
|
||||
// 5. Use SAVE instead of UPDATE
|
||||
// This handles the relations correctly and prevents the "one-to-many" error.
|
||||
await this.eventRepository.save(event);
|
||||
|
||||
// 6. Return the updated event
|
||||
return this.getEventById(id);
|
||||
}
|
||||
|
||||
|
||||
@ -80,7 +80,10 @@ export class EventsService {
|
||||
}
|
||||
|
||||
async findOne(id: number) {
|
||||
const record = await this.eventRepository.findOneBy({ id: id as any });
|
||||
const record = await this.eventRepository.findOne({
|
||||
where: { id: id },
|
||||
relations: ['eventType', 'recurrenceRule', 'exceptions'],
|
||||
});
|
||||
if (!record) {
|
||||
throw new NotFoundException(`Event with ID ${id} not found`);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user