implement edit event
This commit is contained in:
parent
71a8e267dc
commit
e1ae0a36d7
28
admin/src/app/components/detail-view/detail-view.html
Normal file
28
admin/src/app/components/detail-view/detail-view.html
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
{{config().data}}
|
||||||
|
@if (config().data){
|
||||||
|
<div class="overflow-x-auto" [ngClass]="config().styleClass">
|
||||||
|
<table class="table w-full">
|
||||||
|
<tbody>
|
||||||
|
@for (row of config().rows; track row.attribute) {
|
||||||
|
<tr [ngClass]="row.getDetailClass ? row.getDetailClass(config().data) : ''">
|
||||||
|
<th [ngClass]="row.getTitleStyleClass ? row.getTitleStyleClass(config().data) : ''">
|
||||||
|
@if (row.titleComponent) {
|
||||||
|
<ng-container *ngComponentOutlet="row.titleComponent; inputs: row.titleComponentInputs ? row.titleComponentInputs(config().data) : {}"></ng-container>
|
||||||
|
} @else {
|
||||||
|
{{ getTitle(row, config().data) }}
|
||||||
|
}
|
||||||
|
</th>
|
||||||
|
<td [ngClass]="row.getValueStyleClass ? row.getValueStyleClass(config().data) : ''">
|
||||||
|
@if (row.component) {
|
||||||
|
<ng-container *ngComponentOutlet="row.component; inputs: row.componentInputs ? row.componentInputs(config().data) : {}"></ng-container>
|
||||||
|
} @else {
|
||||||
|
{{ getFormattedValue(row, config().data) }}
|
||||||
|
}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
}
|
||||||
23
admin/src/app/components/detail-view/detail-view.spec.ts
Normal file
23
admin/src/app/components/detail-view/detail-view.spec.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
|
import { DetailView } from './detail-view';
|
||||||
|
|
||||||
|
describe('DetailView', () => {
|
||||||
|
let component: DetailView;
|
||||||
|
let fixture: ComponentFixture<DetailView>;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
await TestBed.configureTestingModule({
|
||||||
|
imports: [DetailView]
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
|
||||||
|
fixture = TestBed.createComponent(DetailView);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
||||||
70
admin/src/app/components/detail-view/detail-view.ts
Normal file
70
admin/src/app/components/detail-view/detail-view.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { Component, input, Type } from '@angular/core';
|
||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
|
||||||
|
export interface CellComponent<T> {
|
||||||
|
component?: Type<any>;
|
||||||
|
componentInputs?: (obj: T) => { [key: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DetailViewRow<T> extends CellComponent<T> {
|
||||||
|
attribute: keyof T;
|
||||||
|
getValue?: (obj: T) => any;
|
||||||
|
format?: 'date' | 'datetime' | 'number' | 'raw' | ((value: any) => string);
|
||||||
|
getTitle?: string | ((obj: T) => string);
|
||||||
|
getDetailClass?: (obj: T) => string;
|
||||||
|
getTitleStyleClass?: (obj: T) => string;
|
||||||
|
getValueStyleClass?: (obj: T) => string;
|
||||||
|
titleComponent?: Type<any>;
|
||||||
|
titleComponentInputs?: (obj: T) => { [key: string]: any };
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DetailViewConfig<T> {
|
||||||
|
data: T;
|
||||||
|
rows: DetailViewRow<T>[];
|
||||||
|
styleClass?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-detail-view',
|
||||||
|
imports: [CommonModule],
|
||||||
|
templateUrl: './detail-view.html',
|
||||||
|
styleUrl: './detail-view.css',
|
||||||
|
})
|
||||||
|
export class DetailView<T> {
|
||||||
|
config = input.required<DetailViewConfig<T>>();
|
||||||
|
|
||||||
|
getFormattedValue(row: DetailViewRow<T>, data: T): string {
|
||||||
|
const value = row.getValue ? row.getValue(data) : data[row.attribute];
|
||||||
|
|
||||||
|
if (row.component) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof row.format === 'function') {
|
||||||
|
return row.format(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (row.format) {
|
||||||
|
case 'date':
|
||||||
|
return new Date(value).toLocaleDateString();
|
||||||
|
case 'datetime':
|
||||||
|
return new Date(value).toLocaleString();
|
||||||
|
case 'number':
|
||||||
|
return Number(value).toString();
|
||||||
|
case 'raw':
|
||||||
|
default:
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getTitle(row: DetailViewRow<T>, data: T): string {
|
||||||
|
if (row.titleComponent) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof row.getTitle === 'function') {
|
||||||
|
return row.getTitle(data);
|
||||||
|
}
|
||||||
|
return row.getTitle || String(row.attribute);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,11 +6,18 @@
|
|||||||
</div>
|
</div>
|
||||||
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
|
<full-calendar #calendar [options]="calendarOptions"></full-calendar>
|
||||||
</div>
|
</div>
|
||||||
|
{{"workflow:"+workflow()}}
|
||||||
<rs-daisy-modal [isOpen]="isOpen()" (closeClick)="closeDialog()" >
|
<rs-daisy-modal [isOpen]="workflow() == 'create'" (closeClick)="closeDialog()">
|
||||||
@if (isOpen()){
|
@if (workflow() == 'create') {
|
||||||
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()" [id]="selectedEventId()"></app-create-event-form>
|
<app-create-event-form (ready)="closeDialog()" [date]="selectedDate()"
|
||||||
|
[id]="undefined"></app-create-event-form>
|
||||||
}
|
}
|
||||||
|
|
||||||
</rs-daisy-modal>
|
</rs-daisy-modal>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@if (workflow() == 'event-dashboard' && selectedEvent()) {
|
||||||
|
<rs-daisy-modal [isOpen]="true" (closeClick)="closeDialog()">
|
||||||
|
<app-single-event-dashboard [event]="selectedEvent()"></app-single-event-dashboard>
|
||||||
|
</rs-daisy-modal>
|
||||||
|
}
|
||||||
|
|||||||
@ -9,13 +9,13 @@ import interactionPlugin from '@fullcalendar/interaction';
|
|||||||
import { Modal } from '@rschneider/ng-daisyui';
|
import { Modal } from '@rschneider/ng-daisyui';
|
||||||
import { CreateEventForm } from '../create-event-form/create-event-form';
|
import { CreateEventForm } from '../create-event-form/create-event-form';
|
||||||
import { CalendarService } from '../../services/calendar.service';
|
import { CalendarService } from '../../services/calendar.service';
|
||||||
import { addDays, subDays } from 'date-fns';
|
import { CalendarEventDto, EventsInRangeDTO } from '../../models/events-in-range-dto.model';
|
||||||
import { EventsInRangeDTO } from '../../models/events-in-range-dto.model';
|
|
||||||
import { map } from 'rxjs';
|
import { map } from 'rxjs';
|
||||||
|
import { SingleEventDashboard } from './single-event-dashboard/single-event-dashboard';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-calendar-view',
|
selector: 'app-calendar-view',
|
||||||
imports: [FullCalendarModule, Modal, CreateEventForm],
|
imports: [FullCalendarModule, Modal, CreateEventForm, SingleEventDashboard],
|
||||||
templateUrl: './calendar-view.html',
|
templateUrl: './calendar-view.html',
|
||||||
styleUrl: './calendar-view.css',
|
styleUrl: './calendar-view.css',
|
||||||
})
|
})
|
||||||
@ -27,67 +27,40 @@ export class CalendarView implements OnInit, AfterViewInit {
|
|||||||
calendarService = inject(CalendarService);
|
calendarService = inject(CalendarService);
|
||||||
|
|
||||||
workflow = signal<string>('');
|
workflow = signal<string>('');
|
||||||
isOpen = signal<boolean>(false);
|
|
||||||
selectedDate = signal<Date|undefined>(undefined);
|
selectedDate = signal<Date|undefined>(undefined);
|
||||||
selectedEventId = signal<number|undefined>(undefined)
|
selectedEvent = signal<CalendarEventDto|undefined>(undefined)
|
||||||
|
|
||||||
events = signal<EventsInRangeDTO[]>([]);
|
|
||||||
|
|
||||||
calendarOptions: CalendarOptions;
|
calendarOptions: CalendarOptions;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
const start = new Date();
|
|
||||||
start.setHours(10, 0, 0);
|
|
||||||
const end = new Date();
|
|
||||||
end.setHours(11, 0, 0);
|
|
||||||
|
|
||||||
|
|
||||||
this.calendarOptions = {
|
this.calendarOptions = {
|
||||||
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
|
plugins: [dayGridPlugin, timeGridPlugin, listPlugin, interactionPlugin],
|
||||||
initialView: 'dayGridMonth',
|
initialView: 'dayGridMonth',
|
||||||
weekends: true,
|
weekends: true,
|
||||||
|
firstDay: 1,
|
||||||
headerToolbar: {
|
headerToolbar: {
|
||||||
left: 'prev,next,today',
|
left: 'prev,next,today',
|
||||||
center: 'title',
|
center: 'title',
|
||||||
// right: 'dayGridMonth,dayGridWeek,dayGridDay' // user can switch between the two
|
|
||||||
right: 'dayGridMonth,dayGridWeek,dayGridDay,timeGridWeek,timeGridDay,listWeek',
|
right: 'dayGridMonth,dayGridWeek,dayGridDay,timeGridWeek,timeGridDay,listWeek',
|
||||||
|
|
||||||
},
|
},
|
||||||
events: this.fetchEvents.bind(this), // Bind the context
|
events: this.fetchEvents.bind(this), // Bind the context
|
||||||
|
|
||||||
eventClick: function(info) {
|
eventClick: (info) => {
|
||||||
console.info('Event info: ', info);
|
this.selectedEvent.set(info.event.extendedProps['event']);
|
||||||
|
this.workflow.set('event-dashboard');
|
||||||
// change the border color just for fun
|
|
||||||
info.el.style.borderColor = 'red';
|
|
||||||
},
|
},
|
||||||
|
|
||||||
dateClick: (info) => {
|
dateClick: (info) => {
|
||||||
console.info('setting day ',info);
|
console.info('create new evet for day ',info);
|
||||||
this.workflow.set('day');
|
this.workflow.set('create');
|
||||||
this.selectedDate.set(info.date);
|
this.selectedDate.set(info.date);
|
||||||
this.selectedEventId.set(undefined);
|
this.selectedEvent.set(undefined);
|
||||||
console.info("date click with", this.selectedDate())
|
|
||||||
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
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchEvents(fetchInfo: any, successCallback: (events: EventInput[]) => void, failureCallback: (error: any) => void): void {
|
fetchEvents(fetchInfo: any, successCallback: (events: EventInput[]) => void, failureCallback: (error: any) => void): void {
|
||||||
@ -111,7 +84,10 @@ export class CalendarView implements OnInit, AfterViewInit {
|
|||||||
const calendarEvent: EventInput = {
|
const calendarEvent: EventInput = {
|
||||||
start: new Date(model.startTime),
|
start: new Date(model.startTime),
|
||||||
// end: model.end_time,
|
// end: model.end_time,
|
||||||
title: model.title
|
title: model.title,
|
||||||
|
extendedProps: {
|
||||||
|
event: value
|
||||||
|
}
|
||||||
};
|
};
|
||||||
if ( model.eventType){
|
if ( model.eventType){
|
||||||
calendarEvent.borderColor = model.eventType.color;
|
calendarEvent.borderColor = model.eventType.color;
|
||||||
@ -160,6 +136,6 @@ export class CalendarView implements OnInit, AfterViewInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
closeDialog() {
|
closeDialog() {
|
||||||
this.isOpen.set(false);
|
this.workflow.set('');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,3 @@
|
|||||||
|
<app-detail-view
|
||||||
|
[config]="config"
|
||||||
|
></app-detail-view>
|
||||||
@ -0,0 +1,28 @@
|
|||||||
|
import { Component, input, signal } from '@angular/core';
|
||||||
|
import { CalendarEventDto, EventsInRangeDTO } from '../../../models/events-in-range-dto.model';
|
||||||
|
import { DetailView, DetailViewConfig } from '../../../../../components/detail-view/detail-view';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-single-event-dashboard',
|
||||||
|
imports: [
|
||||||
|
DetailView,
|
||||||
|
],
|
||||||
|
templateUrl: './single-event-dashboard.html',
|
||||||
|
styleUrl: './single-event-dashboard.css',
|
||||||
|
})
|
||||||
|
export class SingleEventDashboard {
|
||||||
|
|
||||||
|
event = input<CalendarEventDto>();
|
||||||
|
|
||||||
|
config: DetailViewConfig<CalendarEventDto>;
|
||||||
|
constructor() {
|
||||||
|
this.config = {
|
||||||
|
data: this.event()!,
|
||||||
|
|
||||||
|
rows: [{
|
||||||
|
attribute: 'title',
|
||||||
|
getTitle: 'title',
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user