git init v2
This commit is contained in:
84
src/app/pages/agenda/agenda.component.html
Normal file
84
src/app/pages/agenda/agenda.component.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<div class="container">
|
||||
<div class="heading">
|
||||
<button
|
||||
appearance="primary"
|
||||
iconStart="@tui.chevron-left"
|
||||
size="m"
|
||||
tuiIconButton
|
||||
(click)="previousDay()"
|
||||
type="button">
|
||||
</button>
|
||||
<h1 class="date" (click)="toggleCalendar()">{{ getDate() }}</h1>
|
||||
<button
|
||||
appearance="primary"
|
||||
iconStart="@tui.chevron-right"
|
||||
size="m"
|
||||
tuiIconButton
|
||||
(click)="nextDay()"
|
||||
type="button">
|
||||
</button>
|
||||
</div>
|
||||
<div class="calendar" *ngIf="showCalendar">
|
||||
<tui-calendar
|
||||
[value]="value"
|
||||
(dayClick)="onDayClick($event)"
|
||||
/>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<button
|
||||
*ngIf="today.getDate() != selectedDate.getDate()"
|
||||
appearance="secondary"
|
||||
size="m"
|
||||
tuiButton
|
||||
(click)="setToday()"
|
||||
type="button">
|
||||
Vandaag
|
||||
</button>
|
||||
<button
|
||||
appearance="secondary"
|
||||
size="m"
|
||||
tuiButton
|
||||
(click)="isModalOpen = true"
|
||||
type="button">
|
||||
<tui-icon
|
||||
icon="@tui.plus"
|
||||
[style.height.rem]="1"
|
||||
/>
|
||||
Afspraak maken
|
||||
</button>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div class="agenda-container">
|
||||
<div *ngFor="let hour of timeSlots" class="time-slot">
|
||||
<span class="time">{{ hour.toString().padStart(2, '0') }}:00</span>
|
||||
|
||||
<div *ngFor="let appointment of getAppointmentsForHour(hour)"
|
||||
class="appointment"
|
||||
(click)="selectAppointment(appointment)"
|
||||
[ngClass]="{ 'large': (getAppointmentHeight(appointment) > 50) }"
|
||||
[ngStyle]="getInlineStyles(appointment)">
|
||||
|
||||
<strong>{{ appointment.title }}</strong>
|
||||
<span class="appointment-time" *ngIf="appointment.customer">
|
||||
<tui-icon icon="@tui.user" [style.font-size.rem]="1"></tui-icon>
|
||||
{{ appointment.customer.firstName }} {{ appointment.customer.lastName }}</span>
|
||||
<span class="appointment-time">
|
||||
<tui-icon icon="@tui.clock" [style.font-size.rem]="1"></tui-icon>
|
||||
{{ getFormattedTime(appointment.startHour, appointment.startMinute) }}
|
||||
- {{ getFormattedTime(appointment.endHour, appointment.endMinute) }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<app-modal title="Nieuwe afspraak" (close)="closeNewItemModal()" *ngIf="isModalOpen">
|
||||
<app-new-item [testForm]="appointmentForm" (appointmentAddedEvent)="registerAppointment($event)"></app-new-item>
|
||||
</app-modal>
|
||||
|
||||
<app-modal title="{{selectedAppointment.title}}" (close)="selectedAppointment = undefined"
|
||||
*ngIf="selectedAppointment != undefined">
|
||||
<app-details [appointment]="selectedAppointment" (appointmentDeleted)="appointmentIsDeleted($event)"
|
||||
(appointmentEdited)="appointmentIsEdited($event)"></app-details>
|
||||
</app-modal>
|
||||
141
src/app/pages/agenda/agenda.component.scss
Normal file
141
src/app/pages/agenda/agenda.component.scss
Normal file
@@ -0,0 +1,141 @@
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
background-color: #f9f9f9;
|
||||
margin: 10px 0;
|
||||
padding: 10px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 5px 0 0;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.calendar {
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.time-slot {
|
||||
height: 25px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
font-size: 14px;
|
||||
background: #f9f9f9;
|
||||
transition: background 0.3s ease;
|
||||
}
|
||||
|
||||
.time-slot.claimed {
|
||||
background: #d1e7dd; /* Lichtgroene achtergrond voor gereserveerde blokken */
|
||||
color: #155724;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.time-slot:nth-child(odd) {
|
||||
background: #ececec;
|
||||
}
|
||||
|
||||
.time {
|
||||
width: 50px;
|
||||
font-weight: bold;
|
||||
margin-top: 20px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.content {
|
||||
overflow-y: scroll;
|
||||
max-height: 70vh;
|
||||
}
|
||||
|
||||
.agenda-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid #ddd;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.time-slot {
|
||||
position: relative;
|
||||
border-bottom: 1px solid #ccc;
|
||||
height: 59px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
font-size: 16px;
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
.appointment {
|
||||
position: absolute;
|
||||
left: 80px;
|
||||
width: calc(100% - 100px);
|
||||
background: #1e88e5;
|
||||
color: white;
|
||||
border-radius: 4px;
|
||||
border-left: 5px solid #1565c0;
|
||||
box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2);
|
||||
|
||||
z-index: 10;
|
||||
cursor: pointer;
|
||||
display: grid;
|
||||
grid-auto-flow: column;
|
||||
align-items: center;
|
||||
//gap: 5px;
|
||||
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.appointment.large {
|
||||
grid-auto-flow: row;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
strong, p {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.appointment-time {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
.toolbar {
|
||||
button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
margin-bottom: 12px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.date {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.date:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
206
src/app/pages/agenda/agenda.component.ts
Normal file
206
src/app/pages/agenda/agenda.component.ts
Normal file
@@ -0,0 +1,206 @@
|
||||
import {Component, inject, OnInit} from '@angular/core';
|
||||
import {CommonModule, NgFor, NgIf} from '@angular/common';
|
||||
import {TuiAlertService, TuiButton, TuiCalendar, tuiDateFormatProvider, TuiIcon} from '@taiga-ui/core';
|
||||
import {Appointment} from '../../models/appointment';
|
||||
import {ModalComponent} from '../../components/modal/modal.component';
|
||||
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
|
||||
import {
|
||||
TuiInputDateModule,
|
||||
TuiInputModule,
|
||||
TuiInputTimeModule,
|
||||
TuiTextareaModule,
|
||||
TuiTextfieldControllerModule
|
||||
} from '@taiga-ui/legacy';
|
||||
import {TuiDay, TuiTime} from '@taiga-ui/cdk';
|
||||
import {AppointmentService} from '../../services/appointment.service';
|
||||
import {DetailsComponent} from '../../components/details/details.component';
|
||||
import {DateFormatter} from '../../utils/date-formatter';
|
||||
import {WeekDay} from '../../models/week-day';
|
||||
import {NewItemComponent} from '../../components/new-item/new-item.component';
|
||||
|
||||
@Component({
|
||||
selector: 'app-agenda',
|
||||
imports: [NgFor,
|
||||
TuiButton, CommonModule, NgIf, ModalComponent, ReactiveFormsModule,
|
||||
TuiInputTimeModule, TuiTextfieldControllerModule,
|
||||
TuiInputModule, TuiTextareaModule, TuiInputDateModule, TuiIcon, DetailsComponent, TuiCalendar, NewItemComponent],
|
||||
templateUrl: './agenda.component.html',
|
||||
providers: [tuiDateFormatProvider({separator: '-'}), AppointmentService],
|
||||
styleUrl: './agenda.component.scss'
|
||||
})
|
||||
export class AgendaComponent implements OnInit {
|
||||
|
||||
constructor(private appointmentService: AppointmentService) {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
}
|
||||
|
||||
timeSlots: number[] = Array.from({length: 24}, (_, i) => i); // 24 uren
|
||||
appointments: Appointment[] = [];
|
||||
isModalOpen = false
|
||||
today = new Date()
|
||||
selectedDate = new Date()
|
||||
waiting: boolean = false;
|
||||
selectedAppointment: Appointment;
|
||||
protected value: TuiDay | null = null;
|
||||
showCalendar: boolean = false;
|
||||
|
||||
private readonly alerts = inject(TuiAlertService);
|
||||
protected appointmentForm = new FormGroup({
|
||||
title: new FormControl('', Validators.required),
|
||||
notes: new FormControl(''),
|
||||
startTime: new FormControl(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required),
|
||||
endTime: new FormControl(new TuiTime(this.getHours(), this.getMinutes()), Validators.required),
|
||||
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
||||
});
|
||||
|
||||
registerAppointment(title: string): void {
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
this.waiting = false
|
||||
this.isModalOpen = false
|
||||
this.showNotification(title)
|
||||
this.resetForms()
|
||||
}
|
||||
|
||||
protected showNotification(message: string): void {
|
||||
this.alerts
|
||||
.open(`Afspraak <strong>${message}</strong> is aangemaakt.`)
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
getAppointmentsForHour(hour: number) {
|
||||
return this.appointments.filter(appointment => appointment.startHour === hour);
|
||||
}
|
||||
|
||||
getDate(): string {
|
||||
const date = this.selectedDate
|
||||
|
||||
const weekDay = WeekDay[date.getDay()];
|
||||
const day = date.getDate().toString().padStart(2, '0'); // Dag met leading zero (01, 02, ..., 31)
|
||||
const monthName = date.toLocaleString('nl-NL', {month: 'long'});
|
||||
const year = date.getFullYear().toString(); // Volledig jaar
|
||||
|
||||
return `${weekDay} ${day} ${monthName} ${year}`;
|
||||
}
|
||||
|
||||
resetForms() {
|
||||
this.appointmentForm = new FormGroup({
|
||||
title: new FormControl('', Validators.required),
|
||||
notes: new FormControl(''),
|
||||
startTime: new FormControl(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required),
|
||||
endTime: new FormControl(new TuiTime(this.getEndTime().getHours(), this.getEndTime().getMinutes()), Validators.required),
|
||||
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
||||
});
|
||||
}
|
||||
|
||||
nextDay() {
|
||||
this.selectedDate.setDate(this.selectedDate.getDate() + 1);
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
this.appointmentForm.get('date').setValue(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()))
|
||||
}
|
||||
|
||||
previousDay() {
|
||||
this.selectedDate.setDate(this.selectedDate.getDate() - 1);
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
this.appointmentForm.get('date').setValue(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()))
|
||||
}
|
||||
|
||||
getHours() {
|
||||
let hours = this.today.getHours()
|
||||
console.log(hours)
|
||||
if (hours > 23) {
|
||||
return 23
|
||||
}
|
||||
return hours
|
||||
}
|
||||
|
||||
getMinutes() {
|
||||
let minutes = this.today.getMinutes() + 30
|
||||
if (minutes > 59) {
|
||||
return 59
|
||||
}
|
||||
return minutes
|
||||
}
|
||||
|
||||
getEndTime(): Date {
|
||||
const endTime = new Date(this.today); // Kopieer startTime
|
||||
endTime.setMinutes(endTime.getMinutes() + 30); // 30 minuten toevoegen
|
||||
|
||||
// Controleer of de dag nog steeds hetzelfde is
|
||||
if (endTime.getDate() !== this.today.getDate()) {
|
||||
endTime.setHours(23, 59, 59, 999); // Zet naar 23:59:59 als het overloopt
|
||||
}
|
||||
|
||||
return endTime;
|
||||
}
|
||||
|
||||
|
||||
setToday() {
|
||||
this.selectedDate = new Date()
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
this.appointmentForm.get('date').setValue(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()))
|
||||
}
|
||||
|
||||
getAppointmentsByDate(date: Date) {
|
||||
this.appointmentService.getAppointmentsByDate(date).subscribe(appointments => {
|
||||
this.appointments = appointments;
|
||||
})
|
||||
}
|
||||
|
||||
getInlineStyles(appointment: Appointment): { [key: string]: string } {
|
||||
return {
|
||||
'--duration': `${appointment.durationInMinutes}`,
|
||||
'--start-minute': `${appointment.startMinute}`,
|
||||
'top': `${appointment.startMinute}px`, // Startpositie binnen het uur
|
||||
'height': `${appointment.durationInMinutes}px`, // Hoogte over meerdere uren
|
||||
};
|
||||
}
|
||||
|
||||
getFormattedTime(hour: number, minute: number): string {
|
||||
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
|
||||
}
|
||||
|
||||
getAppointmentHeight(appointment: Appointment): number {
|
||||
const startInMinutes = (appointment.startHour * 60) + appointment.startMinute;
|
||||
const endInMinutes = (appointment.endHour * 60) + appointment.endMinute;
|
||||
return (endInMinutes - startInMinutes); // 50px per uur
|
||||
}
|
||||
|
||||
selectAppointment(appointment: Appointment) {
|
||||
this.selectedAppointment = appointment;
|
||||
}
|
||||
|
||||
protected readonly DateFormatter = DateFormatter;
|
||||
|
||||
onDayClick(day: TuiDay) {
|
||||
this.value = day;
|
||||
this.selectedDate = new Date(day.year, day.month, day.day);
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
this.appointmentForm.get('date').setValue(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()))
|
||||
this.toggleCalendar()
|
||||
}
|
||||
|
||||
toggleCalendar() {
|
||||
this.showCalendar = !this.showCalendar
|
||||
}
|
||||
|
||||
closeNewItemModal() {
|
||||
this.isModalOpen = false
|
||||
this.resetForms()
|
||||
}
|
||||
|
||||
appointmentIsDeleted(appointment: Appointment) {
|
||||
this.selectedAppointment = undefined;
|
||||
this.alerts
|
||||
.open(`Afspraak <strong>${appointment.title}</strong> is verwijderd.`)
|
||||
.subscribe();
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
}
|
||||
|
||||
appointmentIsEdited($event: Appointment) {
|
||||
this.getAppointmentsByDate(this.selectedDate);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user