add calendarview event creation

This commit is contained in:
Schneider Roland
2025-11-23 22:26:16 +01:00
parent 008b644bb1
commit 6b975dadac
24 changed files with 583 additions and 31 deletions

View File

@@ -6,3 +6,8 @@
</div>
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
</div>
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
<app-create-event-form (ready)="closeDialog()"></app-create-event-form>
</rs-daisy-modal>

View File

@@ -1,4 +1,4 @@
import { Component, ElementRef, ViewChild } from '@angular/core';
import { AfterViewInit, Component, effect, ElementRef, inject, OnInit, signal, ViewChild } from '@angular/core';
import { FullCalendarComponent, FullCalendarModule } from '@fullcalendar/angular';
import { CalendarOptions } from '@fullcalendar/core';
@@ -6,19 +6,30 @@ import dayGridPlugin from '@fullcalendar/daygrid';
import timeGridPlugin from '@fullcalendar/timegrid';
import listPlugin from '@fullcalendar/list';
import interactionPlugin from '@fullcalendar/interaction';
import { appConfig } from '../../../../app.config';
import { Modal } from '@rschneider/ng-daisyui';
import { CreateEventForm } from '../create-event-form/create-event-form';
import { CalendarService } from '../../services/calendar.service';
import { addDays, subDays } from 'date-fns';
import { EventsInRangeDTO } from '../../models/events-in-range-dto.model';
@Component({
selector: 'app-calendar-view',
imports: [FullCalendarModule],
imports: [FullCalendarModule, Modal, CreateEventForm],
templateUrl: './calendar-view.html',
styleUrl: './calendar-view.css',
})
export class CalendarView {
export class CalendarView implements OnInit, AfterViewInit {
@ViewChild('startHour') startHour!: ElementRef;
@ViewChild('calendar') calendarComponent: FullCalendarComponent | undefined;
calendarService = inject(CalendarService);
workflow = signal<string>("")
isOpen = signal<boolean>(false);
events = signal<EventsInRangeDTO[]>([])
calendarOptions: CalendarOptions;
constructor() {
@@ -27,6 +38,7 @@ export class CalendarView {
const end = new Date();
end.setHours(11,0,0)
this.calendarOptions = {
plugins: [dayGridPlugin, timeGridPlugin, listPlugin,interactionPlugin],
initialView: 'dayGridMonth',
@@ -41,7 +53,6 @@ export class CalendarView {
events: [
{ title: 'Meeting1 until'+end.toString(), start, end },
],
eventClick: function(info) {
@@ -51,21 +62,54 @@ export class CalendarView {
info.el.style.borderColor = 'red';
},
dateClick: function(info) {
console.info('Date click on: ' , info);
const calendarApi = info.view.calendar;
const start = new Date(info.date.getTime())
start.setHours(2,0,0)
const end = new Date(info.date.getTime())
end.setHours(3,0,0)
calendarApi.addEvent({
title: 'New Event',
start,
end,
});
dateClick: (info) => {
console.info("setting day workflow");
this.workflow.set("day");
this.isOpen.set(true);
// console.info('Date click on: ' , info);
// const calendarApi = info.view.calendar;
// const start = new Date(info.date.getTime())
// start.setHours(2,0,0)
// const end = new Date(info.date.getTime())
// end.setHours(3,0,0)
// calendarApi.addEvent({
// title: 'New Event',
// start,
// end,
// });
}
};
effect(() => {
// this.calendarOptions.events = this.events
});
}
ngAfterViewInit(): void {
// this.calendarComponent?.getApi().
}
ngOnInit(): void {
const start = subDays(new Date(),14)
const end = addDays(new Date(),14);
this.calendarService.getEventsInRange({
startTime: start,
endTime: end
}).subscribe(
{
'next': (events) => {
console.info('events',events)
}
}
)
}
protected addEvent($event: PointerEvent) {
@@ -82,4 +126,8 @@ export class CalendarView {
start
})
}
closeDialog() {
this.isOpen.set(false)
}
}

View File

@@ -0,0 +1,51 @@
<!-- 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-body">
<h2 class="card-title text-3xl">
Esemény {{ isEditMode ? 'szerkesztése' : 'létrehozása' }}
</h2>
<form [formGroup]="form" (ngSubmit)="onSubmit()" class="space-y-4 mt-4">
<div class="form-control"><label class="label"><span class="label-text">Megnevezés</span></label>
<input [class.input-error]="title?.invalid && title?.touched" type="text" formControlName="title" class="input input-bordered w-full" />
</div>
<div class="form-control"><label class="label"><span class="label-text">Esemény típus</span></label>
<select class="select w-full"
formControlName="eventTypeId"
[class.input-error]="eventType?.invalid && eventType?.touched"
>
<option disabled selected>Pick a color</option>
@for (eventType of eventTypes(); track eventType.id) {
<option [value]="eventType.id">{{ eventType.name }}</option>
}
</select>
</div>
<div class="form-control"><label class="label"><span class="label-text">Leírás</span></label>
<input [class.input-error]="description?.invalid && description?.touched" type="text" formControlName="description" class="input input-bordered w-full" /></div>
<div class="form-control"><label class="label"><span class="label-text">Kezdő időpont</span></label>
<input [class.input-error]="startTime?.invalid && startTime?.touched" type="datetime-local" formControlName="startTime" class="input input-bordered w-full" /></div>
<div class="form-control"><label class="label"><span class="label-text">Befejezési időpont</span></label>
<input [class.input-error]="endTime?.invalid && endTime?.touched" type="datetime-local" formControlName="endTime" class="input input-bordered w-full" /></div>
<div class="form-control"><label class="label cursor-pointer justify-start gap-4">
<span class="label-text">Ismétlődő</span>
<input type="checkbox" formControlName="is_recurring" class="checkbox" />
</label></div>
<div class="card-actions justify-end mt-6">
<a routerLink="/events" class="btn btn-ghost">Mégse</a>
<button type="submit" class="btn btn-primary" [disabled]="form.invalid">
{{ isEditMode ? 'Mentés' : 'Létrezhozás' }}
</button>
</div>
</form>
</div>
</div>
</div>

View File

@@ -0,0 +1,146 @@
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';
import { mergeMap, switchMap, tap } from 'rxjs/operators';
import { Observable, of } from 'rxjs';
import { Event } from '../../../events/models/event.model';
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';
@Component({
selector: 'app-create-event-form',
imports: [
ReactiveFormsModule
],
templateUrl: './create-event-form.html',
styleUrl: './create-event-form.css',
})
export class CreateEventForm implements OnInit {
form: FormGroup;
isEditMode = false;
ready = output<void>();
id= input<number | null>() ;
eventTypes = signal<EventType[]>([])
private numericFields = ["event_type_id"];
constructor(
private fb: FormBuilder,
private route: ActivatedRoute,
private router: Router,
private eventService: EventService,
private calendarService: CalendarService,
private eventTypeService: EventTypeService
) {
this.form = this.fb.group({
eventTypeId: [null,Validators.required],
title: [null,Validators.required],
description: [null],
startTime: [null,Validators.required],
endTime: [null,Validators.required],
is_recurring: [null],
});
}
ngOnInit(): void {
of(this.id()).pipe(
tap(id => {
if (id) {
this.isEditMode = true;
}else{
const start = new Date();
const end = new Date();
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()) {
return this.eventService.findOne(this.id()!);
}
return of(null);
}),
).subscribe(event => {
if (event) {
this.form.patchValue(event);
}
});
}
onSubmit(): void {
if (this.form.invalid) {
this.form.markAllAsTouched();
return;
}
const payload: EventFormDTO|any = { ...this.form.value };
for (const field of this.numericFields) {
if (payload[field] != null && payload[field] !== '') {
payload[field] = parseFloat(payload[field]);
}
}
let action$: Observable<Event>;
if (this.isEditMode && this.id()) {
console.info("rong branch")
// action$ = this.calendarService.update(this.id()!, payload);
action$ = of(payload);
} else {
action$ = this.calendarService.create(payload);
}
action$.subscribe({
next: () => this.router.navigate(['/events']),
error: (err) => console.error('Failed to save event', err)
});
}
get eventType(){
return this.form.get('eventTypeId');
}
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');
}
doReady(){
this.ready.emit();
}
}