@ichgamer999/wmctest 1.0.2 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/package.json +1 -1
  2. package/src/app-ostbahn/app.component.css +0 -0
  3. package/src/app-ostbahn/app.component.html +1 -0
  4. package/src/app-ostbahn/app.component.ts +14 -0
  5. package/src/app-ostbahn/app.config.ts +12 -0
  6. package/src/app-ostbahn/app.routes.ts +12 -0
  7. package/src/app-ostbahn/auth.guard.ts +29 -0
  8. package/src/app-ostbahn/auth.interceptor.ts +14 -0
  9. package/src/app-ostbahn/auth.service.ts +41 -0
  10. package/src/app-ostbahn/domains/child.ts +11 -0
  11. package/src/app-ostbahn/domains/connection.ts +22 -0
  12. package/src/app-ostbahn/domains/customer.ts +17 -0
  13. package/src/app-ostbahn/domains/reservationRequest.ts +14 -0
  14. package/src/app-ostbahn/domains/reservationResponse.ts +16 -0
  15. package/src/app-ostbahn/domains/station.ts +10 -0
  16. package/src/app-ostbahn/http.service.ts +34 -0
  17. package/src/app-ostbahn/login/login.component.css +0 -0
  18. package/src/app-ostbahn/login/login.component.html +14 -0
  19. package/src/app-ostbahn/login/login.component.ts +32 -0
  20. package/src/app-ostbahn/overview/overview.component.css +0 -0
  21. package/src/app-ostbahn/overview/overview.component.html +14 -0
  22. package/src/app-ostbahn/overview/overview.component.ts +41 -0
  23. package/src/app-ostbahn/reservation/reservation.component.css +0 -0
  24. package/src/app-ostbahn/reservation/reservation.component.html +33 -0
  25. package/src/app-ostbahn/reservation/reservation.component.ts +94 -0
  26. package/src/app-sokrates/app.component.css +0 -0
  27. package/src/app-sokrates/app.component.html +1 -0
  28. package/src/app-sokrates/app.component.ts +14 -0
  29. package/src/app-sokrates/app.config.ts +12 -0
  30. package/src/app-sokrates/app.routes.ts +12 -0
  31. package/src/app-sokrates/auth.guard.ts +29 -0
  32. package/src/app-sokrates/auth.interceptor.ts +14 -0
  33. package/src/app-sokrates/auth.service.ts +41 -0
  34. package/src/app-sokrates/domains/child.ts +11 -0
  35. package/src/app-sokrates/domains/connection.ts +22 -0
  36. package/src/app-sokrates/domains/customer.ts +17 -0
  37. package/src/app-sokrates/domains/reservationRequest.ts +14 -0
  38. package/src/app-sokrates/domains/reservationResponse.ts +16 -0
  39. package/src/app-sokrates/domains/station.ts +10 -0
  40. package/src/app-sokrates/http.service.ts +34 -0
  41. package/src/app-sokrates/login/login.component.css +0 -0
  42. package/src/app-sokrates/login/login.component.html +14 -0
  43. package/src/app-sokrates/login/login.component.ts +32 -0
  44. package/src/app-sokrates/overview/overview.component.css +0 -0
  45. package/src/app-sokrates/overview/overview.component.html +14 -0
  46. package/src/app-sokrates/overview/overview.component.ts +41 -0
  47. package/src/app-sokrates/reservation/reservation.component.css +0 -0
  48. package/src/app-sokrates/reservation/reservation.component.html +33 -0
  49. package/src/app-sokrates/reservation/reservation.component.ts +94 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ichgamer999/wmctest",
3
- "version": "1.0.2",
3
+ "version": "1.1.0",
4
4
  "description": "Minimalist Angular authentication template with signals, JWT token handling, and HTTP interceptors",
5
5
  "keywords": [
6
6
  "angular",
File without changes
@@ -0,0 +1 @@
1
+ <router-outlet></router-outlet>
@@ -0,0 +1,14 @@
1
+ import {Component, signal} from '@angular/core';
2
+ import {Router, RouterOutlet} from '@angular/router';
3
+ import {AuthService} from './auth.service';
4
+
5
+ @Component({
6
+ selector: 'app-root',
7
+ templateUrl: './app.component.html',
8
+ imports: [
9
+ RouterOutlet
10
+ ],
11
+ styleUrl: './app.component.css'
12
+ })
13
+ export class AppComponent {
14
+ }
@@ -0,0 +1,12 @@
1
+ import { ApplicationConfig } from '@angular/core';
2
+ import {provideRouter, withComponentInputBinding} from '@angular/router';
3
+
4
+ import { routes } from './app.routes';
5
+ import {provideHttpClient, withInterceptors} from '@angular/common/http';
6
+ import {authInterceptor} from './auth.interceptor';
7
+
8
+ export const appConfig: ApplicationConfig = {
9
+ providers: [
10
+ provideRouter(routes,withComponentInputBinding()),
11
+ provideHttpClient(withInterceptors([authInterceptor]))]
12
+ };
@@ -0,0 +1,12 @@
1
+ import { Routes } from '@angular/router';
2
+ import {LoginComponent} from './login/login.component';
3
+ import {OverviewComponent} from './overview/overview.component';
4
+ import {ReservationComponent} from './reservation/reservation.component';
5
+ import {AuthGuard} from './auth.guard';
6
+
7
+ export const routes: Routes = [
8
+ {path: 'login', component: LoginComponent},
9
+ {path: 'book/:id', component: ReservationComponent, canActivate: [AuthGuard]},
10
+ {path: '', component: OverviewComponent},
11
+ {path: '**', redirectTo:'', pathMatch: "full"}
12
+ ];
@@ -0,0 +1,29 @@
1
+ import {
2
+ ActivatedRouteSnapshot,
3
+ CanActivate,
4
+ CanActivateFn,
5
+ GuardResult,
6
+ MaybeAsync, Router,
7
+ RouterStateSnapshot
8
+ } from '@angular/router';
9
+ import {AuthService} from './auth.service';
10
+ import {Injectable} from '@angular/core';
11
+
12
+ @Injectable({
13
+ providedIn: 'root'
14
+ })
15
+
16
+ export class AuthGuard implements CanActivate{
17
+ constructor(private router: Router, private auth:AuthService) {
18
+ }
19
+ canActivate() {
20
+ if (this.auth.isLoggedIn()){
21
+ return true;
22
+ }
23
+ else {
24
+ this.router.navigate(['/login'])
25
+ return false;
26
+ }
27
+ }
28
+
29
+ }
@@ -0,0 +1,14 @@
1
+ import { HttpInterceptorFn } from '@angular/common/http';
2
+ import {inject} from '@angular/core';
3
+ import {AuthService} from './auth.service';
4
+
5
+ export const authInterceptor: HttpInterceptorFn = (req, next) => {
6
+ const authService = inject(AuthService);
7
+ if (!authService.isLoggedIn())
8
+ return next(req);
9
+ const cloned = req.clone({
10
+ headers: req.headers.set('Authorization',
11
+ `Bearer ${authService.getToken()}`)
12
+ });
13
+ return next(cloned);
14
+ };
@@ -0,0 +1,41 @@
1
+ import {Injectable, signal} from '@angular/core';
2
+ import {HttpService} from './http.service';
3
+ import {HttpClient} from '@angular/common/http';
4
+ import {tap} from 'rxjs';
5
+ import {Router} from '@angular/router';
6
+
7
+ @Injectable({
8
+ providedIn: 'root',
9
+ })
10
+ export class AuthService {
11
+ _user = signal('')
12
+ private baseUrl = 'http://localhost:3000'
13
+ private static tokenKey: string = "token";
14
+ constructor(private httpClient : HttpClient, private router : Router) {
15
+ }
16
+ login(username: string, password: string) {
17
+ return this.httpClient
18
+ .post<{ token: string }>(`${this.baseUrl}/login`,
19
+ { username: username, password: password })
20
+ .pipe(
21
+ tap(response => {
22
+ localStorage.setItem(AuthService.tokenKey, response.token);
23
+ this._user.set(username);
24
+ })
25
+ );
26
+ }
27
+
28
+ logout(): void {
29
+ localStorage.removeItem(AuthService.tokenKey);
30
+ this._user.set('');
31
+ this.router.navigate(['/login']);
32
+ }
33
+
34
+ isLoggedIn(){
35
+ return !!localStorage.getItem(AuthService.tokenKey)
36
+ }
37
+
38
+ getToken() {
39
+ return localStorage.getItem(AuthService.tokenKey)
40
+ }
41
+ }
@@ -0,0 +1,11 @@
1
+
2
+ export class Child{
3
+ name: string;
4
+ age: number;
5
+
6
+
7
+ constructor(name: string, age: number) {
8
+ this.name = name;
9
+ this.age = age;
10
+ }
11
+ }
@@ -0,0 +1,22 @@
1
+ export class Connection{
2
+ id: number;
3
+ fromStationId: number;
4
+ toStationId: number;
5
+ fromStationName: string;
6
+ toStationName:string;
7
+ date: string;
8
+ departureTime:string;
9
+ arrivalTime:string;
10
+
11
+
12
+ constructor(id: number, fromStationId: number, toStationId: number, fromStationName: string, toStationName: string, date: string, departureTime: string, arrivalTime: string) {
13
+ this.id = id;
14
+ this.fromStationId = fromStationId;
15
+ this.toStationId = toStationId;
16
+ this.fromStationName = fromStationName;
17
+ this.toStationName = toStationName;
18
+ this.date = date;
19
+ this.departureTime = departureTime;
20
+ this.arrivalTime = arrivalTime;
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+
2
+ export class Customer{
3
+ id:number
4
+ username:string
5
+ name:string
6
+ password:string
7
+ role:string
8
+
9
+
10
+ constructor(id: number, username: string, name: string, password: string, role: string) {
11
+ this.id = id;
12
+ this.username = username;
13
+ this.name = name;
14
+ this.password = password;
15
+ this.role = role;
16
+ }
17
+ }
@@ -0,0 +1,14 @@
1
+ import {Child} from './child';
2
+
3
+ export class ReservationRequest{
4
+ connectionId:number;
5
+ firstClass:boolean;
6
+ children:Child[]
7
+
8
+
9
+ constructor(connectionId: number, firstClass: boolean, children: Child[]) {
10
+ this.connectionId = connectionId;
11
+ this.firstClass = firstClass;
12
+ this.children = children;
13
+ }
14
+ }
@@ -0,0 +1,16 @@
1
+ import {Child} from './child';
2
+
3
+ export class ReservationResponse{
4
+ id:number;
5
+ connectionId:number;
6
+ firstClass:boolean;
7
+ children:Child[];
8
+
9
+
10
+ constructor(id: number, connectionId: number, firstClass: boolean, children: Child[]) {
11
+ this.id = id;
12
+ this.connectionId = connectionId;
13
+ this.firstClass = firstClass;
14
+ this.children = children;
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ export class Station{
2
+ id:number;
3
+ name:string
4
+
5
+
6
+ constructor(id: number, name: string) {
7
+ this.id = id;
8
+ this.name = name;
9
+ }
10
+ }
@@ -0,0 +1,34 @@
1
+ import { Injectable } from '@angular/core';
2
+ import {HttpClient} from '@angular/common/http';
3
+ import {Connection} from './domains/connection';
4
+ import {ReservationRequest} from './domains/reservationRequest';
5
+ import {ReservationResponse} from './domains/reservationResponse';
6
+
7
+ @Injectable({
8
+ providedIn: 'root',
9
+ })
10
+ export class HttpService {
11
+ baseurl = 'http://localhost:3000/'
12
+ constructor(private http:HttpClient) {
13
+ }
14
+
15
+ getAllConnections(){
16
+ return this.http.get<Connection[]>(this.baseurl + "connections")
17
+ }
18
+
19
+ getConnection(connectionId: number) {
20
+ return this.http.get<Connection>(this.baseurl + "connections/" + connectionId)
21
+ }
22
+
23
+ postReservation(reservation:ReservationRequest){
24
+ return this.http.post(this.baseurl + "reservations", reservation)
25
+ }
26
+
27
+ getAllReservations(){
28
+ return this.http.get<ReservationResponse[]>(this.baseurl+"reservations")
29
+ }
30
+
31
+ getReservationById(id:number){
32
+ return this.http.get<ReservationResponse>(this.baseurl+ "reservations/"+id)
33
+ }
34
+ }
File without changes
@@ -0,0 +1,14 @@
1
+ <form [formGroup] = "loginForm" (ngSubmit)="login()">
2
+ @if (errorMessage() !== '') {
3
+ <p>{{errorMessage()}}</p>
4
+ }
5
+
6
+ <label for="username">Nutzername: </label>
7
+ <input type="text" id="username" formControlName="username">
8
+
9
+ <label for="password">Password: </label>
10
+ <input type="password" id="password" formControlName="password">
11
+
12
+ <button type="submit">Login</button>
13
+
14
+ </form>
@@ -0,0 +1,32 @@
1
+ import {Component, signal} from '@angular/core';
2
+ import {AuthService} from '../auth.service';
3
+ import {Router} from '@angular/router';
4
+ import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
5
+
6
+ @Component({
7
+ selector: 'app-login',
8
+ imports: [
9
+ ReactiveFormsModule
10
+ ],
11
+ templateUrl: './login.component.html',
12
+ styleUrl: './login.component.css',
13
+ })
14
+ export class LoginComponent {
15
+ errorMessage = signal('')
16
+ loginForm: FormGroup;
17
+ constructor(private auth:AuthService, private router: Router, private fb: FormBuilder) {
18
+ this.loginForm = new FormGroup({
19
+ username: new FormControl('demo@demo.com', Validators.required),
20
+ password: new FormControl('demo', Validators.required)
21
+ })
22
+ }
23
+
24
+
25
+ login() {
26
+ this.auth.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({
27
+ next: () => {this.router.navigate(['/overview'])},
28
+ error: () => {this.errorMessage.set("Fehlerhafte Logindaten")}
29
+ }
30
+ )
31
+ }
32
+ }
@@ -0,0 +1,14 @@
1
+ <h1>Connection overview</h1>
2
+ @if (logined()){
3
+ <button (click)="logout()">Logout</button>
4
+ } @else {
5
+ <button (click)="login()">Login</button>
6
+ }
7
+ <div>
8
+ @for (connection of connections(); track connection) {
9
+ <h5>Connection {{$index+1}}</h5>
10
+ <p>{{connection.fromStationName}} ===> {{connection.toStationName}}</p>
11
+ <a [routerLink]="['/book/', connection.id]">Buchen</a>
12
+ }
13
+ </div>
14
+
@@ -0,0 +1,41 @@
1
+ import {Component, OnInit, signal} from '@angular/core';
2
+ import {HttpService} from '../http.service';
3
+ import {Connection} from '../domains/connection';
4
+ import {Router, RouterLink} from '@angular/router';
5
+ import {AuthService} from '../auth.service';
6
+
7
+ @Component({
8
+ selector: 'app-overview',
9
+ imports: [
10
+ RouterLink
11
+ ],
12
+ templateUrl: './overview.component.html',
13
+ styleUrl: './overview.component.css',
14
+ })
15
+ export class OverviewComponent implements OnInit{
16
+ logined = signal(false)
17
+ connections = signal<Connection[]>([])
18
+ constructor(private http:HttpService, private auth:AuthService, private router: Router) {
19
+ this.logined.set(auth.isLoggedIn())
20
+ }
21
+
22
+ ngOnInit() {
23
+ this.http.getAllConnections().subscribe(cs => {
24
+ this.connections.set(cs)
25
+ })
26
+ }
27
+
28
+ logout(){
29
+ this.auth.logout();
30
+ this.router.navigate(['login'])
31
+ this.logined.set(false)
32
+ }
33
+
34
+ login() {
35
+ this.router.navigate(['login'])
36
+ this.logined.set(true)
37
+ }
38
+
39
+
40
+
41
+ }
@@ -0,0 +1,33 @@
1
+ @if (detailTab()) {
2
+ <p>{{neuReservation().id}}</p>
3
+ <p>From: {{connection().fromStationName}}</p>
4
+ <p>TO: {{connection().toStationName}}</p>
5
+ <p>Date: {{connection().date}}</p>
6
+ <p>Children: {{neuReservation().children?.length}}</p>
7
+ <button (click)="renew()">Make Another Reservation</button>
8
+ } @else {
9
+
10
+ <h1>Train reservation</h1>
11
+ <p>Username</p>
12
+ <p>{{user()}}</p>
13
+ <form [formGroup]="reservationGroup" (ngSubmit)="reserve()">
14
+ <input type="checkbox" id="firstClassBox" formControlName="firstClassBox">
15
+ <label for="firstClassBox">First Class?</label>
16
+
17
+ <button type="button" (click)="addChild()">Add Child</button>
18
+ <div formArrayName="childrenArray">
19
+ @for (child of childrenArray.controls; track child){
20
+ <div [formGroupName]="$index">
21
+ <h5>Child {{$index+1}}</h5> <button type="button" (click)="removeChild($index)">Remove</button>
22
+ <label for="childName">Child Name</label>
23
+ <input id="childName" type="text" formControlName="name">
24
+
25
+ <label for="childAge">Child Age</label>
26
+ <input id="childAge" type="number" formControlName="age">
27
+ </div>
28
+ }
29
+ </div>
30
+ <button type="submit">Reserve</button>
31
+
32
+ </form>
33
+ }
@@ -0,0 +1,94 @@
1
+ import {Component, OnInit, signal} from '@angular/core';
2
+ import {ActivatedRoute} from '@angular/router';
3
+ import {HttpService} from '../http.service';
4
+ import {Connection} from '../domains/connection';
5
+ import {AuthService} from '../auth.service';
6
+ import {FormArray, FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms';
7
+ import {ReservationRequest} from '../domains/reservationRequest';
8
+ import {ReservationResponse} from '../domains/reservationResponse';
9
+
10
+ @Component({
11
+ selector: 'app-reservation',
12
+ imports: [
13
+ ReactiveFormsModule
14
+ ],
15
+ templateUrl: './reservation.component.html',
16
+ styleUrl: './reservation.component.css',
17
+ })
18
+ export class ReservationComponent implements OnInit {
19
+ detailTab = signal(false)
20
+ connectionId = -1;
21
+ connection = signal<Connection>({} as Connection)
22
+ user = signal('')
23
+ reservationGroup: FormGroup;
24
+ neuReservation = signal<ReservationResponse>({} as ReservationResponse)
25
+
26
+ constructor(private route: ActivatedRoute, private api: HttpService, private auth: AuthService) {
27
+ this.user.set(this.auth._user())
28
+ this.reservationGroup = new FormGroup({
29
+ firstClassBox: new FormControl(false) ?? false,
30
+ childrenArray: new FormArray([]) ?? []
31
+ })
32
+ }
33
+
34
+ get childrenArray() {
35
+ return this.reservationGroup.get('childrenArray') as FormArray
36
+ }
37
+
38
+ ngOnInit(): void {
39
+ this.route.paramMap.subscribe(params => {
40
+ this.connectionId = Number(params.get('id'));
41
+
42
+ if (this.connectionId) {
43
+ this.api.getConnection(this.connectionId).subscribe(
44
+ conn => this.connection.set(conn)
45
+ );
46
+ }
47
+ })
48
+ }
49
+
50
+ addChild() {
51
+ this.childrenArray.push(new FormGroup({
52
+ name: new FormControl(''),
53
+ age: new FormControl(0)
54
+ }))
55
+ }
56
+
57
+ protected removeChild($index: number) {
58
+ this.childrenArray.removeAt($index)
59
+ }
60
+
61
+ reserve() {
62
+ let reservation: ReservationRequest = {
63
+ connectionId: this.connectionId,
64
+ firstClass: this.reservationGroup.get('firstClassBox')?.value ?? false,
65
+ children: this.childrenArray.value ?? []
66
+ }
67
+ console.log(reservation)
68
+ this.api.postReservation(reservation).subscribe(
69
+ {
70
+ next: () => {
71
+ let reservations: ReservationResponse[] = []
72
+ this.detailTab.set(true)
73
+ this.api.getAllReservations().subscribe(res => {
74
+ reservations = res;
75
+ if (reservations[reservations.length - 1]) {
76
+ this.api.getReservationById(reservations[reservations.length - 1].id).subscribe(reser => {
77
+ this.neuReservation.set(reser)
78
+ })
79
+ }
80
+ })
81
+ }
82
+ }
83
+ )
84
+
85
+
86
+ }
87
+
88
+ renew() {
89
+ this.reservationGroup.reset()
90
+ this.childrenArray.clear()
91
+ this.detailTab.set(false)
92
+
93
+ }
94
+ }
File without changes
@@ -0,0 +1 @@
1
+ <router-outlet></router-outlet>
@@ -0,0 +1,14 @@
1
+ import {Component, signal} from '@angular/core';
2
+ import {Router, RouterOutlet} from '@angular/router';
3
+ import {AuthService} from './auth.service';
4
+
5
+ @Component({
6
+ selector: 'app-root',
7
+ templateUrl: './app.component.html',
8
+ imports: [
9
+ RouterOutlet
10
+ ],
11
+ styleUrl: './app.component.css'
12
+ })
13
+ export class AppComponent {
14
+ }
@@ -0,0 +1,12 @@
1
+ import { ApplicationConfig } from '@angular/core';
2
+ import {provideRouter, withComponentInputBinding} from '@angular/router';
3
+
4
+ import { routes } from './app.routes';
5
+ import {provideHttpClient, withInterceptors} from '@angular/common/http';
6
+ import {authInterceptor} from './auth.interceptor';
7
+
8
+ export const appConfig: ApplicationConfig = {
9
+ providers: [
10
+ provideRouter(routes,withComponentInputBinding()),
11
+ provideHttpClient(withInterceptors([authInterceptor]))]
12
+ };
@@ -0,0 +1,12 @@
1
+ import { Routes } from '@angular/router';
2
+ import {LoginComponent} from './login/login.component';
3
+ import {OverviewComponent} from './overview/overview.component';
4
+ import {ReservationComponent} from './reservation/reservation.component';
5
+ import {AuthGuard} from './auth.guard';
6
+
7
+ export const routes: Routes = [
8
+ {path: 'login', component: LoginComponent},
9
+ {path: 'book/:id', component: ReservationComponent, canActivate: [AuthGuard]},
10
+ {path: '', component: OverviewComponent},
11
+ {path: '**', redirectTo:'', pathMatch: "full"}
12
+ ];
@@ -0,0 +1,29 @@
1
+ import {
2
+ ActivatedRouteSnapshot,
3
+ CanActivate,
4
+ CanActivateFn,
5
+ GuardResult,
6
+ MaybeAsync, Router,
7
+ RouterStateSnapshot
8
+ } from '@angular/router';
9
+ import {AuthService} from './auth.service';
10
+ import {Injectable} from '@angular/core';
11
+
12
+ @Injectable({
13
+ providedIn: 'root'
14
+ })
15
+
16
+ export class AuthGuard implements CanActivate{
17
+ constructor(private router: Router, private auth:AuthService) {
18
+ }
19
+ canActivate() {
20
+ if (this.auth.isLoggedIn()){
21
+ return true;
22
+ }
23
+ else {
24
+ this.router.navigate(['/login'])
25
+ return false;
26
+ }
27
+ }
28
+
29
+ }
@@ -0,0 +1,14 @@
1
+ import { HttpInterceptorFn } from '@angular/common/http';
2
+ import {inject} from '@angular/core';
3
+ import {AuthService} from './auth.service';
4
+
5
+ export const authInterceptor: HttpInterceptorFn = (req, next) => {
6
+ const authService = inject(AuthService);
7
+ if (!authService.isLoggedIn())
8
+ return next(req);
9
+ const cloned = req.clone({
10
+ headers: req.headers.set('Authorization',
11
+ `Bearer ${authService.getToken()}`)
12
+ });
13
+ return next(cloned);
14
+ };
@@ -0,0 +1,41 @@
1
+ import {Injectable, signal} from '@angular/core';
2
+ import {HttpService} from './http.service';
3
+ import {HttpClient} from '@angular/common/http';
4
+ import {tap} from 'rxjs';
5
+ import {Router} from '@angular/router';
6
+
7
+ @Injectable({
8
+ providedIn: 'root',
9
+ })
10
+ export class AuthService {
11
+ _user = signal('')
12
+ private baseUrl = 'http://localhost:3000'
13
+ private static tokenKey: string = "token";
14
+ constructor(private httpClient : HttpClient, private router : Router) {
15
+ }
16
+ login(username: string, password: string) {
17
+ return this.httpClient
18
+ .post<{ token: string }>(`${this.baseUrl}/login`,
19
+ { username: username, password: password })
20
+ .pipe(
21
+ tap(response => {
22
+ localStorage.setItem(AuthService.tokenKey, response.token);
23
+ this._user.set(username);
24
+ })
25
+ );
26
+ }
27
+
28
+ logout(): void {
29
+ localStorage.removeItem(AuthService.tokenKey);
30
+ this._user.set('');
31
+ this.router.navigate(['/login']);
32
+ }
33
+
34
+ isLoggedIn(){
35
+ return !!localStorage.getItem(AuthService.tokenKey)
36
+ }
37
+
38
+ getToken() {
39
+ return localStorage.getItem(AuthService.tokenKey)
40
+ }
41
+ }
@@ -0,0 +1,11 @@
1
+
2
+ export class Child{
3
+ name: string;
4
+ age: number;
5
+
6
+
7
+ constructor(name: string, age: number) {
8
+ this.name = name;
9
+ this.age = age;
10
+ }
11
+ }
@@ -0,0 +1,22 @@
1
+ export class Connection{
2
+ id: number;
3
+ fromStationId: number;
4
+ toStationId: number;
5
+ fromStationName: string;
6
+ toStationName:string;
7
+ date: string;
8
+ departureTime:string;
9
+ arrivalTime:string;
10
+
11
+
12
+ constructor(id: number, fromStationId: number, toStationId: number, fromStationName: string, toStationName: string, date: string, departureTime: string, arrivalTime: string) {
13
+ this.id = id;
14
+ this.fromStationId = fromStationId;
15
+ this.toStationId = toStationId;
16
+ this.fromStationName = fromStationName;
17
+ this.toStationName = toStationName;
18
+ this.date = date;
19
+ this.departureTime = departureTime;
20
+ this.arrivalTime = arrivalTime;
21
+ }
22
+ }
@@ -0,0 +1,17 @@
1
+
2
+ export class Customer{
3
+ id:number
4
+ username:string
5
+ name:string
6
+ password:string
7
+ role:string
8
+
9
+
10
+ constructor(id: number, username: string, name: string, password: string, role: string) {
11
+ this.id = id;
12
+ this.username = username;
13
+ this.name = name;
14
+ this.password = password;
15
+ this.role = role;
16
+ }
17
+ }
@@ -0,0 +1,14 @@
1
+ import {Child} from './child';
2
+
3
+ export class ReservationRequest{
4
+ connectionId:number;
5
+ firstClass:boolean;
6
+ children:Child[]
7
+
8
+
9
+ constructor(connectionId: number, firstClass: boolean, children: Child[]) {
10
+ this.connectionId = connectionId;
11
+ this.firstClass = firstClass;
12
+ this.children = children;
13
+ }
14
+ }
@@ -0,0 +1,16 @@
1
+ import {Child} from './child';
2
+
3
+ export class ReservationResponse{
4
+ id:number;
5
+ connectionId:number;
6
+ firstClass:boolean;
7
+ children:Child[];
8
+
9
+
10
+ constructor(id: number, connectionId: number, firstClass: boolean, children: Child[]) {
11
+ this.id = id;
12
+ this.connectionId = connectionId;
13
+ this.firstClass = firstClass;
14
+ this.children = children;
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ export class Station{
2
+ id:number;
3
+ name:string
4
+
5
+
6
+ constructor(id: number, name: string) {
7
+ this.id = id;
8
+ this.name = name;
9
+ }
10
+ }
@@ -0,0 +1,34 @@
1
+ import { Injectable } from '@angular/core';
2
+ import {HttpClient} from '@angular/common/http';
3
+ import {Connection} from './domains/connection';
4
+ import {ReservationRequest} from './domains/reservationRequest';
5
+ import {ReservationResponse} from './domains/reservationResponse';
6
+
7
+ @Injectable({
8
+ providedIn: 'root',
9
+ })
10
+ export class HttpService {
11
+ baseurl = 'http://localhost:3000/'
12
+ constructor(private http:HttpClient) {
13
+ }
14
+
15
+ getAllConnections(){
16
+ return this.http.get<Connection[]>(this.baseurl + "connections")
17
+ }
18
+
19
+ getConnection(connectionId: number) {
20
+ return this.http.get<Connection>(this.baseurl + "connections/" + connectionId)
21
+ }
22
+
23
+ postReservation(reservation:ReservationRequest){
24
+ return this.http.post(this.baseurl + "reservations", reservation)
25
+ }
26
+
27
+ getAllReservations(){
28
+ return this.http.get<ReservationResponse[]>(this.baseurl+"reservations")
29
+ }
30
+
31
+ getReservationById(id:number){
32
+ return this.http.get<ReservationResponse>(this.baseurl+ "reservations/"+id)
33
+ }
34
+ }
File without changes
@@ -0,0 +1,14 @@
1
+ <form [formGroup] = "loginForm" (ngSubmit)="login()">
2
+ @if (errorMessage() !== '') {
3
+ <p>{{errorMessage()}}</p>
4
+ }
5
+
6
+ <label for="username">Nutzername: </label>
7
+ <input type="text" id="username" formControlName="username">
8
+
9
+ <label for="password">Password: </label>
10
+ <input type="password" id="password" formControlName="password">
11
+
12
+ <button type="submit">Login</button>
13
+
14
+ </form>
@@ -0,0 +1,32 @@
1
+ import {Component, signal} from '@angular/core';
2
+ import {AuthService} from '../auth.service';
3
+ import {Router} from '@angular/router';
4
+ import {FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators} from '@angular/forms';
5
+
6
+ @Component({
7
+ selector: 'app-login',
8
+ imports: [
9
+ ReactiveFormsModule
10
+ ],
11
+ templateUrl: './login.component.html',
12
+ styleUrl: './login.component.css',
13
+ })
14
+ export class LoginComponent {
15
+ errorMessage = signal('')
16
+ loginForm: FormGroup;
17
+ constructor(private auth:AuthService, private router: Router, private fb: FormBuilder) {
18
+ this.loginForm = new FormGroup({
19
+ username: new FormControl('demo@demo.com', Validators.required),
20
+ password: new FormControl('demo', Validators.required)
21
+ })
22
+ }
23
+
24
+
25
+ login() {
26
+ this.auth.login(this.loginForm.value.username, this.loginForm.value.password).subscribe({
27
+ next: () => {this.router.navigate(['/overview'])},
28
+ error: () => {this.errorMessage.set("Fehlerhafte Logindaten")}
29
+ }
30
+ )
31
+ }
32
+ }
@@ -0,0 +1,14 @@
1
+ <h1>Connection overview</h1>
2
+ @if (logined()){
3
+ <button (click)="logout()">Logout</button>
4
+ } @else {
5
+ <button (click)="login()">Login</button>
6
+ }
7
+ <div>
8
+ @for (connection of connections(); track connection) {
9
+ <h5>Connection {{$index+1}}</h5>
10
+ <p>{{connection.fromStationName}} ===> {{connection.toStationName}}</p>
11
+ <a [routerLink]="['/book/', connection.id]">Buchen</a>
12
+ }
13
+ </div>
14
+
@@ -0,0 +1,41 @@
1
+ import {Component, OnInit, signal} from '@angular/core';
2
+ import {HttpService} from '../http.service';
3
+ import {Connection} from '../domains/connection';
4
+ import {Router, RouterLink} from '@angular/router';
5
+ import {AuthService} from '../auth.service';
6
+
7
+ @Component({
8
+ selector: 'app-overview',
9
+ imports: [
10
+ RouterLink
11
+ ],
12
+ templateUrl: './overview.component.html',
13
+ styleUrl: './overview.component.css',
14
+ })
15
+ export class OverviewComponent implements OnInit{
16
+ logined = signal(false)
17
+ connections = signal<Connection[]>([])
18
+ constructor(private http:HttpService, private auth:AuthService, private router: Router) {
19
+ this.logined.set(auth.isLoggedIn())
20
+ }
21
+
22
+ ngOnInit() {
23
+ this.http.getAllConnections().subscribe(cs => {
24
+ this.connections.set(cs)
25
+ })
26
+ }
27
+
28
+ logout(){
29
+ this.auth.logout();
30
+ this.router.navigate(['login'])
31
+ this.logined.set(false)
32
+ }
33
+
34
+ login() {
35
+ this.router.navigate(['login'])
36
+ this.logined.set(true)
37
+ }
38
+
39
+
40
+
41
+ }
@@ -0,0 +1,33 @@
1
+ @if (detailTab()) {
2
+ <p>{{neuReservation().id}}</p>
3
+ <p>From: {{connection().fromStationName}}</p>
4
+ <p>TO: {{connection().toStationName}}</p>
5
+ <p>Date: {{connection().date}}</p>
6
+ <p>Children: {{neuReservation().children?.length}}</p>
7
+ <button (click)="renew()">Make Another Reservation</button>
8
+ } @else {
9
+
10
+ <h1>Train reservation</h1>
11
+ <p>Username</p>
12
+ <p>{{user()}}</p>
13
+ <form [formGroup]="reservationGroup" (ngSubmit)="reserve()">
14
+ <input type="checkbox" id="firstClassBox" formControlName="firstClassBox">
15
+ <label for="firstClassBox">First Class?</label>
16
+
17
+ <button type="button" (click)="addChild()">Add Child</button>
18
+ <div formArrayName="childrenArray">
19
+ @for (child of childrenArray.controls; track child){
20
+ <div [formGroupName]="$index">
21
+ <h5>Child {{$index+1}}</h5> <button type="button" (click)="removeChild($index)">Remove</button>
22
+ <label for="childName">Child Name</label>
23
+ <input id="childName" type="text" formControlName="name">
24
+
25
+ <label for="childAge">Child Age</label>
26
+ <input id="childAge" type="number" formControlName="age">
27
+ </div>
28
+ }
29
+ </div>
30
+ <button type="submit">Reserve</button>
31
+
32
+ </form>
33
+ }
@@ -0,0 +1,94 @@
1
+ import {Component, OnInit, signal} from '@angular/core';
2
+ import {ActivatedRoute} from '@angular/router';
3
+ import {HttpService} from '../http.service';
4
+ import {Connection} from '../domains/connection';
5
+ import {AuthService} from '../auth.service';
6
+ import {FormArray, FormControl, FormGroup, ReactiveFormsModule} from '@angular/forms';
7
+ import {ReservationRequest} from '../domains/reservationRequest';
8
+ import {ReservationResponse} from '../domains/reservationResponse';
9
+
10
+ @Component({
11
+ selector: 'app-reservation',
12
+ imports: [
13
+ ReactiveFormsModule
14
+ ],
15
+ templateUrl: './reservation.component.html',
16
+ styleUrl: './reservation.component.css',
17
+ })
18
+ export class ReservationComponent implements OnInit {
19
+ detailTab = signal(false)
20
+ connectionId = -1;
21
+ connection = signal<Connection>({} as Connection)
22
+ user = signal('')
23
+ reservationGroup: FormGroup;
24
+ neuReservation = signal<ReservationResponse>({} as ReservationResponse)
25
+
26
+ constructor(private route: ActivatedRoute, private api: HttpService, private auth: AuthService) {
27
+ this.user.set(this.auth._user())
28
+ this.reservationGroup = new FormGroup({
29
+ firstClassBox: new FormControl(false) ?? false,
30
+ childrenArray: new FormArray([]) ?? []
31
+ })
32
+ }
33
+
34
+ get childrenArray() {
35
+ return this.reservationGroup.get('childrenArray') as FormArray
36
+ }
37
+
38
+ ngOnInit(): void {
39
+ this.route.paramMap.subscribe(params => {
40
+ this.connectionId = Number(params.get('id'));
41
+
42
+ if (this.connectionId) {
43
+ this.api.getConnection(this.connectionId).subscribe(
44
+ conn => this.connection.set(conn)
45
+ );
46
+ }
47
+ })
48
+ }
49
+
50
+ addChild() {
51
+ this.childrenArray.push(new FormGroup({
52
+ name: new FormControl(''),
53
+ age: new FormControl(0)
54
+ }))
55
+ }
56
+
57
+ protected removeChild($index: number) {
58
+ this.childrenArray.removeAt($index)
59
+ }
60
+
61
+ reserve() {
62
+ let reservation: ReservationRequest = {
63
+ connectionId: this.connectionId,
64
+ firstClass: this.reservationGroup.get('firstClassBox')?.value ?? false,
65
+ children: this.childrenArray.value ?? []
66
+ }
67
+ console.log(reservation)
68
+ this.api.postReservation(reservation).subscribe(
69
+ {
70
+ next: () => {
71
+ let reservations: ReservationResponse[] = []
72
+ this.detailTab.set(true)
73
+ this.api.getAllReservations().subscribe(res => {
74
+ reservations = res;
75
+ if (reservations[reservations.length - 1]) {
76
+ this.api.getReservationById(reservations[reservations.length - 1].id).subscribe(reser => {
77
+ this.neuReservation.set(reser)
78
+ })
79
+ }
80
+ })
81
+ }
82
+ }
83
+ )
84
+
85
+
86
+ }
87
+
88
+ renew() {
89
+ this.reservationGroup.reset()
90
+ this.childrenArray.clear()
91
+ this.detailTab.set(false)
92
+
93
+ }
94
+ }