Compare commits
17 Commits
cb3243e524
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 9ca282ca3f | |||
| c14328a4bb | |||
| f5e52b58e0 | |||
|
|
8b3527b4c6 | ||
| a71579b801 | |||
|
|
d043ce840b | ||
| ab31ba039b | |||
|
|
a7462b5e29 | ||
| e4c90f8750 | |||
|
|
7dd6131ce1 | ||
| ebd9a6af70 | |||
|
|
c1a4111814 | ||
| e6b359cc9b | |||
| ed0345fd3e | |||
|
|
9520f8b5c9 | ||
| eed9e30fd3 | |||
| c3663e4c6e |
85
.github/workflows/deploy-docker-to-tst.yml
vendored
Normal file
85
.github/workflows/deploy-docker-to-tst.yml
vendored
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
name: Docker Image CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
tags:
|
||||||
|
- "docker-build-*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build-and-push:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Stap 1: Code ophalen
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
# Stap 2: Versienummer ophalen uit package.json en opslaan als artifact
|
||||||
|
- name: Extract Angular version
|
||||||
|
run: |
|
||||||
|
echo "$(cat package.json | jq -r '.version')" > version.txt
|
||||||
|
- name: Save version as artifact
|
||||||
|
uses: actions/upload-artifact@v3
|
||||||
|
with:
|
||||||
|
name: version
|
||||||
|
path: version.txt
|
||||||
|
|
||||||
|
# Stap 3: Inloggen bij Docker Hub
|
||||||
|
- name: Log in to Docker Hub
|
||||||
|
uses: docker/login-action@v2
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKER_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||||
|
|
||||||
|
# Stap 4: Docker-image bouwen en taggen met Angular-versie
|
||||||
|
- name: Build the Docker image
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat version.txt)
|
||||||
|
docker buildx build . --file Dockerfile-tst --tag veenm/paypoint:$VERSION-SNAPSHOT --platform linux/amd64
|
||||||
|
|
||||||
|
# Stap 5: Docker-image pushen naar Docker Hub (huidige versie tag)
|
||||||
|
- name: Push the Docker image (version-snapshot)
|
||||||
|
run: |
|
||||||
|
VERSION=$(cat version.txt)
|
||||||
|
docker push veenm/paypoint:$VERSION-SNAPSHOT
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
needs: build-and-push
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
# Stap 1: Artifact ophalen
|
||||||
|
- name: Download version artifact
|
||||||
|
uses: actions/download-artifact@v3
|
||||||
|
with:
|
||||||
|
name: version
|
||||||
|
|
||||||
|
# Stap 2: Lees versie uit het artifact
|
||||||
|
- name: Read version
|
||||||
|
id: read_version
|
||||||
|
run: echo "VERSION=$(cat version.txt)" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
# Stap 3: Maak verbinding via SSH naar de Alpine server en update de container
|
||||||
|
- name: SSH into Alpine and update Docker container
|
||||||
|
uses: appleboy/ssh-action@v0.1.10
|
||||||
|
with:
|
||||||
|
host: ${{ secrets.ALPINE_HOST }}
|
||||||
|
username: ${{ secrets.ALPINE_USER }}
|
||||||
|
password: ${{ secrets.ALPINE_PASSWORD }}
|
||||||
|
script: |
|
||||||
|
VERSION=${{ env.VERSION }}
|
||||||
|
echo "Gekozen versie: $VERSION-SNAPSHOT"
|
||||||
|
|
||||||
|
# Stop en verwijder de huidige container
|
||||||
|
docker stop paypoint || true
|
||||||
|
docker rm paypoint || true
|
||||||
|
|
||||||
|
# Haal de nieuwste image binnen
|
||||||
|
docker pull veenm/paypoint:$VERSION-SNAPSHOT
|
||||||
|
|
||||||
|
# Start een nieuwe container
|
||||||
|
docker run -d --name paypoint --restart unless-stopped -p 15001:80 veenm/paypoint:$VERSION-SNAPSHOT
|
||||||
|
|
||||||
|
# Opruimen oude images
|
||||||
|
docker image prune -f
|
||||||
6
.github/workflows/deploy-docker.yml
vendored
6
.github/workflows/deploy-docker.yml
vendored
@@ -1,7 +1,11 @@
|
|||||||
name: Docker Image CI
|
name: Docker Image CI
|
||||||
|
|
||||||
on:
|
on:
|
||||||
workflow_call:
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
tags:
|
||||||
|
- "docker-build-*"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-and-push:
|
build-and-push:
|
||||||
|
|||||||
13
.github/workflows/increase-version.yml
vendored
13
.github/workflows/increase-version.yml
vendored
@@ -31,5 +31,14 @@ jobs:
|
|||||||
# Push changes to remote main branch
|
# Push changes to remote main branch
|
||||||
git push origin main
|
git push origin main
|
||||||
|
|
||||||
build-and-run:
|
trigger-pipeline-b:
|
||||||
uses: ./.github/workflows/deploy-docker.yml@main
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Create and push tag
|
||||||
|
run: |
|
||||||
|
git config --global user.name "Gitea Actions"
|
||||||
|
git config --global user.email "actions@gitea.local"
|
||||||
|
git tag docker-build-$(date +%s)
|
||||||
|
git push --tags
|
||||||
22
Dockerfile-tst
Normal file
22
Dockerfile-tst
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
# Gebruik een multi-architecture versie van Node
|
||||||
|
FROM node:23.0.0 as build
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
RUN npm install -g @angular/cli
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN ng build --configuration=production
|
||||||
|
|
||||||
|
# Gebruik een multi-architecture versie van Nginx
|
||||||
|
FROM nginx:latest
|
||||||
|
|
||||||
|
# Kopieer de gecompileerde bestanden van Angular naar de Nginx-webserver
|
||||||
|
COPY --from=build app/dist/pay-point/browser /usr/share/nginx/html
|
||||||
|
|
||||||
|
EXPOSE 80
|
||||||
20
angular.json
20
angular.json
@@ -53,8 +53,8 @@
|
|||||||
"budgets": [
|
"budgets": [
|
||||||
{
|
{
|
||||||
"type": "initial",
|
"type": "initial",
|
||||||
"maximumWarning": "500kB",
|
"maximumWarning": "500MB",
|
||||||
"maximumError": "1MB"
|
"maximumError": "1000MB"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "anyComponentStyle",
|
"type": "anyComponentStyle",
|
||||||
@@ -67,7 +67,21 @@
|
|||||||
"development": {
|
"development": {
|
||||||
"optimization": false,
|
"optimization": false,
|
||||||
"extractLicenses": false,
|
"extractLicenses": false,
|
||||||
"sourceMap": true
|
"sourceMap": true,
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.development.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"fileReplacements": [
|
||||||
|
{
|
||||||
|
"replace": "src/environments/environment.ts",
|
||||||
|
"with": "src/environments/environment.test.ts"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"defaultConfiguration": "production"
|
"defaultConfiguration": "production"
|
||||||
|
|||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "pay-point",
|
"name": "pay-point",
|
||||||
"version": "0.0.15",
|
"version": "0.0.21",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "pay-point",
|
"name": "pay-point",
|
||||||
"version": "0.0.15",
|
"version": "0.0.21",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/animations": "^19.0.0",
|
"@angular/animations": "^19.0.0",
|
||||||
"@angular/cdk": "^19.0.0",
|
"@angular/cdk": "^19.0.0",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "pay-point",
|
"name": "pay-point",
|
||||||
"version": "0.0.15",
|
"version": "0.0.21",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"ng": "ng",
|
"ng": "ng",
|
||||||
"start": "ng serve",
|
"start": "ng serve",
|
||||||
|
|||||||
@@ -58,7 +58,6 @@ export class EditItemComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
console.log(this.appointment);
|
|
||||||
let date = new Date(this.appointment.startDate);
|
let date = new Date(this.appointment.startDate);
|
||||||
this.testForm = new FormGroup({
|
this.testForm = new FormGroup({
|
||||||
title: new FormControl(this.appointment.title, Validators.required),
|
title: new FormControl(this.appointment.title, Validators.required),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<form [formGroup]="testForm">
|
<form [formGroup]="appointmentForm">
|
||||||
<tui-input formControlName="title">
|
<tui-input formControlName="title">
|
||||||
Titel
|
Titel
|
||||||
<input
|
<input
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
/>
|
/>
|
||||||
</tui-input>
|
</tui-input>
|
||||||
<div
|
<div
|
||||||
*ngIf="testForm.get('title').value == ''"
|
*ngIf="appointmentForm.get('title').value == ''"
|
||||||
tuiGroup
|
tuiGroup
|
||||||
class="group"
|
class="group"
|
||||||
[collapsed]="true">
|
[collapsed]="true">
|
||||||
@@ -25,7 +25,7 @@
|
|||||||
<br>
|
<br>
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<tui-combo-box
|
<tui-combo-box
|
||||||
[formControl]="control"
|
[formControl]="customerControl"
|
||||||
[stringify]="stringify"
|
[stringify]="stringify"
|
||||||
tuiTextfieldSize="m">
|
tuiTextfieldSize="m">
|
||||||
Klant
|
Klant
|
||||||
@@ -43,18 +43,17 @@
|
|||||||
type="button">
|
type="button">
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<div
|
<div
|
||||||
tuiGroup
|
tuiGroup
|
||||||
class="group"
|
class="group">
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<tui-input-date
|
<tui-input-date
|
||||||
formControlName="date"
|
formControlName="date"
|
||||||
tuiTextfieldSize="m"
|
tuiTextfieldSize="m"
|
||||||
class="tui-space_vertical-4"
|
class="tui-space_vertical-4"
|
||||||
[tuiTextfieldLabelOutside]="false"
|
[tuiTextfieldLabelOutside]="false">
|
||||||
>
|
|
||||||
Datum
|
Datum
|
||||||
</tui-input-date>
|
</tui-input-date>
|
||||||
</div>
|
</div>
|
||||||
@@ -72,12 +71,38 @@
|
|||||||
formControlName="endTime"
|
formControlName="endTime"
|
||||||
tuiTextfieldSize="m"
|
tuiTextfieldSize="m"
|
||||||
class="tui-space_top-2"
|
class="tui-space_top-2"
|
||||||
[tuiTextfieldLabelOutside]="false"
|
[tuiTextfieldLabelOutside]="false">
|
||||||
>
|
|
||||||
Tot
|
Tot
|
||||||
</tui-input-time>
|
</tui-input-time>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<span *ngIf="appointmentForm.get('endTime')?.errors?.['endTimeInvalid']">
|
||||||
|
<tui-error [error]="timeError"/>
|
||||||
|
</span>
|
||||||
|
<br>
|
||||||
|
<ng-container *ngIf="appointments.length > 0">
|
||||||
|
<h3>Geplande afspraken die dag:</h3>
|
||||||
|
<div class="appointments-container">
|
||||||
|
<div *ngFor="let appointment of appointments" class="appointment-object">
|
||||||
|
<span class="title">{{ appointment.title }}</span>
|
||||||
|
<span class="name">
|
||||||
|
<tui-icon
|
||||||
|
icon="@tui.user"
|
||||||
|
[style.font-size.rem]="1"
|
||||||
|
[style.color]="'var(--tui-background-accent-1)'"/>
|
||||||
|
{{ appointment.customer.firstName }} {{ appointment.customer.lastName }}</span>
|
||||||
|
<span class="time">
|
||||||
|
<tui-icon
|
||||||
|
icon="@tui.clock"
|
||||||
|
[style.font-size.rem]="1"
|
||||||
|
[style.color]="'var(--tui-background-accent-1)'"/>
|
||||||
|
{{ getFormattedTime(appointment.startHour, appointment.startMinute) }} -
|
||||||
|
{{ getFormattedTime(appointment.endHour, appointment.endMinute) }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<tui-textarea formControlName="notes">Notities</tui-textarea>
|
<tui-textarea formControlName="notes">Notities</tui-textarea>
|
||||||
</form>
|
</form>
|
||||||
@@ -95,42 +120,35 @@
|
|||||||
<tui-input
|
<tui-input
|
||||||
formControlName="firstName"
|
formControlName="firstName"
|
||||||
tuiTextfieldSize="m"
|
tuiTextfieldSize="m"
|
||||||
[tuiTextfieldCleaner]="true"
|
[tuiTextfieldCleaner]="true">
|
||||||
>
|
|
||||||
Voornaam
|
Voornaam
|
||||||
<input
|
<input
|
||||||
tuiTextfieldLegacy
|
tuiTextfieldLegacy
|
||||||
type="text"
|
type="text"
|
||||||
formControlName="firstName"
|
formControlName="firstName"/>
|
||||||
/>
|
|
||||||
</tui-input>
|
</tui-input>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<tui-input
|
<tui-input
|
||||||
formControlName="lastName"
|
formControlName="lastName"
|
||||||
tuiTextfieldSize="m"
|
tuiTextfieldSize="m"
|
||||||
[tuiTextfieldCleaner]="true"
|
[tuiTextfieldCleaner]="true">
|
||||||
>
|
|
||||||
Achternaam
|
Achternaam
|
||||||
<input
|
<input
|
||||||
tuiTextfieldLegacy
|
tuiTextfieldLegacy
|
||||||
type="text"
|
type="text"
|
||||||
formControlName="lastName"
|
formControlName="lastName"/>
|
||||||
/>
|
|
||||||
</tui-input>
|
</tui-input>
|
||||||
<br>
|
<br>
|
||||||
<tui-input
|
<tui-input
|
||||||
formControlName="email"
|
formControlName="email"
|
||||||
tuiTextfieldSize="m"
|
tuiTextfieldSize="m"
|
||||||
[tuiTextfieldCleaner]="true"
|
[tuiTextfieldCleaner]="true">
|
||||||
>
|
|
||||||
Email
|
Email
|
||||||
<input
|
<input
|
||||||
tuiTextfieldLegacy
|
tuiTextfieldLegacy
|
||||||
autocomplete="email"
|
autocomplete="email"
|
||||||
type="email"
|
type="email"
|
||||||
formControlName="email"
|
formControlName="email"/>
|
||||||
/>
|
|
||||||
</tui-input>
|
</tui-input>
|
||||||
<br>
|
<br>
|
||||||
<button
|
<button
|
||||||
@@ -142,8 +160,7 @@
|
|||||||
type="button">
|
type="button">
|
||||||
<tui-icon
|
<tui-icon
|
||||||
icon="@tui.plus"
|
icon="@tui.plus"
|
||||||
[style.height.rem]="1"
|
[style.height.rem]="1"/>
|
||||||
/>
|
|
||||||
Klant toevoegen
|
Klant toevoegen
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -13,3 +13,48 @@
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[tuiAppearance][data-appearance='custom'] {
|
||||||
|
background: #526ed3;
|
||||||
|
color: white;
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.appointments-container {
|
||||||
|
display: flex;
|
||||||
|
gap: 5px; /* Ruimte tussen de objecten */
|
||||||
|
overflow-x: auto; /* Alleen horizontaal scrollen als nodig */
|
||||||
|
white-space: nowrap; /* Voorkomt dat items naar een nieuwe regel springen */
|
||||||
|
padding-bottom: 5px; /* Ruimte voor scrollbar */
|
||||||
|
}
|
||||||
|
|
||||||
|
.appointment-object {
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.1);
|
||||||
|
min-width: 120px;
|
||||||
|
text-align: left;
|
||||||
|
font-size: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 2px;
|
||||||
|
flex-shrink: 0; /* Voorkomt dat items kleiner worden bij weinig ruimte */
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Optioneel: Specifieke styling voor de tekstregels */
|
||||||
|
.name {
|
||||||
|
color: #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #777;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
|
||||||
import {NgForOf, NgIf} from "@angular/common";
|
import {NgForOf, NgIf} from "@angular/common";
|
||||||
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
import {FormControl, FormGroup, ReactiveFormsModule, Validators} from "@angular/forms";
|
||||||
import {TuiButton, TuiGroup, TuiIcon} from "@taiga-ui/core";
|
import {TuiButton, TuiError, TuiGroup, TuiIcon} from "@taiga-ui/core";
|
||||||
import {
|
import {
|
||||||
TuiComboBoxModule,
|
TuiComboBoxModule,
|
||||||
TuiInputDateModule,
|
TuiInputDateModule,
|
||||||
@@ -11,7 +11,7 @@ import {
|
|||||||
TuiTextfieldControllerModule
|
TuiTextfieldControllerModule
|
||||||
} from "@taiga-ui/legacy";
|
} from "@taiga-ui/legacy";
|
||||||
import {Appointment} from '../../models/appointment';
|
import {Appointment} from '../../models/appointment';
|
||||||
import {TuiDay} from '@taiga-ui/cdk';
|
import {TuiDay, TuiTime, TuiValidationError} from '@taiga-ui/cdk';
|
||||||
import {AppointmentService} from '../../services/appointment.service';
|
import {AppointmentService} from '../../services/appointment.service';
|
||||||
import {
|
import {
|
||||||
TuiButtonLoading,
|
TuiButtonLoading,
|
||||||
@@ -22,6 +22,7 @@ import {
|
|||||||
import {Customer} from '../../models/customer';
|
import {Customer} from '../../models/customer';
|
||||||
import {CustomerService} from '../../services/customer.service';
|
import {CustomerService} from '../../services/customer.service';
|
||||||
import {ModalComponent} from '../modal/modal.component';
|
import {ModalComponent} from '../modal/modal.component';
|
||||||
|
import {timeAfterStartValidator} from '../../models/validators/time-after-start-validator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-new-item',
|
selector: 'app-new-item',
|
||||||
@@ -42,42 +43,65 @@ import {ModalComponent} from '../modal/modal.component';
|
|||||||
TuiFilterByInputPipe,
|
TuiFilterByInputPipe,
|
||||||
ModalComponent,
|
ModalComponent,
|
||||||
TuiIcon,
|
TuiIcon,
|
||||||
TuiButtonLoading
|
TuiButtonLoading,
|
||||||
|
TuiError
|
||||||
],
|
],
|
||||||
templateUrl: './new-item.component.html',
|
templateUrl: './new-item.component.html',
|
||||||
styleUrl: './new-item.component.scss'
|
styleUrl: './new-item.component.scss'
|
||||||
})
|
})
|
||||||
export class NewItemComponent implements OnInit {
|
export class NewItemComponent implements OnInit {
|
||||||
|
|
||||||
@Input() testForm: FormGroup;
|
@Input() appointmentForm: FormGroup;
|
||||||
|
@Input() appointments: Appointment[];
|
||||||
quickActions = ['Knippen', 'Kleuren', 'Knippen + Kleuren']
|
quickActions = ['Knippen', 'Kleuren', 'Knippen + Kleuren']
|
||||||
waiting: boolean = false;
|
waiting: boolean = false;
|
||||||
protected value: TuiDay | null = null;
|
protected value: TuiDay | null = null;
|
||||||
@Output() appointmentAddedEvent = new EventEmitter();
|
@Output() appointmentAddedEvent = new EventEmitter();
|
||||||
showNewCustomer = false;
|
showNewCustomer = false;
|
||||||
customerForm: FormGroup;
|
customerForm: FormGroup;
|
||||||
|
today: Date;
|
||||||
|
timeError = new TuiValidationError('Begintijd moet voor de eindtijd liggen.');
|
||||||
|
|
||||||
|
|
||||||
constructor(private appointmentService: AppointmentService, private customerService: CustomerService) {
|
constructor(private appointmentService: AppointmentService, private customerService: CustomerService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
this.getCustomers()
|
this.getCustomers()
|
||||||
|
this.today = new Date();
|
||||||
this.customerForm = new FormGroup({
|
this.customerForm = new FormGroup({
|
||||||
firstName: new FormControl('', Validators.required),
|
firstName: new FormControl('', Validators.required),
|
||||||
lastName: new FormControl('', Validators.required),
|
lastName: new FormControl('', Validators.required),
|
||||||
email: new FormControl('', Validators.required),
|
email: new FormControl('', Validators.required),
|
||||||
})
|
})
|
||||||
|
this.appointmentForm.get('startTime').setValue(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required)
|
||||||
|
this.appointmentForm.get('endTime').setValue(new TuiTime(this.getEndTime().getHours(), this.getEndTime().getMinutes()), [Validators.required, timeAfterStartValidator('startTime')])
|
||||||
|
this.appointments.sort((a, b) => {
|
||||||
|
return a.startHour - b.startHour || a.startMinute - b.startMinute;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
registerAppointment() {
|
registerAppointment() {
|
||||||
const title = this.testForm.get('title').value
|
const title = this.appointmentForm.get('title').value
|
||||||
const description = this.testForm.get('notes').value
|
const description = this.appointmentForm.get('notes').value
|
||||||
const startTime = this.testForm.get('startTime').value
|
const startTime = this.appointmentForm.get('startTime').value
|
||||||
const endTime = this.testForm.get('endTime').value
|
const endTime = this.appointmentForm.get('endTime').value
|
||||||
let date = this.testForm.get('date').value
|
let date = this.appointmentForm.get('date').value
|
||||||
let correctDate = new Date(date.year, date.month, date.day, startTime.hours, startTime.minutes);
|
let correctDate = new Date(date.year, date.month, date.day, startTime.hours, startTime.minutes);
|
||||||
|
|
||||||
const customer = this.control.value;
|
const customer = this.customerControl.value;
|
||||||
|
|
||||||
const appointment = new Appointment(title, description, startTime.hours, startTime.minutes, endTime.hours, endTime.minutes, correctDate, customer)
|
const appointment = new Appointment(title, description, startTime.hours, startTime.minutes, endTime.hours, endTime.minutes, correctDate, customer)
|
||||||
this.waiting = true
|
this.waiting = true
|
||||||
@@ -88,15 +112,15 @@ export class NewItemComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
formIsValid() {
|
formIsValid() {
|
||||||
return this.testForm.valid ? 'active' : 'disabled'
|
return this.appointmentForm.valid && this.customerControl.valid ? 'active' : 'disabled'
|
||||||
}
|
}
|
||||||
|
|
||||||
addAction(action: string) {
|
addAction(action: string) {
|
||||||
this.testForm.get('title').setValue(`${action} `)
|
this.appointmentForm.get('title').setValue(`${action} `)
|
||||||
}
|
}
|
||||||
|
|
||||||
protected readonly control = new FormControl<Customer | null>(
|
protected readonly customerControl = new FormControl<Customer | null>(
|
||||||
null,
|
null, Validators.required
|
||||||
);
|
);
|
||||||
|
|
||||||
toggleCustomerModal() {
|
toggleCustomerModal() {
|
||||||
@@ -125,4 +149,8 @@ export class NewItemComponent implements OnInit {
|
|||||||
this.items = response;
|
this.items = response;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getFormattedTime(hour: number, minute: number): string {
|
||||||
|
return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,8 +22,6 @@ export class Appointment {
|
|||||||
this.startDate = date;
|
this.startDate = date;
|
||||||
this.customer = customer;
|
this.customer = customer;
|
||||||
|
|
||||||
console.log(this)
|
|
||||||
|
|
||||||
// Bereken de totale duur in minuten
|
// Bereken de totale duur in minuten
|
||||||
this.durationInMinutes = (endHour * 60 + endMinute) - (startHour * 60 + startMinute);
|
this.durationInMinutes = (endHour * 60 + endMinute) - (startHour * 60 + startMinute);
|
||||||
}
|
}
|
||||||
|
|||||||
18
src/app/models/validators/time-after-start-validator.ts
Normal file
18
src/app/models/validators/time-after-start-validator.ts
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
import {AbstractControl, ValidationErrors, ValidatorFn} from '@angular/forms';
|
||||||
|
|
||||||
|
export function timeAfterStartValidator(startTimeField: string): ValidatorFn {
|
||||||
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
|
const startTime = control.parent?.get(startTimeField)?.value;
|
||||||
|
const endTime = control.value;
|
||||||
|
|
||||||
|
if (!startTime || !endTime) {
|
||||||
|
return null; // Niet valideren als een van beide leeg is
|
||||||
|
}
|
||||||
|
|
||||||
|
// Omzetten naar Date-objecten voor vergelijking
|
||||||
|
const start = new Date(`1970-01-01T${startTime}:00`);
|
||||||
|
const end = new Date(`1970-01-01T${endTime}:00`);
|
||||||
|
|
||||||
|
return end > start ? null : {endTimeInvalid: true};
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -74,7 +74,8 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<app-modal title="Nieuwe afspraak" (close)="closeNewItemModal()" *ngIf="isModalOpen">
|
<app-modal title="Nieuwe afspraak" (close)="closeNewItemModal()" *ngIf="isModalOpen">
|
||||||
<app-new-item [testForm]="appointmentForm" (appointmentAddedEvent)="registerAppointment($event)"></app-new-item>
|
<app-new-item [appointments]="appointments" [appointmentForm]="appointmentForm"
|
||||||
|
(appointmentAddedEvent)="registerAppointment($event)"></app-new-item>
|
||||||
</app-modal>
|
</app-modal>
|
||||||
|
|
||||||
<app-modal title="{{selectedAppointment.title}}" (close)="selectedAppointment = undefined"
|
<app-modal title="{{selectedAppointment.title}}" (close)="selectedAppointment = undefined"
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import {DetailsComponent} from '../../components/details/details.component';
|
|||||||
import {DateFormatter} from '../../utils/date-formatter';
|
import {DateFormatter} from '../../utils/date-formatter';
|
||||||
import {WeekDay} from '../../models/week-day';
|
import {WeekDay} from '../../models/week-day';
|
||||||
import {NewItemComponent} from '../../components/new-item/new-item.component';
|
import {NewItemComponent} from '../../components/new-item/new-item.component';
|
||||||
|
import {timeAfterStartValidator} from '../../models/validators/time-after-start-validator';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-agenda',
|
selector: 'app-agenda',
|
||||||
@@ -52,7 +53,7 @@ export class AgendaComponent implements OnInit {
|
|||||||
title: new FormControl('', Validators.required),
|
title: new FormControl('', Validators.required),
|
||||||
notes: new FormControl(''),
|
notes: new FormControl(''),
|
||||||
startTime: new FormControl(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required),
|
startTime: new FormControl(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required),
|
||||||
endTime: new FormControl(new TuiTime(this.getHours(), this.getMinutes()), Validators.required),
|
endTime: new FormControl(new TuiTime(this.getHours(), this.getMinutes()), [Validators.required, timeAfterStartValidator('startTime')]),
|
||||||
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -90,7 +91,7 @@ export class AgendaComponent implements OnInit {
|
|||||||
title: new FormControl('', Validators.required),
|
title: new FormControl('', Validators.required),
|
||||||
notes: new FormControl(''),
|
notes: new FormControl(''),
|
||||||
startTime: new FormControl(new TuiTime(this.today.getHours(), this.today.getMinutes()), Validators.required),
|
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),
|
endTime: new FormControl(new TuiTime(this.getEndTime().getHours(), this.getEndTime().getMinutes()), [Validators.required, timeAfterStartValidator('startTime')]),
|
||||||
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
date: new FormControl(new TuiDay(this.selectedDate.getFullYear(), this.selectedDate.getMonth(), this.selectedDate.getDate()), Validators.required),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -109,7 +110,6 @@ export class AgendaComponent implements OnInit {
|
|||||||
|
|
||||||
getHours() {
|
getHours() {
|
||||||
let hours = this.today.getHours()
|
let hours = this.today.getHours()
|
||||||
console.log(hours)
|
|
||||||
if (hours > 23) {
|
if (hours > 23) {
|
||||||
return 23
|
return 23
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ export class AuthService {
|
|||||||
baseApi = "https://api.melvanveen.nl/api/auth/login";
|
baseApi = "https://api.melvanveen.nl/api/auth/login";
|
||||||
jwtHelper = new JwtHelperService();
|
jwtHelper = new JwtHelperService();
|
||||||
|
|
||||||
constructor(private http: HttpClient) {}
|
constructor(private http: HttpClient) {
|
||||||
|
}
|
||||||
|
|
||||||
login(username: string, password: string): Observable<any> {
|
login(username: string, password: string): Observable<any> {
|
||||||
return this.http.post(this.baseApi, {username, password});
|
return this.http.post(this.baseApi, {username, password});
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ export class DateFormatter {
|
|||||||
|
|
||||||
static getHours(date: Date) {
|
static getHours(date: Date) {
|
||||||
let hours = date.getHours()
|
let hours = date.getHours()
|
||||||
console.log(hours)
|
|
||||||
if (hours > 23) {
|
if (hours > 23) {
|
||||||
return 23
|
return 23
|
||||||
}
|
}
|
||||||
|
|||||||
4
src/environments/environment.development.ts
Normal file
4
src/environments/environment.development.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
baseApi: 'http://localhost:8080/api',
|
||||||
|
production: false
|
||||||
|
};
|
||||||
4
src/environments/environment.test.ts
Normal file
4
src/environments/environment.test.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
baseApi: 'http://localhost:8080/api',
|
||||||
|
production: false
|
||||||
|
};
|
||||||
4
src/environments/environment.ts
Normal file
4
src/environments/environment.ts
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
export const environment = {
|
||||||
|
baseApi: 'https://api.melvanveen.nl/api',
|
||||||
|
production: true
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user