git init v2

This commit is contained in:
2025-03-11 23:13:19 +01:00
parent 4d4c8a362a
commit abae328d8f
62 changed files with 3461 additions and 421 deletions

View File

@@ -0,0 +1,19 @@
<h2>
<tui-icon
icon="@tui.user"
[style.color]="'var(--tui-background-accent-1)'"/>
{{ customer.firstName }} {{ customer.lastName }}
</h2>
<h2>
<tui-icon
icon="@tui.mail"
[style.color]="'var(--tui-background-accent-1)'"/>
{{ customer.email }}
</h2>
<ng-template *ngIf="appointment">
<br>
<h2>
Eerst volgende afspraak:
</h2>
<h2>{{ appointment.startDate }}</h2>
</ng-template>

View File

@@ -0,0 +1,37 @@
import {Component, Input, OnInit} from '@angular/core';
import {ReactiveFormsModule} from "@angular/forms";
import {TuiIcon} from "@taiga-ui/core";
import {TuiTextareaModule} from "@taiga-ui/legacy";
import {Customer} from '../../models/customer';
import {AppointmentService} from '../../services/appointment.service';
import {Appointment} from '../../models/appointment';
import {DateFormatter} from '../../utils/date-formatter';
import {NgIf} from '@angular/common';
@Component({
selector: 'app-customer-details',
imports: [
ReactiveFormsModule,
TuiIcon,
TuiTextareaModule,
NgIf
],
templateUrl: './customer-details.component.html',
styleUrl: './customer-details.component.scss'
})
export class CustomerDetailsComponent implements OnInit {
@Input() customer: Customer;
appointment: Appointment;
constructor(private appointmentService: AppointmentService) {
}
ngOnInit(): void {
this.appointmentService.getMostRecentAppointment(this.customer.id).subscribe((response: Appointment) =>
this.appointment = response
)
}
protected readonly DateFormatter = DateFormatter;
}

View File

@@ -0,0 +1,80 @@
<h2>
<tui-icon
icon="@tui.calendar"
[style.color]="'var(--tui-background-accent-1)'"/>
{{ DateFormatter.getDate(appointment.startDate.toString()) }}
</h2>
<h2>
<tui-icon
icon="@tui.clock"
[style.color]="'var(--tui-background-accent-1)'"/>
{{ DateFormatter.getFormattedTime(appointment.startHour, appointment.startMinute) }}
- {{ DateFormatter.getFormattedTime(appointment.endHour, appointment.endMinute) }}
</h2>
<h2 *ngIf="appointment.customer">
<tui-icon
icon="@tui.user"
[style.color]="'var(--tui-background-accent-1)'"/>
{{ appointment.customer.firstName }} {{ appointment.customer.lastName }}
</h2>
<form [formGroup]="testForm" *ngIf="appointment.description">
<tui-textarea formControlName="testValue1" [readOnly]="readonly">Notities</tui-textarea>
</form>
<div
tuiGroup
class="group"
[collapsed]="true">
<button
appearance="outline"
tuiButton
iconStart="@tui.pencil"
size="s"
(click)="showEditModal = true"
type="button">
Bewerken
</button>
<button
appearance="outline"
tuiButton
iconStart="@tui.trash-2"
size="s"
(click)="showDeleteModal = true"
type="button">
Verwijderen
</button>
</div>
<app-modal [title]="appointment.title + ' verwijderen'" *ngIf="showDeleteModal" (close)="showDeleteModal = false">
<h3>Weet je dit zeker?</h3>
<br>
<div
tuiGroup
class="group"
[collapsed]="true">
<button
appearance="outline"
tuiButton
size="s"
(click)="deleteAppointment()"
type="button">
Ja, afspraak verwijderen
</button>
<button
appearance="outline"
tuiButton
size="s"
(click)="showDeleteModal = false"
type="button">
Nee, ga terug
</button>
</div>
</app-modal>
<app-modal [title]="'Afspraak bewerken'" *ngIf="showEditModal" (close)="showEditModal = false">
<app-edit-item [appointment]="appointment" (appointmentUpdateEvent)="updateAppointment($event)"></app-edit-item>
</app-modal>

View File

@@ -0,0 +1,74 @@
import {Component, EventEmitter, inject, Input, OnInit, Output} from '@angular/core';
import {Appointment} from '../../models/appointment';
import {DateFormatter} from '../../utils/date-formatter';
import {TuiAlertService, TuiButton, TuiGroup, TuiIcon} from '@taiga-ui/core';
import {TuiTextareaModule} from '@taiga-ui/legacy';
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
import {NgIf} from '@angular/common';
import {ModalComponent} from '../modal/modal.component';
import {EditItemComponent} from '../edit-item/edit-item.component';
import {AppointmentService} from '../../services/appointment.service';
@Component({
selector: 'app-details',
imports: [
TuiIcon,
TuiTextareaModule,
ReactiveFormsModule,
NgIf,
TuiButton,
TuiGroup,
ModalComponent,
EditItemComponent
],
templateUrl: './details.component.html',
styleUrl: './details.component.scss'
})
export class DetailsComponent implements OnInit {
private readonly alerts = inject(TuiAlertService);
ngOnInit(): void {
if (this.appointment.description) {
this.testForm.get('testValue1').setValue(this.appointment.description)
}
}
constructor(private appointmentService: AppointmentService) {
}
@Input() appointment: Appointment;
@Output() appointmentDeleted = new EventEmitter<Appointment>();
@Output() appointmentEdited = new EventEmitter<Appointment>();
open: boolean = true;
readonly = true;
showDeleteModal = false;
showEditModal = false;
protected testForm = new FormGroup({
testValue1: new FormControl('', Validators.required),
testValue2: new FormControl('This one can be expanded', Validators.required),
testValue3: new FormControl(
'This one can be expanded (expandable on focus)',
Validators.required,
),
});
deleteAppointment() {
this.appointmentService.deleteAppointment(this.appointment).subscribe(() => {
this.showDeleteModal = false;
this.appointmentDeleted.emit(this.appointment);
}
)
}
protected readonly DateFormatter = DateFormatter;
updateAppointment($event: any) {
this.showEditModal = false;
this.appointmentService.getAppointment($event).subscribe((appointment: Appointment) => {
this.appointment = appointment
this.appointmentEdited.emit(this.appointment);
})
}
}

View File

@@ -0,0 +1,149 @@
<form [formGroup]="testForm">
<tui-input formControlName="title">
Titel
<input
tuiTextfieldLegacy
formControlName="title"
type="text"
/>
</tui-input>
<div
*ngIf="testForm.get('title').value == ''"
tuiGroup
class="group"
[collapsed]="true">
<button
*ngFor="let action of quickActions"
appearance="outline"
tuiButton
size="s"
(click)="addAction(action)"
type="button">{{ action }}
</button>
</div>
<br>
<div class="toolbar">
<tui-combo-box
[formControl]="control"
[stringify]="stringify"
tuiTextfieldSize="m">
Klant
<tui-data-list-wrapper
*tuiDataList
[itemContent]="stringify | tuiStringifyContent"
[items]="items | tuiFilterByInput"
/>
</tui-combo-box>
<button
size="m"
tuiButton
(click)="toggleCustomerModal()"
iconStart="@tui.plus"
type="button">
</button>
</div>
<br>
<div
tuiGroup
class="group"
>
<div>
<tui-input-date
formControlName="date"
tuiTextfieldSize="m"
class="tui-space_vertical-4"
[tuiTextfieldLabelOutside]="false"
>
Datum
</tui-input-date>
</div>
<div>
<tui-input-time
formControlName="startTime"
tuiTextfieldSize="m"
class="tui-space_top-2"
[tuiTextfieldLabelOutside]="false">
Van
</tui-input-time>
</div>
<div>
<tui-input-time
formControlName="endTime"
tuiTextfieldSize="m"
class="tui-space_top-2"
[tuiTextfieldLabelOutside]="false"
>
Tot
</tui-input-time>
</div>
</div>
<br>
<tui-textarea formControlName="notes">Notities</tui-textarea>
</form>
<br>
<button
size="m"
tuiButton
type="button" (click)="updateAppointment()"
[tuiAppearanceState]="formIsValid()">
Afspraak bewerken
</button>
<app-modal title="Nieuwe klant" *ngIf="showNewCustomer" (close)="toggleCustomerModal()">
<form [formGroup]="customerForm">
<tui-input
formControlName="firstName"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Voornaam
<input
tuiTextfieldLegacy
type="text"
formControlName="firstName"
/>
</tui-input>
<br>
<tui-input
formControlName="lastName"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Achternaam
<input
tuiTextfieldLegacy
type="text"
formControlName="lastName"
/>
</tui-input>
<br>
<tui-input
formControlName="email"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Email
<input
tuiTextfieldLegacy
autocomplete="email"
type="email"
formControlName="email"
/>
</tui-input>
<br>
<button
appearance="secondary"
size="m"
tuiButton
(click)="saveCustomer()"
type="button">
<tui-icon
icon="@tui.plus"
[style.height.rem]="1"
/>
Klant toevoegen
</button>
</form>
</app-modal>

View File

@@ -0,0 +1,15 @@
.toolbar {
button {
margin-left: 8px;
}
tui-combo-box {
width: 50vw;
}
margin-bottom: 12px;
display: flex;
flex-direction: row;
justify-content: center;
}

View File

@@ -0,0 +1,146 @@
import {Component, EventEmitter, inject, Input, OnInit, Output} from '@angular/core';
import {NgForOf, NgIf} from "@angular/common";
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import {TuiAlertService, TuiButton, TuiGroup, TuiIcon} from "@taiga-ui/core";
import {
TuiComboBoxModule,
TuiInputDateModule,
TuiInputModule,
TuiInputTimeModule,
TuiTextareaModule,
TuiTextfieldControllerModule
} from "@taiga-ui/legacy";
import {Appointment} from '../../models/appointment';
import {TuiDay, TuiTime} from '@taiga-ui/cdk';
import {AppointmentService} from '../../services/appointment.service';
import {TuiDataListWrapperComponent, TuiFilterByInputPipe, TuiStringifyContentPipe} from '@taiga-ui/kit';
import {Customer} from '../../models/customer';
import {CustomerService} from '../../services/customer.service';
import {ModalComponent} from '../modal/modal.component';
@Component({
selector: 'app-edit-item',
imports: [
NgForOf,
NgIf,
ReactiveFormsModule,
TuiButton,
TuiGroup,
TuiInputDateModule,
TuiInputModule,
TuiInputTimeModule,
TuiTextareaModule,
TuiTextfieldControllerModule,
TuiComboBoxModule,
TuiDataListWrapperComponent,
TuiStringifyContentPipe,
TuiFilterByInputPipe,
ModalComponent,
TuiIcon
],
templateUrl: './edit-item.component.html',
styleUrl: './edit-item.component.scss'
})
export class EditItemComponent implements OnInit {
@Input() appointment: Appointment;
testForm: FormGroup;
quickActions = ['Knippen', 'Kleuren', 'Knippen + Kleuren']
waiting: boolean = false;
protected value: TuiDay | null = null;
@Output() appointmentUpdateEvent = new EventEmitter();
showNewCustomer = false;
customerForm: FormGroup;
private readonly alerts = inject(TuiAlertService);
constructor(private appointmentService: AppointmentService, private customerService: CustomerService) {
}
ngOnInit(): void {
console.log(this.appointment);
let date = new Date(this.appointment.startDate);
this.testForm = new FormGroup({
title: new FormControl(this.appointment.title, Validators.required),
notes: new FormControl(this.appointment.description),
startTime: new FormControl(new TuiTime(this.appointment.startHour, this.appointment.startMinute), Validators.required),
endTime: new FormControl(new TuiTime(this.appointment.endHour, this.appointment.endMinute), Validators.required),
date: new FormControl(new TuiDay(date.getFullYear(), date.getMonth(), date.getDate()), Validators.required),
})
this.control = new FormControl(this.appointment.customer)
this.getCustomers()
this.customerForm = new FormGroup({
firstName: new FormControl('', Validators.required),
lastName: new FormControl('', Validators.required),
email: new FormControl('', Validators.required),
})
}
updateAppointment() {
const title = this.testForm.get('title').value
const description = this.testForm.get('notes').value
const startTime = this.testForm.get('startTime').value
const endTime = this.testForm.get('endTime').value
let date = this.testForm.get('date').value
let correctDate = new Date(date.year, date.month, date.day + 1)
const customer = this.control.value;
this.appointment.startDate = correctDate;
this.appointment.title = title;
this.appointment.description = description
this.appointment.startHour = startTime.hours
this.appointment.startMinute = startTime.minutes
this.appointment.endHour = endTime.hours
this.appointment.endMinute = endTime.minutes
this.appointment.customer = customer;
this.appointment.durationInMinutes = (this.appointment.endHour * 60 + this.appointment.endMinute) - (this.appointment.startHour * 60 + this.appointment.startMinute);
this.waiting = true
this.appointmentService.updateAppointment(this.appointment).subscribe(() => {
this.waiting = false
this.appointmentUpdateEvent.emit(this.appointment.id)
this.alerts.open(`Afspraak <strong>${title}</strong> is aangepast.`)
.subscribe();
})
}
formIsValid() {
return this.testForm.valid ? 'active' : 'disabled'
}
addAction(action: string) {
this.testForm.get('title').setValue(`${action} `)
}
protected control = new FormControl<Customer | null>(
null,
);
toggleCustomerModal() {
this.showNewCustomer = !this.showNewCustomer;
}
protected items: Customer[] = [];
protected readonly stringify = (item: Customer): string =>
`${item.firstName} ${item.lastName}`;
saveCustomer() {
const firstName = this.customerForm.get('firstName').value
const lastName = this.customerForm.get('lastName').value
const email = this.customerForm.get('email').value
const customer = new Customer(firstName, lastName, email);
this.customerService.addCustomer(customer).subscribe(() => {
this.showNewCustomer = false;
this.getCustomers()
})
}
getCustomers() {
this.customerService.getCustomers().subscribe(response => {
this.items = response;
})
}
}

View File

@@ -0,0 +1,20 @@
<div class="modal-overlay" (click)="closeModal()"></div>
<div class="modal">
<div class="modal-header">
<h1>{{ title }}</h1>
<button
appearance="secondary-destructive"
iconStart="@tui.x"
size="xs"
tuiIconButton
type="button"
[style.border-radius.%]="100"
(click)="closeModal()"
>
Favorite
</button>
</div>
<div class="modal-content">
<ng-content></ng-content>
</div>
</div>

View File

@@ -0,0 +1,42 @@
/* Overlay achtergrond */
.modal-overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.5); /* Donkere overlay */
backdrop-filter: blur(5px); /* Maakt de achtergrond wazig */
z-index: 998; /* Zorgt dat het onder de modal blijft */
}
/* Modal venster */
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
box-shadow: 0px 4px 6px rgba(0, 0, 0, 0.1);
border-radius: 8px;
min-width: 300px;
width: 50vw;
z-index: 999; /* Zorgt dat het boven de overlay blijft */
}
/* Modal header */
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
}
/* Sluitknop */
button {
background: red;
color: white;
border: none;
padding: 5px 10px;
cursor: pointer;
}

View File

@@ -0,0 +1,23 @@
import {ComponentFixture, TestBed} from '@angular/core/testing';
import {ModalComponent} from './modal.component';
describe('ModalComponent', () => {
let component: ModalComponent;
let fixture: ComponentFixture<ModalComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ModalComponent]
})
.compileComponents();
fixture = TestBed.createComponent(ModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,17 @@
import {Component, EventEmitter, Input, Output} from '@angular/core';
import {TuiButton} from '@taiga-ui/core';
@Component({
selector: 'app-modal',
imports: [TuiButton],
templateUrl: './modal.component.html',
styleUrls: ['./modal.component.scss']
})
export class ModalComponent {
@Input() title: string = 'Modal Title';
@Output() close = new EventEmitter<void>();
closeModal() {
this.close.emit();
}
}

View File

@@ -0,0 +1,150 @@
<form [formGroup]="testForm">
<tui-input formControlName="title">
Titel
<input
tuiTextfieldLegacy
formControlName="title"
type="text"
/>
</tui-input>
<div
*ngIf="testForm.get('title').value == ''"
tuiGroup
class="group"
[collapsed]="true">
<button
*ngFor="let action of quickActions"
appearance="outline"
tuiButton
size="s"
(click)="addAction(action)"
type="button">{{ action }}
</button>
</div>
<br>
<div class="toolbar">
<tui-combo-box
[formControl]="control"
[stringify]="stringify"
tuiTextfieldSize="m">
Klant
<tui-data-list-wrapper
*tuiDataList
[itemContent]="stringify | tuiStringifyContent"
[items]="items | tuiFilterByInput"
/>
</tui-combo-box>
<button
size="m"
tuiButton
(click)="toggleCustomerModal()"
iconStart="@tui.plus"
type="button">
</button>
</div>
<br>
<div
tuiGroup
class="group"
>
<div>
<tui-input-date
formControlName="date"
tuiTextfieldSize="m"
class="tui-space_vertical-4"
[tuiTextfieldLabelOutside]="false"
>
Datum
</tui-input-date>
</div>
<div>
<tui-input-time
formControlName="startTime"
tuiTextfieldSize="m"
class="tui-space_top-2"
[tuiTextfieldLabelOutside]="false">
Van
</tui-input-time>
</div>
<div>
<tui-input-time
formControlName="endTime"
tuiTextfieldSize="m"
class="tui-space_top-2"
[tuiTextfieldLabelOutside]="false"
>
Tot
</tui-input-time>
</div>
</div>
<br>
<tui-textarea formControlName="notes">Notities</tui-textarea>
</form>
<br>
<button
size="m"
tuiButton
type="button" (click)="registerAppointment()"
[tuiAppearanceState]="formIsValid()">
Afspraak maken
</button>
<app-modal title="Nieuwe klant" *ngIf="showNewCustomer" (close)="toggleCustomerModal()">
<form [formGroup]="customerForm">
<tui-input
formControlName="firstName"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Voornaam
<input
tuiTextfieldLegacy
type="text"
formControlName="firstName"
/>
</tui-input>
<br>
<tui-input
formControlName="lastName"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Achternaam
<input
tuiTextfieldLegacy
type="text"
formControlName="lastName"
/>
</tui-input>
<br>
<tui-input
formControlName="email"
tuiTextfieldSize="m"
[tuiTextfieldCleaner]="true"
>
Email
<input
tuiTextfieldLegacy
autocomplete="email"
type="email"
formControlName="email"
/>
</tui-input>
<br>
<button
appearance="secondary"
size="m"
tuiButton
[loading]=waiting
(click)="saveCustomer()"
type="button">
<tui-icon
icon="@tui.plus"
[style.height.rem]="1"
/>
Klant toevoegen
</button>
</form>
</app-modal>

View File

@@ -0,0 +1,15 @@
.toolbar {
button {
margin-left: 8px;
}
tui-combo-box {
width: 50vw;
}
margin-bottom: 12px;
display: flex;
flex-direction: row;
justify-content: center;
}

View File

@@ -0,0 +1,128 @@
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {NgForOf, NgIf} from "@angular/common";
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
import {TuiButton, TuiGroup, TuiIcon} from "@taiga-ui/core";
import {
TuiComboBoxModule,
TuiInputDateModule,
TuiInputModule,
TuiInputTimeModule,
TuiTextareaModule,
TuiTextfieldControllerModule
} from "@taiga-ui/legacy";
import {Appointment} from '../../models/appointment';
import {TuiDay} from '@taiga-ui/cdk';
import {AppointmentService} from '../../services/appointment.service';
import {
TuiButtonLoading,
TuiDataListWrapperComponent,
TuiFilterByInputPipe,
TuiStringifyContentPipe
} from '@taiga-ui/kit';
import {Customer} from '../../models/customer';
import {CustomerService} from '../../services/customer.service';
import {ModalComponent} from '../modal/modal.component';
@Component({
selector: 'app-new-item',
imports: [
NgForOf,
NgIf,
ReactiveFormsModule,
TuiButton,
TuiGroup,
TuiInputDateModule,
TuiInputModule,
TuiInputTimeModule,
TuiTextareaModule,
TuiTextfieldControllerModule,
TuiComboBoxModule,
TuiDataListWrapperComponent,
TuiStringifyContentPipe,
TuiFilterByInputPipe,
ModalComponent,
TuiIcon,
TuiButtonLoading
],
templateUrl: './new-item.component.html',
styleUrl: './new-item.component.scss'
})
export class NewItemComponent implements OnInit {
@Input() testForm: FormGroup;
quickActions = ['Knippen', 'Kleuren', 'Knippen + Kleuren']
waiting: boolean = false;
protected value: TuiDay | null = null;
@Output() appointmentAddedEvent = new EventEmitter();
showNewCustomer = false;
customerForm: FormGroup;
constructor(private appointmentService: AppointmentService, private customerService: CustomerService) {
}
ngOnInit(): void {
this.getCustomers()
this.customerForm = new FormGroup({
firstName: new FormControl('', Validators.required),
lastName: new FormControl('', Validators.required),
email: new FormControl('', Validators.required),
})
}
registerAppointment() {
const title = this.testForm.get('title').value
const description = this.testForm.get('notes').value
const startTime = this.testForm.get('startTime').value
const endTime = this.testForm.get('endTime').value
let date = this.testForm.get('date').value
let correctDate = new Date(date.year, date.month, date.day, startTime.hours, startTime.minutes);
const customer = this.control.value;
const appointment = new Appointment(title, description, startTime.hours, startTime.minutes, endTime.hours, endTime.minutes, correctDate, customer)
this.waiting = true
this.appointmentService.addAppointment(appointment).subscribe(() => {
this.waiting = false
this.appointmentAddedEvent.emit(title)
})
}
formIsValid() {
return this.testForm.valid ? 'active' : 'disabled'
}
addAction(action: string) {
this.testForm.get('title').setValue(`${action} `)
}
protected readonly control = new FormControl<Customer | null>(
null,
);
toggleCustomerModal() {
this.showNewCustomer = !this.showNewCustomer;
}
protected items: Customer[] = [];
protected readonly stringify = (item: Customer): string =>
`${item.firstName} ${item.lastName}`;
saveCustomer() {
const firstName = this.customerForm.get('firstName').value
const lastName = this.customerForm.get('lastName').value
const email = this.customerForm.get('email').value
const customer = new Customer(firstName, lastName, email);
this.customerService.addCustomer(customer).subscribe(() => {
this.showNewCustomer = false;
this.getCustomers()
})
}
getCustomers() {
this.customerService.getCustomers().subscribe(response => {
this.items = response;
})
}
}