style: format code for consistency and readability
This commit is contained in:
parent
69d26e89b7
commit
386813c524
44 changed files with 566 additions and 370 deletions
17
angular.json
17
angular.json
|
@ -16,9 +16,7 @@
|
||||||
"outputPath": "dist/hotel-manager",
|
"outputPath": "dist/hotel-manager",
|
||||||
"index": "src/index.html",
|
"index": "src/index.html",
|
||||||
"browser": "src/main.ts",
|
"browser": "src/main.ts",
|
||||||
"polyfills": [
|
"polyfills": ["zone.js"],
|
||||||
"zone.js"
|
|
||||||
],
|
|
||||||
"tsConfig": "tsconfig.app.json",
|
"tsConfig": "tsconfig.app.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
|
@ -27,9 +25,7 @@
|
||||||
},
|
},
|
||||||
"src/assets"
|
"src/assets"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": ["src/styles.css"],
|
||||||
"src/styles.css"
|
|
||||||
],
|
|
||||||
"scripts": []
|
"scripts": []
|
||||||
},
|
},
|
||||||
"configurations": {
|
"configurations": {
|
||||||
|
@ -74,10 +70,7 @@
|
||||||
"test": {
|
"test": {
|
||||||
"builder": "@angular-devkit/build-angular:karma",
|
"builder": "@angular-devkit/build-angular:karma",
|
||||||
"options": {
|
"options": {
|
||||||
"polyfills": [
|
"polyfills": ["zone.js", "zone.js/testing"],
|
||||||
"zone.js",
|
|
||||||
"zone.js/testing"
|
|
||||||
],
|
|
||||||
"tsConfig": "tsconfig.spec.json",
|
"tsConfig": "tsconfig.spec.json",
|
||||||
"assets": [
|
"assets": [
|
||||||
{
|
{
|
||||||
|
@ -85,9 +78,7 @@
|
||||||
"input": "public"
|
"input": "public"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": ["src/styles.css"],
|
||||||
"src/styles.css"
|
|
||||||
],
|
|
||||||
"scripts": []
|
"scripts": []
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||||
"extends": [
|
"extends": ["local>Renovate/renovate-config"]
|
||||||
"local>Renovate/renovate-config"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
<button type="button" class="px-6 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75">{{ text }}</button>
|
<button
|
||||||
|
type="button"
|
||||||
|
class="px-6 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75"
|
||||||
|
>
|
||||||
|
{{ text }}
|
||||||
|
</button>
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Component } from "@angular/core";
|
import { Component } from '@angular/core';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-button',
|
selector: 'app-button',
|
||||||
|
|
|
@ -1,4 +1,12 @@
|
||||||
<h1 class="text-2xl font-bold mb-4">Child</h1>
|
<h1 class="text-2xl font-bold mb-4">Child</h1>
|
||||||
<p class="text-lg mb-2">Balance: {{balance}}</p>
|
<p class="text-lg mb-2">Balance: {{ balance }}</p>
|
||||||
<p [class.hidden]="!isBroke" class="text-red-500 mb-4">I'm broke. Now I'm about as poor as Jan-Marlon.</p>
|
<p [class.hidden]="!isBroke" class="text-red-500 mb-4">
|
||||||
<button type="button" (click)="takeMoney()" class="px-6 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75">Take Money</button>
|
I'm broke. Now I'm about as poor as Jan-Marlon.
|
||||||
|
</p>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
(click)="takeMoney()"
|
||||||
|
class="px-6 py-2 bg-blue-500 text-white font-semibold rounded-lg shadow-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-400 focus:ring-opacity-75"
|
||||||
|
>
|
||||||
|
Take Money
|
||||||
|
</button>
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Component, Input, Output, EventEmitter } from "@angular/core";
|
import { Component, Input, Output, EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-child',
|
selector: 'app-child',
|
||||||
|
|
|
@ -1,8 +1,37 @@
|
||||||
<p class="text-2xl font-bold text-gray-800 mb-2">Name: {{hotel.hotelName}}</p>
|
<p class="text-2xl font-bold text-gray-800 mb-2">Name: {{ hotel.hotelName }}</p>
|
||||||
<p class="text-base text-gray-600 mb-4">Description: {{hotel.description}}</p>
|
<p class="text-base text-gray-600 mb-4">Description: {{ hotel.description }}</p>
|
||||||
<p class="text-lg font-medium text-green-600 mb-4">Price: {{hotel.price | currency : getCurrencyCode(selectedLanguage) : "symbol" : "2.2-2" : selectedLanguage}}</p>
|
<p class="text-lg font-medium text-green-600 mb-4">
|
||||||
<select [ngModel]="selectedLanguage" (ngModelChange)="languageChange($event)" class="input-field block w-full p-2 border border-gray-300 rounded-md mb-4 focus:border-blue-500 focus:ring focus:ring-blue-200">
|
Price:
|
||||||
<option *ngFor="let lang of langs" [value]="lang.code" [selected]="lang.lang == 'de'">{{lang.lang}}</option>
|
{{
|
||||||
|
hotel.price
|
||||||
|
| currency
|
||||||
|
: getCurrencyCode(selectedLanguage)
|
||||||
|
: "symbol"
|
||||||
|
: "2.2-2"
|
||||||
|
: selectedLanguage
|
||||||
|
}}
|
||||||
|
</p>
|
||||||
|
<select
|
||||||
|
[ngModel]="selectedLanguage"
|
||||||
|
(ngModelChange)="languageChange($event)"
|
||||||
|
class="input-field block w-full p-2 border border-gray-300 rounded-md mb-4 focus:border-blue-500 focus:ring focus:ring-blue-200"
|
||||||
|
>
|
||||||
|
<option
|
||||||
|
*ngFor="let lang of langs"
|
||||||
|
[value]="lang.code"
|
||||||
|
[selected]="lang.lang == 'de'"
|
||||||
|
>
|
||||||
|
{{ lang.lang }}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<img src="{{hotel.imageUrl}}" alt="Hotel" class="w-full rounded-full h-auto animate-shake shadow-lg mb-4">
|
<img
|
||||||
<a *ngIf="!isDetail" routerLink="/hotels/{{hotel.id}}" class="submit-button text-blue-600 hover:text-blue-800 hover:underline mb-4 block">Details</a>
|
src="{{ hotel.imageUrl }}"
|
||||||
|
alt="Hotel"
|
||||||
|
class="w-full rounded-full h-auto animate-shake shadow-lg mb-4"
|
||||||
|
/>
|
||||||
|
<a
|
||||||
|
*ngIf="!isDetail"
|
||||||
|
routerLink="/hotels/{{ hotel.id }}"
|
||||||
|
class="submit-button text-blue-600 hover:text-blue-800 hover:underline mb-4 block"
|
||||||
|
>Details</a
|
||||||
|
>
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
import { Component, Injectable, Input } from "@angular/core";
|
import { Component, Injectable, Input } from '@angular/core';
|
||||||
import { ChildComponent } from "../Child/child.component";
|
import { ChildComponent } from '../Child/child.component';
|
||||||
import { Hotel } from "./hotel";
|
import { Hotel } from './hotel';
|
||||||
import { CurrencyPipe, NgFor, NgIf } from "@angular/common";
|
import { CurrencyPipe, NgFor, NgIf } from '@angular/common';
|
||||||
import { FormsModule } from "@angular/forms";
|
import { FormsModule } from '@angular/forms';
|
||||||
import { StarRatingComponent } from "../star-rating/star-rating.component";
|
import { StarRatingComponent } from '../star-rating/star-rating.component';
|
||||||
import { HttpClient } from "@angular/common/http";
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { RouterLink } from "@angular/router";
|
import { RouterLink } from '@angular/router';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hotel-item',
|
selector: 'app-hotel-item',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
templateUrl: './HotelItem.component.html',
|
templateUrl: './HotelItem.component.html',
|
||||||
imports: [ChildComponent, CurrencyPipe, FormsModule, StarRatingComponent, NgIf, RouterLink, NgFor],
|
imports: [
|
||||||
|
ChildComponent,
|
||||||
|
CurrencyPipe,
|
||||||
|
FormsModule,
|
||||||
|
StarRatingComponent,
|
||||||
|
NgIf,
|
||||||
|
RouterLink,
|
||||||
|
NgFor,
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class HotelItem {
|
export class HotelItem {
|
||||||
|
|
||||||
@Input() public hotel!: Hotel;
|
@Input() public hotel!: Hotel;
|
||||||
public selectedLanguage?: string;
|
public selectedLanguage?: string;
|
||||||
|
|
||||||
|
@ -38,19 +45,19 @@ export class HotelItem {
|
||||||
|
|
||||||
public langs = [
|
public langs = [
|
||||||
{
|
{
|
||||||
"lang": "en",
|
lang: 'en',
|
||||||
"code": "en-US",
|
code: 'en-US',
|
||||||
"currency": "USD"
|
currency: 'USD',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lang": "cn",
|
lang: 'cn',
|
||||||
"code": "cn-CN",
|
code: 'cn-CN',
|
||||||
"currency": "CNY"
|
currency: 'CNY',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"lang": "de",
|
lang: 'de',
|
||||||
"code": "de-DE",
|
code: 'de-DE',
|
||||||
"currency": "EUR"
|
currency: 'EUR',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
<div class="m-3">
|
<div class="m-3">
|
||||||
<h1>Parent</h1>
|
<h1>Parent</h1>
|
||||||
<p>Kontostand: {{ balance }}</p>
|
<p>Kontostand: {{ balance }}</p>
|
||||||
<button type="button" class="button" (click)=addFifty()>Add Money</button>
|
<button type="button" class="button" (click)="addFifty()">Add Money</button>
|
||||||
|
|
||||||
<app-child [(balance)]="balance"></app-child>
|
<app-child [(balance)]="balance"></app-child>
|
||||||
<app-child [(balance)]="balance"></app-child>
|
<app-child [(balance)]="balance"></app-child>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { Component } from "@angular/core";
|
import { Component } from '@angular/core';
|
||||||
import { ChildComponent } from "../Child/child.component";
|
import { ChildComponent } from '../Child/child.component';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-parent',
|
selector: 'app-parent',
|
||||||
|
|
|
@ -1,47 +1,47 @@
|
||||||
import { Injectable } from "@angular/core";
|
import { Injectable } from '@angular/core';
|
||||||
import { Hotel } from "../../HotelItem/hotel";
|
import { Hotel } from '../../HotelItem/hotel';
|
||||||
import { from, Observable } from "rxjs";
|
import { from, Observable } from 'rxjs';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class HotelService {
|
export class HotelService {
|
||||||
public getHotels(): Observable<Hotel> {
|
public getHotels(): Observable<Hotel> {
|
||||||
return from([
|
return from([
|
||||||
{
|
{
|
||||||
"id": 1,
|
id: 1,
|
||||||
"hotelName": "Buea süßes Leben",
|
hotelName: 'Buea süßes Leben',
|
||||||
"description": "Schöne Aussicht am Meer",
|
description: 'Schöne Aussicht am Meer',
|
||||||
"price": 230.5,
|
price: 230.5,
|
||||||
"imageUrl": "assets/img/1.jpg",
|
imageUrl: 'assets/img/1.jpg',
|
||||||
"rating": 3.5,
|
rating: 3.5,
|
||||||
"tags": ["test"]
|
tags: ['test'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 2,
|
id: 2,
|
||||||
"hotelName": "Marrakesch",
|
hotelName: 'Marrakesch',
|
||||||
"description": "Genießen Sie den Blick auf die Berge",
|
description: 'Genießen Sie den Blick auf die Berge',
|
||||||
"price": 145.5,
|
price: 145.5,
|
||||||
"imageUrl": "assets/img/2.jpg",
|
imageUrl: 'assets/img/2.jpg',
|
||||||
"rating": 5,
|
rating: 5,
|
||||||
"tags": ["test"]
|
tags: ['test'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 3,
|
id: 3,
|
||||||
"hotelName": "Abuja neuer Palast",
|
hotelName: 'Abuja neuer Palast',
|
||||||
"description": "Kompletter Aufenthalt mit Autoservice",
|
description: 'Kompletter Aufenthalt mit Autoservice',
|
||||||
"price": 120.12,
|
price: 120.12,
|
||||||
"imageUrl": "assets/img/3.jpg",
|
imageUrl: 'assets/img/3.jpg',
|
||||||
"rating": 4,
|
rating: 4,
|
||||||
"tags": ["test"]
|
tags: ['test'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": 4,
|
id: 4,
|
||||||
"hotelName": "Kapstadt Stadt",
|
hotelName: 'Kapstadt Stadt',
|
||||||
"description": "Wunderschönes Ambiente für Ihren Aufenthalt",
|
description: 'Wunderschönes Ambiente für Ihren Aufenthalt',
|
||||||
"price": 135.12,
|
price: 135.12,
|
||||||
"imageUrl": "assets/img/4.jpg",
|
imageUrl: 'assets/img/4.jpg',
|
||||||
"rating": 2.5,
|
rating: 2.5,
|
||||||
"tags": ["test"]
|
tags: ['test'],
|
||||||
}
|
},
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1 +1,6 @@
|
||||||
<input [(ngModel)]="input" (ngModelChange)="update($event)" class="border border-gray-300 rounded-md p-2 w-full focus:border-blue-500 focus:ring focus:ring-blue-200" type="search">
|
<input
|
||||||
|
[(ngModel)]="input"
|
||||||
|
(ngModelChange)="update($event)"
|
||||||
|
class="border border-gray-300 rounded-md p-2 w-full focus:border-blue-500 focus:ring focus:ring-blue-200"
|
||||||
|
type="search"
|
||||||
|
/>
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from '@angular/common';
|
||||||
import { Component, NgModule } from "@angular/core";
|
import { Component, NgModule } from '@angular/core';
|
||||||
import { FormsModule, NgForm, NgModel } from "@angular/forms";
|
import { FormsModule, NgForm, NgModel } from '@angular/forms';
|
||||||
import { Input, Output } from "@angular/core";
|
import { Input, Output } from '@angular/core';
|
||||||
import { EventEmitter } from "@angular/core";
|
import { EventEmitter } from '@angular/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-search',
|
selector: 'app-search',
|
||||||
|
@ -11,7 +11,7 @@ import { EventEmitter } from "@angular/core";
|
||||||
imports: [FormsModule],
|
imports: [FormsModule],
|
||||||
})
|
})
|
||||||
export class SearchComponent {
|
export class SearchComponent {
|
||||||
@Input() public input: string = "";
|
@Input() public input: string = '';
|
||||||
@Output() inputChange = new EventEmitter<string>();
|
@Output() inputChange = new EventEmitter<string>();
|
||||||
|
|
||||||
public update(e: string) {
|
public update(e: string) {
|
||||||
|
|
|
@ -10,7 +10,6 @@ import { Hotel } from '../HotelItem/hotel';
|
||||||
* @implements {InMemoryDbService}
|
* @implements {InMemoryDbService}
|
||||||
*/
|
*/
|
||||||
export class HotelData implements InMemoryDbService {
|
export class HotelData implements InMemoryDbService {
|
||||||
|
|
||||||
createDb(): Record<string, Hotel[]> {
|
createDb(): Record<string, Hotel[]> {
|
||||||
const hotels: Hotel[] = [
|
const hotels: Hotel[] = [
|
||||||
{
|
{
|
||||||
|
@ -20,39 +19,43 @@ export class HotelData implements InMemoryDbService {
|
||||||
price: 230.5,
|
price: 230.5,
|
||||||
imageUrl: 'assets/img/1.jpg',
|
imageUrl: 'assets/img/1.jpg',
|
||||||
rating: 3.5,
|
rating: 3.5,
|
||||||
tags: ['nouveau']
|
tags: ['nouveau'],
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
hotelName: 'Marakech',
|
hotelName: 'Marakech',
|
||||||
description: 'Profitez de la vue sur les montagnes',
|
description: 'Profitez de la vue sur les montagnes',
|
||||||
price: 145.5,
|
price: 145.5,
|
||||||
imageUrl: 'assets/img/2.jpg',
|
imageUrl: 'assets/img/2.jpg',
|
||||||
rating: 5,
|
rating: 5,
|
||||||
tags: ['nouveau']
|
tags: ['nouveau'],
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
hotelName: 'Abudja new look palace',
|
hotelName: 'Abudja new look palace',
|
||||||
description: 'Séjour complet avec service de voitures',
|
description: 'Séjour complet avec service de voitures',
|
||||||
price: 120.12,
|
price: 120.12,
|
||||||
imageUrl: 'assets/img/3.jpg',
|
imageUrl: 'assets/img/3.jpg',
|
||||||
rating: 4,
|
rating: 4,
|
||||||
tags: ['nouveau']
|
tags: ['nouveau'],
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
hotelName: 'Cape town city',
|
hotelName: 'Cape town city',
|
||||||
description: 'Magnifique cadre pour votre séjour',
|
description: 'Magnifique cadre pour votre séjour',
|
||||||
price: 135.12,
|
price: 135.12,
|
||||||
imageUrl: 'assets/img/4.jpg',
|
imageUrl: 'assets/img/4.jpg',
|
||||||
rating: 2.5,
|
rating: 2.5,
|
||||||
tags: ['nouveau']
|
tags: ['nouveau'],
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
return { hotels };
|
return { hotels };
|
||||||
}
|
}
|
||||||
|
|
||||||
genId(hotels: Hotel[]): number {
|
genId(hotels: Hotel[]): number {
|
||||||
return hotels.length > 0 ? Math.max(...hotels.map(hotel => hotel.id)) + 1 : 1;
|
return hotels.length > 0
|
||||||
|
? Math.max(...hotels.map((hotel) => hotel.id)) + 1
|
||||||
|
: 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,8 @@ describe('AppComponent', () => {
|
||||||
const fixture = TestBed.createComponent(AppComponent);
|
const fixture = TestBed.createComponent(AppComponent);
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const compiled = fixture.nativeElement as HTMLElement;
|
const compiled = fixture.nativeElement as HTMLElement;
|
||||||
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, hotel-manager');
|
expect(compiled.querySelector('h1')?.textContent).toContain(
|
||||||
|
'Hello, hotel-manager',
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
import { Component, Injectable } from '@angular/core';
|
import { Component, Injectable } from '@angular/core';
|
||||||
import { HotelItem } from './HotelItem/HotelItem.component';
|
import { HotelItem } from './HotelItem/HotelItem.component';
|
||||||
import { SearchComponent } from './Search/search.component';
|
import { SearchComponent } from './Search/search.component';
|
||||||
import { AsyncPipe, NgFor, NgForOf, NgIf, UpperCasePipe } from '@angular/common';
|
import {
|
||||||
|
AsyncPipe,
|
||||||
|
NgFor,
|
||||||
|
NgForOf,
|
||||||
|
NgIf,
|
||||||
|
UpperCasePipe,
|
||||||
|
} from '@angular/common';
|
||||||
import { TextPipe } from '../text.pipe';
|
import { TextPipe } from '../text.pipe';
|
||||||
import { HotelService } from './Parent/services/hotel.service';
|
import { HotelService } from './Parent/services/hotel.service';
|
||||||
import { inject } from '@angular/core';
|
import { inject } from '@angular/core';
|
||||||
|
@ -10,15 +16,23 @@ import { HttpClient } from '@angular/common/http';
|
||||||
import { Hotel } from './HotelItem/hotel';
|
import { Hotel } from './HotelItem/hotel';
|
||||||
import { RouterOutlet } from '@angular/router';
|
import { RouterOutlet } from '@angular/router';
|
||||||
|
|
||||||
@Injectable({providedIn: "root"})
|
@Injectable({ providedIn: 'root' })
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-root',
|
selector: 'app-root',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [RouterOutlet, NgFor, NgForOf, NgIf, HotelItem, SearchComponent, UpperCasePipe, TextPipe, AsyncPipe],
|
imports: [
|
||||||
|
RouterOutlet,
|
||||||
|
NgFor,
|
||||||
|
NgForOf,
|
||||||
|
NgIf,
|
||||||
|
HotelItem,
|
||||||
|
SearchComponent,
|
||||||
|
UpperCasePipe,
|
||||||
|
TextPipe,
|
||||||
|
AsyncPipe,
|
||||||
|
],
|
||||||
templateUrl: './app.component.html',
|
templateUrl: './app.component.html',
|
||||||
providers: [HotelService],
|
providers: [HotelService],
|
||||||
styleUrl: './app.component.css'
|
styleUrl: './app.component.css',
|
||||||
})
|
})
|
||||||
export class AppComponent {
|
export class AppComponent {}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,8 @@
|
||||||
import { ApplicationConfig, importProvidersFrom, provideZoneChangeDetection } from '@angular/core';
|
import {
|
||||||
|
ApplicationConfig,
|
||||||
|
importProvidersFrom,
|
||||||
|
provideZoneChangeDetection,
|
||||||
|
} from '@angular/core';
|
||||||
import { provideRouter } from '@angular/router';
|
import { provideRouter } from '@angular/router';
|
||||||
import localeDe from '@angular/common/locales/de';
|
import localeDe from '@angular/common/locales/de';
|
||||||
import localeCn from '@angular/common/locales/zh-Hans';
|
import localeCn from '@angular/common/locales/zh-Hans';
|
||||||
|
@ -16,5 +20,6 @@ export const appConfig: ApplicationConfig = {
|
||||||
provideZoneChangeDetection({ eventCoalescing: true }),
|
provideZoneChangeDetection({ eventCoalescing: true }),
|
||||||
provideRouter(routes),
|
provideRouter(routes),
|
||||||
provideHttpClient(),
|
provideHttpClient(),
|
||||||
importProvidersFrom(InMemoryWebApiModule.forRoot(HotelData))]
|
importProvidersFrom(InMemoryWebApiModule.forRoot(HotelData)),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,19 +6,19 @@ import { NewHotelComponent } from './new-hotel/new-hotel.component';
|
||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{
|
{
|
||||||
path: "",
|
path: '',
|
||||||
component: HotelListComponent,
|
component: HotelListComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "hotels/:id",
|
path: 'hotels/:id',
|
||||||
component: HotelDetailsComponent,
|
component: HotelDetailsComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "testing",
|
path: 'testing',
|
||||||
component: TestComponent,
|
component: TestComponent,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
path: "new",
|
path: 'new',
|
||||||
component: NewHotelComponent,
|
component: NewHotelComponent,
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
|
|
|
@ -1,25 +1,11 @@
|
||||||
import { AbstractControl, FormGroup, ValidationErrors, ValidatorFn } from "@angular/forms";
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
FormGroup,
|
||||||
|
ValidationErrors,
|
||||||
|
ValidatorFn,
|
||||||
|
} from '@angular/forms';
|
||||||
|
|
||||||
export class CrossValidator {
|
export class CrossValidator {
|
||||||
public onlyAllowNameAndDescriptionSame() {
|
|
||||||
return (control: AbstractControl): ValidationErrors | null => {
|
|
||||||
if (!(control instanceof FormGroup)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const name = control.get('name')?.value;
|
|
||||||
const description = control.get('description')?.value;
|
|
||||||
|
|
||||||
console.log(name, description);
|
|
||||||
|
|
||||||
const error = name !== description ? { mismatch: true } : null;
|
|
||||||
|
|
||||||
console.log(error);
|
|
||||||
|
|
||||||
return error;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public crossValidate() {
|
public crossValidate() {
|
||||||
return (control: AbstractControl): ValidationErrors | null => {
|
return (control: AbstractControl): ValidationErrors | null => {
|
||||||
if (!(control instanceof FormGroup)) {
|
if (!(control instanceof FormGroup)) {
|
||||||
|
@ -28,7 +14,23 @@ export class CrossValidator {
|
||||||
|
|
||||||
const contactType = control.get('contactType')?.value;
|
const contactType = control.get('contactType')?.value;
|
||||||
|
|
||||||
if (contactType == "None") return null;
|
if (contactType == ('None' || null)) return null;
|
||||||
|
|
||||||
|
let error = null;
|
||||||
|
if (contactType == 'Email') {
|
||||||
|
error =
|
||||||
|
control.get('email')?.value != control.get('emailConfirmation')?.value
|
||||||
|
? { mismatchEmail: true }
|
||||||
|
: null;
|
||||||
|
} else {
|
||||||
|
error =
|
||||||
|
control.get('phone')?.value != control.get('phoneConfirmation')?.value
|
||||||
|
? { mismatchPhone: true }
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('Error: ', error);
|
||||||
|
return error;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('HotelDetailsComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [HotelDetailsComponent]
|
imports: [HotelDetailsComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HotelDetailsComponent);
|
fixture = TestBed.createComponent(HotelDetailsComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -11,35 +11,51 @@ import { HotelFormComponent } from '../hotel-form/hotel-form.component';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hotel-details',
|
selector: 'app-hotel-details',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [CurrencyPipe, StarRatingComponent, HotelItem, HotelFormComponent, NgIf, NgForOf],
|
imports: [
|
||||||
|
CurrencyPipe,
|
||||||
|
StarRatingComponent,
|
||||||
|
HotelItem,
|
||||||
|
HotelFormComponent,
|
||||||
|
NgIf,
|
||||||
|
NgForOf,
|
||||||
|
],
|
||||||
templateUrl: './hotel-details.component.html',
|
templateUrl: './hotel-details.component.html',
|
||||||
styleUrl: './hotel-details.component.css'
|
styleUrl: './hotel-details.component.css',
|
||||||
})
|
})
|
||||||
export class HotelDetailsComponent implements OnInit {
|
export class HotelDetailsComponent implements OnInit {
|
||||||
public hotel: any;
|
public hotel: any;
|
||||||
|
|
||||||
constructor(private route: ActivatedRoute, private http: HttpClient, private router: Router) { }
|
constructor(
|
||||||
|
private route: ActivatedRoute,
|
||||||
|
private http: HttpClient,
|
||||||
|
private router: Router,
|
||||||
|
) {}
|
||||||
|
|
||||||
delete(): void {
|
delete(): void {
|
||||||
if (confirm("Are u sure u want to delete this hotel")) {
|
if (confirm('Are u sure u want to delete this hotel')) {
|
||||||
this.http.delete<Hotel>("/api/hotels/" + this.route.snapshot.paramMap.get("id")).subscribe();
|
this.http
|
||||||
this.router.navigate(["/"]);
|
.delete<Hotel>('/api/hotels/' + this.route.snapshot.paramMap.get('id'))
|
||||||
|
.subscribe();
|
||||||
|
this.router.navigate(['/']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
const routeParams = this.route.snapshot.paramMap;
|
const routeParams = this.route.snapshot.paramMap;
|
||||||
const hotelId = routeParams.get("id");
|
const hotelId = routeParams.get('id');
|
||||||
|
|
||||||
this.http.get<Hotel>("api/hotels/" + hotelId).pipe(
|
this.http
|
||||||
|
.get<Hotel>('api/hotels/' + hotelId)
|
||||||
|
.pipe(
|
||||||
catchError(() => {
|
catchError(() => {
|
||||||
alert("Not Found");
|
alert('Not Found');
|
||||||
this.router.navigate(["/"]);
|
this.router.navigate(['/']);
|
||||||
|
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
})
|
}),
|
||||||
).subscribe(res => {
|
)
|
||||||
|
.subscribe((res) => {
|
||||||
this.hotel = res;
|
this.hotel = res;
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,47 @@
|
||||||
<p>hotel-form works!</p>
|
<p>hotel-form works!</p>
|
||||||
<h1>{{errorMsg}}</h1>
|
<h1>{{ errorMsg }}</h1>
|
||||||
<form [formGroup]="hotelForm">
|
<form [formGroup]="hotelForm">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<div class="text-red-500 text-5xl font-bold" *ngIf="errorMessages['name']">{{ errorMessages['name'] }}</div>
|
<div class="text-red-500 text-5xl font-bold" *ngIf="errorMessages['name']">
|
||||||
<input type="text" class="border-red-500 text-3xl border-3 rounded-full bg-gray-500 font-bold p-3 m-3 border-8" id="name" formControlName="name">
|
{{ errorMessages["name"] }}
|
||||||
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="border-red-500 text-3xl border-3 rounded-full bg-gray-500 font-bold p-3 m-3 border-8"
|
||||||
|
id="name"
|
||||||
|
formControlName="name"
|
||||||
|
/>
|
||||||
<label for="description">Description</label>
|
<label for="description">Description</label>
|
||||||
<div class="text-red" *ngIf="errorMessages['description']">{{ errorMessages['description'] }}</div>
|
<div class="text-red" *ngIf="errorMessages['description']">
|
||||||
<input type="text" class="input-field" [class.border-8]='hotelForm.get("description")?.invalid' id="description"
|
{{ errorMessages["description"] }}
|
||||||
formControlName="description">
|
</div>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
class="input-field"
|
||||||
|
[class.border-8]="hotelForm.get('description')?.invalid"
|
||||||
|
id="description"
|
||||||
|
formControlName="description"
|
||||||
|
/>
|
||||||
<label for="price">Price</label>
|
<label for="price">Price</label>
|
||||||
<div class="text-red" *ngIf="errorMessages['price']">{{ errorMessages['price'] }}</div>
|
<div class="text-red" *ngIf="errorMessages['price']">
|
||||||
<input type="number" class="input-field"
|
{{ errorMessages["price"] }}
|
||||||
[class.border-8]='hotelForm.get("price")?.invalid && hotelForm.get("price")?.touched' id="price"
|
</div>
|
||||||
formControlName="price">
|
<input
|
||||||
<button class="submit-button" (click)="submit()" [disabled]="!hotelForm.valid" type="submit">😃 Submit</button>
|
type="number"
|
||||||
|
class="input-field"
|
||||||
|
[class.border-8]="
|
||||||
|
hotelForm.get('price')?.invalid && hotelForm.get('price')?.touched
|
||||||
|
"
|
||||||
|
id="price"
|
||||||
|
formControlName="price"
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="submit-button"
|
||||||
|
(click)="submit()"
|
||||||
|
[disabled]="!hotelForm.valid"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
😃 Submit
|
||||||
|
</button>
|
||||||
<a class="back-button" routerLink="/">😭 Cancel</a>
|
<a class="back-button" routerLink="/">😭 Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('HotelFormComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [HotelFormComponent]
|
imports: [HotelFormComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HotelFormComponent);
|
fixture = TestBed.createComponent(HotelFormComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -1,6 +1,12 @@
|
||||||
import { Component, Input } from '@angular/core';
|
import { Component, Input } from '@angular/core';
|
||||||
import { Hotel } from '../HotelItem/hotel';
|
import { Hotel } from '../HotelItem/hotel';
|
||||||
import { AbstractControl, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
Validators,
|
||||||
|
} from '@angular/forms';
|
||||||
import { NgFor, NgIf } from '@angular/common';
|
import { NgFor, NgIf } from '@angular/common';
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Router, RouterLink } from '@angular/router';
|
import { Router, RouterLink } from '@angular/router';
|
||||||
|
@ -10,43 +16,50 @@ import { Router, RouterLink } from '@angular/router';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [ReactiveFormsModule, NgIf, NgFor, RouterLink],
|
imports: [ReactiveFormsModule, NgIf, NgFor, RouterLink],
|
||||||
templateUrl: './hotel-form.component.html',
|
templateUrl: './hotel-form.component.html',
|
||||||
styleUrl: './hotel-form.component.css'
|
styleUrl: './hotel-form.component.css',
|
||||||
})
|
})
|
||||||
export class HotelFormComponent {
|
export class HotelFormComponent {
|
||||||
@Input() public hotel!: Hotel;
|
@Input() public hotel!: Hotel;
|
||||||
public hotelForm!: FormGroup
|
public hotelForm!: FormGroup;
|
||||||
public errorMsg: string = 'testing';
|
public errorMsg: string = 'testing';
|
||||||
errorMessages: Record<string, string> = {};
|
errorMessages: Record<string, string> = {};
|
||||||
|
|
||||||
constructor(public http: HttpClient, public router: Router) {
|
constructor(
|
||||||
|
public http: HttpClient,
|
||||||
}
|
public router: Router,
|
||||||
|
) {}
|
||||||
|
|
||||||
private validationErrorMessages: Record<string, string> = {
|
private validationErrorMessages: Record<string, string> = {
|
||||||
required: "This field is required",
|
required: 'This field is required',
|
||||||
minlength: "The value is too short",
|
minlength: 'The value is too short',
|
||||||
maxlength: "The value is too long",
|
maxlength: 'The value is too long',
|
||||||
pattern: "The value format is incorrect"
|
pattern: 'The value format is incorrect',
|
||||||
};
|
};
|
||||||
|
|
||||||
setMessage(value: AbstractControl): void {
|
setMessage(value: AbstractControl): void {
|
||||||
if ((value.touched || value.dirty) && value.errors) {
|
if ((value.touched || value.dirty) && value.errors) {
|
||||||
this.errorMsg = Object.keys(value.errors).map(key => {
|
this.errorMsg = Object.keys(value.errors)
|
||||||
|
.map((key) => {
|
||||||
console.log(this.validationErrorMessages[key]);
|
console.log(this.validationErrorMessages[key]);
|
||||||
return this.validationErrorMessages[key] || `Unknown error: ${key}`;
|
return this.validationErrorMessages[key] || `Unknown error: ${key}`;
|
||||||
}).join(' ');
|
})
|
||||||
|
.join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateErrorMessages(): void {
|
updateErrorMessages(): void {
|
||||||
this.errorMessages = {};
|
this.errorMessages = {};
|
||||||
|
|
||||||
Object.keys(this.hotelForm.controls).forEach(field => {
|
Object.keys(this.hotelForm.controls).forEach((field) => {
|
||||||
const control = this.hotelForm.get(field);
|
const control = this.hotelForm.get(field);
|
||||||
|
|
||||||
if (control && control.errors) {
|
if (control && control.errors) {
|
||||||
this.errorMessages[field] = Object.keys(control.errors)
|
this.errorMessages[field] = Object.keys(control.errors)
|
||||||
.map(errorKey => this.validationErrorMessages[errorKey] || `Unknown error: ${errorKey}`)
|
.map(
|
||||||
|
(errorKey) =>
|
||||||
|
this.validationErrorMessages[errorKey] ||
|
||||||
|
`Unknown error: ${errorKey}`,
|
||||||
|
)
|
||||||
.join(' ');
|
.join(' ');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -67,11 +80,11 @@ export class HotelFormComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
submit(): void {
|
submit(): void {
|
||||||
this.hotel.hotelName = this.hotelForm.get("name")?.value;
|
this.hotel.hotelName = this.hotelForm.get('name')?.value;
|
||||||
this.hotel.description = this.hotelForm.get("description")?.value;
|
this.hotel.description = this.hotelForm.get('description')?.value;
|
||||||
this.hotel.price = this.hotelForm.get("price")?.value;
|
this.hotel.price = this.hotelForm.get('price')?.value;
|
||||||
console.log(this.hotelForm.value);
|
console.log(this.hotelForm.value);
|
||||||
this.http.put("/api/hotels/" + this.hotel.id, this.hotel).subscribe();
|
this.http.put('/api/hotels/' + this.hotel.id, this.hotel).subscribe();
|
||||||
this.router.navigate(["/"]);
|
this.router.navigate(['/']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,13 @@
|
||||||
<div class="container p-4 mx-auto max-w-4xl">
|
<div class="container p-4 mx-auto max-w-4xl">
|
||||||
<h1>{{'hello' | uppercase | text}}</h1>
|
<h1>{{ "hello" | uppercase | text }}</h1>
|
||||||
<a class="submit-button" routerLink="/new">CREATE NEW HOTEL</a>
|
<a class="submit-button" routerLink="/new">CREATE NEW HOTEL</a>
|
||||||
<app-search [(input)]="search"></app-search>
|
<app-search [(input)]="search"></app-search>
|
||||||
@if (hotels[0].hotelName) {
|
@if (hotels[0].hotelName) {
|
||||||
<div *ngFor="let hotel of hotels">
|
<div *ngFor="let hotel of hotels">
|
||||||
<app-hotel-item *ngIf="hotel.hotelName.toLowerCase().includes(search.toLowerCase())" [hotel]="hotel"></app-hotel-item>
|
<app-hotel-item
|
||||||
|
*ngIf="hotel.hotelName.toLowerCase().includes(search.toLowerCase())"
|
||||||
|
[hotel]="hotel"
|
||||||
|
></app-hotel-item>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('HotelListComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [HotelListComponent]
|
imports: [HotelListComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(HotelListComponent);
|
fixture = TestBed.createComponent(HotelListComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -17,41 +17,50 @@ interface User {
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-hotel-list',
|
selector: 'app-hotel-list',
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [UpperCasePipe, TextPipe, SearchComponent, HotelItem, NgFor, NgIf, RouterLink],
|
imports: [
|
||||||
|
UpperCasePipe,
|
||||||
|
TextPipe,
|
||||||
|
SearchComponent,
|
||||||
|
HotelItem,
|
||||||
|
NgFor,
|
||||||
|
NgIf,
|
||||||
|
RouterLink,
|
||||||
|
],
|
||||||
templateUrl: './hotel-list.component.html',
|
templateUrl: './hotel-list.component.html',
|
||||||
styleUrl: './hotel-list.component.css'
|
styleUrl: './hotel-list.component.css',
|
||||||
})
|
})
|
||||||
export class HotelListComponent {
|
export class HotelListComponent {
|
||||||
public search: string = "";
|
public search: string = '';
|
||||||
public hotelService: HotelService = inject(HotelService);
|
public hotelService: HotelService = inject(HotelService);
|
||||||
public response: any = null;
|
public response: any = null;
|
||||||
public hotels: Array<Hotel> = [{} as Hotel];
|
public hotels: Array<Hotel> = [{} as Hotel];
|
||||||
|
|
||||||
constructor (private http: HttpClient) {
|
constructor(private http: HttpClient) {}
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.http.get<Array<Hotel>>("api/hotels").subscribe(res => {
|
this.http.get<Array<Hotel>>('api/hotels').subscribe((res) => {
|
||||||
this.hotels = res;
|
this.hotels = res;
|
||||||
});
|
});
|
||||||
|
|
||||||
const users = [
|
const users = [
|
||||||
{ name: "Max", age: 21 },
|
{ name: 'Max', age: 21 },
|
||||||
{ name: "Peter", age: 31 },
|
{ name: 'Peter', age: 31 },
|
||||||
{ name: "Hans", age: 13 },
|
{ name: 'Hans', age: 13 },
|
||||||
{ name: "Klaus", age: 51 },
|
{ name: 'Klaus', age: 51 },
|
||||||
{ name: "Dieter", age: 1 },
|
{ name: 'Dieter', age: 1 },
|
||||||
{ name: "Jan-Marlon", age: 3 },
|
{ name: 'Jan-Marlon', age: 3 },
|
||||||
]
|
];
|
||||||
|
|
||||||
const stream: Observable<User> = from(users);
|
const stream: Observable<User> = from(users);
|
||||||
|
|
||||||
stream.pipe(
|
stream
|
||||||
|
.pipe(
|
||||||
filter((user) => user.age > 18),
|
filter((user) => user.age > 18),
|
||||||
scan((acc, user) => acc + user.age, 0),
|
scan((acc, user) => acc + user.age, 0),
|
||||||
map((ageSum, index) => ageSum / (index + 1)),
|
map((ageSum, index) => ageSum / (index + 1)),
|
||||||
last(),
|
last(),
|
||||||
).subscribe(console.log);
|
)
|
||||||
|
.subscribe(console.log);
|
||||||
|
|
||||||
// const stream: Observable<number | string> = from([5, 1, 2, 12, 5, 14, 17, 5, "testing"]);
|
// const stream: Observable<number | string> = from([5, 1, 2, 12, 5, 14, 17, 5, "testing"]);
|
||||||
|
|
||||||
|
|
|
@ -1,59 +1,120 @@
|
||||||
<p>Create Hotel</p>
|
<p>Create Hotel</p>
|
||||||
|
|
||||||
<form [formGroup]="hotelForm">
|
<form [formGroup]="hotelForm">
|
||||||
<div class="text-red-500" *ngIf="errorMessages['form']">{{ errorMessages['form'] }}</div>
|
<div class="text-red-500 bg-white m-3" *ngIf="errorMessages['form']">
|
||||||
|
{{ errorMessages["form"] }}
|
||||||
|
</div>
|
||||||
|
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
<div class="text-red-500" *ngIf="errorMessages['name']">{{ errorMessages['name'] }}</div>
|
<div class="text-red-500" *ngIf="errorMessages['name']">
|
||||||
<input type="text" class="border-red-500"
|
{{ errorMessages["name"] }}
|
||||||
[class.border-8]='hotelForm.get("name")?.invalid && hotelForm.get("name")?.touched' id="name"
|
</div>
|
||||||
formControlName="name">
|
<input
|
||||||
|
type="text"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="
|
||||||
|
hotelForm.get('name')?.invalid && hotelForm.get('name')?.touched
|
||||||
|
"
|
||||||
|
id="name"
|
||||||
|
formControlName="name"
|
||||||
|
/>
|
||||||
<label for="description">Description</label>
|
<label for="description">Description</label>
|
||||||
<div class="text-red-500" *ngIf="errorMessages['description']">{{ errorMessages['description'] }}</div>
|
<div class="text-red-500" *ngIf="errorMessages['description']">
|
||||||
<input type="text" class="border-red-500"
|
{{ errorMessages["description"] }}
|
||||||
[class.border-8]='hotelForm.get("description")?.invalid && hotelForm.get("description")?.touched' id="description"
|
</div>
|
||||||
formControlName="description">
|
<input
|
||||||
|
type="text"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="
|
||||||
|
hotelForm.get('description')?.invalid &&
|
||||||
|
hotelForm.get('description')?.touched
|
||||||
|
"
|
||||||
|
id="description"
|
||||||
|
formControlName="description"
|
||||||
|
/>
|
||||||
<label for="imageUrl">Image</label>
|
<label for="imageUrl">Image</label>
|
||||||
<div class="text-red-500" *ngIf="errorMessages['imageUrl']">{{ errorMessages['imageUrl'] }}</div>
|
<div class="text-red-500" *ngIf="errorMessages['imageUrl']">
|
||||||
<input type="url" class="border-red-500"
|
{{ errorMessages["imageUrl"] }}
|
||||||
[class.border-8]='hotelForm.get("imageUel")?.invalid && hotelForm.get("imageUrl")?.touched' id="imageUrl"
|
</div>
|
||||||
formControlName="imageUrl">
|
<input
|
||||||
|
type="url"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="
|
||||||
|
hotelForm.get('imageUel')?.invalid && hotelForm.get('imageUrl')?.touched
|
||||||
|
"
|
||||||
|
id="imageUrl"
|
||||||
|
formControlName="imageUrl"
|
||||||
|
/>
|
||||||
<label for="price">Price</label>
|
<label for="price">Price</label>
|
||||||
<div class="text-red-500" *ngIf="errorMessages['price']">{{ errorMessages['price'] }}</div>
|
<div class="text-red-500" *ngIf="errorMessages['price']">
|
||||||
<input type="number" class="border-red-500" [class.border-8]='hotelForm.get("price")?.invalid' id="price"
|
{{ errorMessages["price"] }}
|
||||||
formControlName="price">
|
</div>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="hotelForm.get('price')?.invalid"
|
||||||
|
id="price"
|
||||||
|
formControlName="price"
|
||||||
|
/>
|
||||||
<label for="rating">Rating</label>
|
<label for="rating">Rating</label>
|
||||||
<div class="text-red-500" *ngIf="errorMessages['rating']">{{ errorMessages['rating'] }}</div>
|
<div class="text-red-500" *ngIf="errorMessages['rating']">
|
||||||
<input type="rating" class="border-red-500" [class.border-8]='hotelForm.get("rating")?.invalid' id="rating"
|
{{ errorMessages["rating"] }}
|
||||||
formControlName="rating">
|
</div>
|
||||||
|
<input
|
||||||
|
type="rating"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="hotelForm.get('rating')?.invalid"
|
||||||
|
id="rating"
|
||||||
|
formControlName="rating"
|
||||||
|
/>
|
||||||
<button class="submit-button" (click)="addTag()">Add Tag</button>
|
<button class="submit-button" (click)="addTag()">Add Tag</button>
|
||||||
@for (tag of getTags().controls; track tag) {
|
@for (tag of getTags().controls; track tag) {
|
||||||
<input type="tag" class="border-red-500" [class.border-8]='hotelForm.get("tag")?.invalid' id="tag"
|
<input
|
||||||
formControlName="tag">
|
type="tag"
|
||||||
|
class="border-red-500"
|
||||||
|
[class.border-8]="hotelForm.get('tag')?.invalid"
|
||||||
|
id="tag"
|
||||||
|
formControlName="tag"
|
||||||
|
/>
|
||||||
<button (click)="deleteTag(tag)" class="delete-button">delete</button>
|
<button (click)="deleteTag(tag)" class="delete-button">delete</button>
|
||||||
}
|
}
|
||||||
|
|
||||||
<input type="radio" value='None' formControlName="contactType">None
|
<input type="radio" value="None" formControlName="contactType" />None
|
||||||
<input type="radio" value='Email' formControlName="contactType">Email
|
<input type="radio" value="Email" formControlName="contactType" />Email
|
||||||
<input type="radio" value='SMS' formControlName="contactType">SMS
|
<input type="radio" value="SMS" formControlName="contactType" />SMS
|
||||||
|
|
||||||
@if (hotelForm.get("contactType")?.value == "Email") {
|
@if (hotelForm.get("contactType")?.value == "Email") {
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<label for="email">Email</label>
|
<label for="email">Email</label>
|
||||||
<input type="email" formControlName="email" id="email">
|
<input type="email" formControlName="email" id="email" />
|
||||||
<label for="emailConfirmation">Email Confirmation</label>
|
<label for="emailConfirmation">Email Confirmation</label>
|
||||||
<input type="email" formControlName="emailConfirmation" id="emailConfirmation">
|
<input
|
||||||
|
type="email"
|
||||||
|
formControlName="emailConfirmation"
|
||||||
|
id="emailConfirmation"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@if (hotelForm.get("contactType")?.value == "SMS") {
|
@if (hotelForm.get("contactType")?.value == "SMS") {
|
||||||
<div class="mt-3">
|
<div class="mt-3">
|
||||||
<label for="phone">Phone Number</label>
|
<label for="phone">Phone Number</label>
|
||||||
<input type="tel" formControlName="phone" id="phone">
|
<input type="tel" formControlName="phone" id="phone" />
|
||||||
<label for="phoneConfirmation">Phone Number Confirmation</label>
|
<label for="phoneConfirmation">Phone Number Confirmation</label>
|
||||||
<input type="tel" formControlName="phoneConfirmation" id="phoneConfirmation">
|
<input
|
||||||
|
type="tel"
|
||||||
|
formControlName="phoneConfirmation"
|
||||||
|
id="phoneConfirmation"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
<button class="submit-button" (click)="submit()" [disabled]="!hotelForm.valid" type="submit">Submit</button>
|
<button
|
||||||
|
class="submit-button"
|
||||||
|
(click)="submit()"
|
||||||
|
[disabled]="!hotelForm.valid"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
Submit
|
||||||
|
</button>
|
||||||
<a routerLink="/" class="delete-button">Cancel</a>
|
<a routerLink="/" class="delete-button">Cancel</a>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('NewHotelComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [NewHotelComponent]
|
imports: [NewHotelComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(NewHotelComponent);
|
fixture = TestBed.createComponent(NewHotelComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -1,6 +1,13 @@
|
||||||
import { HttpClient } from '@angular/common/http';
|
import { HttpClient } from '@angular/common/http';
|
||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
import { AbstractControl, FormArray, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
|
import {
|
||||||
|
AbstractControl,
|
||||||
|
FormArray,
|
||||||
|
FormControl,
|
||||||
|
FormGroup,
|
||||||
|
ReactiveFormsModule,
|
||||||
|
Validators,
|
||||||
|
} from '@angular/forms';
|
||||||
import { Router, RouterLink } from '@angular/router';
|
import { Router, RouterLink } from '@angular/router';
|
||||||
import { Hotel } from '../HotelItem/hotel';
|
import { Hotel } from '../HotelItem/hotel';
|
||||||
import { NgFor, NgIf } from '@angular/common';
|
import { NgFor, NgIf } from '@angular/common';
|
||||||
|
@ -11,41 +18,46 @@ import { CrossValidator } from '../crossValidator.service';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [ReactiveFormsModule, NgIf, NgFor, RouterLink],
|
imports: [ReactiveFormsModule, NgIf, NgFor, RouterLink],
|
||||||
templateUrl: './new-hotel.component.html',
|
templateUrl: './new-hotel.component.html',
|
||||||
styleUrl: './new-hotel.component.css'
|
styleUrl: './new-hotel.component.css',
|
||||||
})
|
})
|
||||||
export class NewHotelComponent {
|
export class NewHotelComponent {
|
||||||
public hotelForm!: FormGroup
|
public hotelForm!: FormGroup;
|
||||||
public hotel!: Hotel
|
public hotel!: Hotel;
|
||||||
errorMessages: Record<string, string> = {};
|
errorMessages: Record<string, string> = {};
|
||||||
|
|
||||||
private validationErrorMessages: Record<string, string> = {
|
private validationErrorMessages: Record<string, string> = {
|
||||||
required: "This field is required",
|
required: 'This field is required',
|
||||||
minlength: "The value is too short",
|
minlength: 'The value is too short',
|
||||||
maxlength: "The value is too long",
|
maxlength: 'The value is too long',
|
||||||
pattern: "The value format is incorrect"
|
pattern: 'The value format is incorrect',
|
||||||
};
|
};
|
||||||
|
|
||||||
private fullFormValidationErrorMessages: Record<string, string> = {
|
private fullFormValidationErrorMessages: Record<string, string> = {
|
||||||
mismatch: "The name and description have to be the same",
|
mismatch: 'The name and description have to be the same',
|
||||||
}
|
};
|
||||||
|
|
||||||
updateErrorMessages(): void {
|
updateErrorMessages(): void {
|
||||||
this.errorMessages = {};
|
this.errorMessages = {};
|
||||||
|
|
||||||
Object.keys(this.hotelForm.controls).forEach(field => {
|
Object.keys(this.hotelForm.controls).forEach((field) => {
|
||||||
const control = this.hotelForm.get(field);
|
const control = this.hotelForm.get(field);
|
||||||
|
|
||||||
if (control && control.errors && control.touched) {
|
if (control && control.errors && control.touched) {
|
||||||
this.errorMessages[field] = Object.keys(control.errors)
|
this.errorMessages[field] = Object.keys(control.errors)
|
||||||
.map(errorKey => this.validationErrorMessages[errorKey] || `Unknown error: ${errorKey}`)
|
.map(
|
||||||
|
(errorKey) =>
|
||||||
|
this.validationErrorMessages[errorKey] ||
|
||||||
|
`Unknown error: ${errorKey}`,
|
||||||
|
)
|
||||||
.join(' ');
|
.join(' ');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
if (this.hotelForm.errors) {
|
if (this.hotelForm.errors) {
|
||||||
Object.keys(this.hotelForm.errors).forEach(errorKey => {
|
Object.keys(this.hotelForm.errors).forEach((errorKey) => {
|
||||||
const errorMessage = this.fullFormValidationErrorMessages[errorKey] || `Unknown error: ${errorKey}`;
|
const errorMessage =
|
||||||
|
this.fullFormValidationErrorMessages[errorKey] ||
|
||||||
|
`Unknown error: ${errorKey}`;
|
||||||
this.errorMessages['form'] = errorMessage;
|
this.errorMessages['form'] = errorMessage;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -60,27 +72,29 @@ export class NewHotelComponent {
|
||||||
tags.push(new FormControl(tag, [Validators.required]));
|
tags.push(new FormControl(tag, [Validators.required]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.hotelForm = new FormGroup(
|
||||||
this.hotelForm = new FormGroup({
|
{
|
||||||
name: new FormControl("", Validators.required),
|
name: new FormControl('', Validators.required),
|
||||||
description: new FormControl("", Validators.required),
|
description: new FormControl('', Validators.required),
|
||||||
price: new FormControl(0, Validators.required),
|
price: new FormControl(0, Validators.required),
|
||||||
imageUrl: new FormControl("", Validators.required),
|
imageUrl: new FormControl('', Validators.required),
|
||||||
rating: new FormControl(0, Validators.required),
|
rating: new FormControl(0, Validators.required),
|
||||||
contactType: new FormControl('None'),
|
contactType: new FormControl('None'),
|
||||||
email: new FormControl(''),
|
email: new FormControl(''),
|
||||||
emailConfirmation: new FormControl(''),
|
emailConfirmation: new FormControl(''),
|
||||||
phone: new FormControl(''),
|
phone: new FormControl(''),
|
||||||
phoneConfirmation: new FormControl(''),
|
phoneConfirmation: new FormControl(''),
|
||||||
tags: new FormArray(tags)
|
tags: new FormArray(tags),
|
||||||
}, { validators: new CrossValidator().onlyAllowNameAndDescriptionSame() })
|
},
|
||||||
|
{ validators: new CrossValidator().crossValidate() },
|
||||||
|
);
|
||||||
|
|
||||||
this.hotelForm.valueChanges.subscribe(() => this.updateErrorMessages());
|
this.hotelForm.valueChanges.subscribe(() => this.updateErrorMessages());
|
||||||
this.hotelForm.valueChanges.subscribe(() => this.formUpdated());
|
this.hotelForm.valueChanges.subscribe(() => this.formUpdated());
|
||||||
}
|
}
|
||||||
|
|
||||||
formUpdated() {
|
formUpdated() {
|
||||||
console.log(this.hotelForm.get("contactType")?.value);
|
console.log(this.hotelForm.get('contactType')?.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
getTags() {
|
getTags() {
|
||||||
|
@ -91,27 +105,27 @@ export class NewHotelComponent {
|
||||||
this.getTags().removeAt(this.getTags().controls.indexOf(tagElement));
|
this.getTags().removeAt(this.getTags().controls.indexOf(tagElement));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
addTag() {
|
addTag() {
|
||||||
this.getTags().push(new FormControl('', [Validators.required]));
|
this.getTags().push(new FormControl('', [Validators.required]));
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(public http: HttpClient, public router: Router) {
|
constructor(
|
||||||
|
public http: HttpClient,
|
||||||
}
|
public router: Router,
|
||||||
|
) {}
|
||||||
|
|
||||||
submit(): void {
|
submit(): void {
|
||||||
console.log(this.hotelForm.value);
|
console.log(this.hotelForm.value);
|
||||||
const hotel: Hotel = {
|
const hotel: Hotel = {
|
||||||
id: 0,
|
id: 0,
|
||||||
hotelName: this.hotelForm.get("name")?.value,
|
hotelName: this.hotelForm.get('name')?.value,
|
||||||
description: this.hotelForm.get("description")?.value,
|
description: this.hotelForm.get('description')?.value,
|
||||||
price: this.hotelForm.get("price")?.value,
|
price: this.hotelForm.get('price')?.value,
|
||||||
imageUrl: this.hotelForm.get("imageUrl")?.value,
|
imageUrl: this.hotelForm.get('imageUrl')?.value,
|
||||||
rating: this.hotelForm.get("rating")?.value,
|
rating: this.hotelForm.get('rating')?.value,
|
||||||
tags: this.hotelForm.get("tags")?.value
|
tags: this.hotelForm.get('tags')?.value,
|
||||||
}
|
};
|
||||||
this.http.post("/api/hotels/", hotel).subscribe();
|
this.http.post('/api/hotels/', hotel).subscribe();
|
||||||
this.router.navigate(["/"]);
|
this.router.navigate(['/']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('StarRatingComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [StarRatingComponent]
|
imports: [StarRatingComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(StarRatingComponent);
|
fixture = TestBed.createComponent(StarRatingComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { Component, Input } from '@angular/core';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [NgClass, NgFor],
|
imports: [NgClass, NgFor],
|
||||||
templateUrl: './star-rating.component.html',
|
templateUrl: './star-rating.component.html',
|
||||||
styleUrl: './star-rating.component.css'
|
styleUrl: './star-rating.component.css',
|
||||||
})
|
})
|
||||||
export class StarRatingComponent {
|
export class StarRatingComponent {
|
||||||
@Input() public rating: number = 0;
|
@Input() public rating: number = 0;
|
||||||
|
|
|
@ -2,9 +2,14 @@
|
||||||
|
|
||||||
<form [formGroup]="loginForm">
|
<form [formGroup]="loginForm">
|
||||||
<label for="username">Username</label>
|
<label for="username">Username</label>
|
||||||
<input type="text" id="username" autocomplete="username" formControlName="username">
|
<input
|
||||||
|
type="text"
|
||||||
|
id="username"
|
||||||
|
autocomplete="username"
|
||||||
|
formControlName="username"
|
||||||
|
/>
|
||||||
<label for="password">Password</label>
|
<label for="password">Password</label>
|
||||||
<input type="password" id="password" formControlName="password">
|
<input type="password" id="password" formControlName="password" />
|
||||||
<button (click)="submit()" type="submit">Login</button>
|
<button (click)="submit()" type="submit">Login</button>
|
||||||
<button type="reset" (click)="reset()">Reset</button>
|
<button type="reset" (click)="reset()">Reset</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
@ -8,9 +8,8 @@ describe('TestComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
imports: [TestComponent]
|
imports: [TestComponent],
|
||||||
})
|
}).compileComponents();
|
||||||
.compileComponents();
|
|
||||||
|
|
||||||
fixture = TestBed.createComponent(TestComponent);
|
fixture = TestBed.createComponent(TestComponent);
|
||||||
component = fixture.componentInstance;
|
component = fixture.componentInstance;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import { FormControl, FormGroup, ReactiveFormsModule } from '@angular/forms';
|
||||||
standalone: true,
|
standalone: true,
|
||||||
imports: [ReactiveFormsModule],
|
imports: [ReactiveFormsModule],
|
||||||
templateUrl: './test.component.html',
|
templateUrl: './test.component.html',
|
||||||
styleUrl: './test.component.css'
|
styleUrl: './test.component.css',
|
||||||
})
|
})
|
||||||
export class TestComponent {
|
export class TestComponent {
|
||||||
public loginForm!: FormGroup;
|
public loginForm!: FormGroup;
|
||||||
|
@ -19,8 +19,8 @@ export class TestComponent {
|
||||||
|
|
||||||
setUpLoginForm(): FormGroup {
|
setUpLoginForm(): FormGroup {
|
||||||
return new FormGroup({
|
return new FormGroup({
|
||||||
username: new FormControl("Jan"),
|
username: new FormControl('Jan'),
|
||||||
password: new FormControl('')
|
password: new FormControl(''),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'jkcurrency',
|
name: 'jkcurrency',
|
||||||
standalone: true
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class CurrencyPipe implements PipeTransform {
|
export class CurrencyPipe implements PipeTransform {
|
||||||
transform(value: string): string {
|
transform(value: string): string {
|
||||||
return value.replaceAll("L", "P");
|
return value.replaceAll('L', 'P');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8" />
|
||||||
<title>HotelManager</title>
|
<title>HotelManager</title>
|
||||||
<base href="/">
|
<base href="/" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
<link rel="icon" type="image/x-icon" href="favicon.ico" />
|
||||||
<link rel="stylesheet" href="./styles.css">
|
<link rel="stylesheet" href="./styles.css" />
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-pink-600 p-32">
|
<body class="bg-pink-600 p-32">
|
||||||
<app-root></app-root>
|
<app-root></app-root>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -2,5 +2,6 @@ import { bootstrapApplication } from '@angular/platform-browser';
|
||||||
import { appConfig } from './app/app.config';
|
import { appConfig } from './app/app.config';
|
||||||
import { AppComponent } from './app/app.component';
|
import { AppComponent } from './app/app.component';
|
||||||
|
|
||||||
bootstrapApplication(AppComponent, appConfig)
|
bootstrapApplication(AppComponent, appConfig).catch((err) =>
|
||||||
.catch((err) => console.error(err));
|
console.error(err),
|
||||||
|
);
|
||||||
|
|
|
@ -8,17 +8,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-field {
|
.input-field {
|
||||||
@apply border-red-500 text-3xl rounded-full bg-gray-500 font-bold p-3 m-3 border-8
|
@apply border-red-500 text-3xl rounded-full bg-gray-500 font-bold p-3 m-3 border-8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-button {
|
.back-button {
|
||||||
@apply border-black rounded bg-blue-500 border-[30px] m-3 text-3xl font-bold p-3
|
@apply border-black rounded bg-blue-500 border-[30px] m-3 text-3xl font-bold p-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.submit-button {
|
.submit-button {
|
||||||
@apply border-black rounded-full bg-green-500 border-[30px] m-3 text-3xl font-bold p-3
|
@apply border-black rounded-full bg-green-500 border-[30px] m-3 text-3xl font-bold p-3;
|
||||||
}
|
}
|
||||||
|
|
||||||
.delete-button {
|
.delete-button {
|
||||||
@apply border-black rounded bg-red-500 border-[30px] m-3 text-3xl font-bold p-3
|
@apply border-black rounded bg-red-500 border-[30px] m-3 text-3xl font-bold p-3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {Pipe, PipeTransform} from '@angular/core';
|
import { Pipe, PipeTransform } from '@angular/core';
|
||||||
|
|
||||||
@Pipe({
|
@Pipe({
|
||||||
name: 'text',
|
name: 'text',
|
||||||
standalone: true
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class TextPipe implements PipeTransform {
|
export class TextPipe implements PipeTransform {
|
||||||
transform(value: string): string {
|
transform(value: string): string {
|
||||||
return value.replaceAll("L", "P");
|
return value.replaceAll('L', 'P');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,9 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
|
|
||||||
const colors = require('tailwindcss/colors');
|
const colors = require("tailwindcss/colors");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: [
|
content: ["./src/**/*.{html,ts}"],
|
||||||
"./src/**/*.{html,ts}",
|
|
||||||
],
|
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
colors: {
|
colors: {
|
||||||
|
@ -13,16 +11,15 @@ module.exports = {
|
||||||
},
|
},
|
||||||
keyframes: {
|
keyframes: {
|
||||||
shake: {
|
shake: {
|
||||||
'0%, 100%': { transform: 'translateX(0)' },
|
"0%, 100%": { transform: "translateX(0)" },
|
||||||
'25%': { transform: 'translateX(-30px)' },
|
"25%": { transform: "translateX(-30px)" },
|
||||||
'75%': { transform: 'translateX(30px)' },
|
"75%": { transform: "translateX(30px)" },
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
shake: 'shake 10s ease-in-out infinite',
|
shake: "shake 10s ease-in-out infinite",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,10 +6,6 @@
|
||||||
"outDir": "./out-tsc/app",
|
"outDir": "./out-tsc/app",
|
||||||
"types": []
|
"types": []
|
||||||
},
|
},
|
||||||
"files": [
|
"files": ["src/main.ts"],
|
||||||
"src/main.ts"
|
"include": ["src/**/*.d.ts"]
|
||||||
],
|
|
||||||
"include": [
|
|
||||||
"src/**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,10 +18,7 @@
|
||||||
"importHelpers": true,
|
"importHelpers": true,
|
||||||
"target": "ES2022",
|
"target": "ES2022",
|
||||||
"module": "ES2022",
|
"module": "ES2022",
|
||||||
"lib": [
|
"lib": ["ES2022", "dom"]
|
||||||
"ES2022",
|
|
||||||
"dom"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"angularCompilerOptions": {
|
"angularCompilerOptions": {
|
||||||
"enableI18nLegacyMessageIdFormat": false,
|
"enableI18nLegacyMessageIdFormat": false,
|
||||||
|
|
|
@ -4,12 +4,7 @@
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"outDir": "./out-tsc/spec",
|
"outDir": "./out-tsc/spec",
|
||||||
"types": [
|
"types": ["jasmine"]
|
||||||
"jasmine"
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src/**/*.spec.ts", "src/**/*.d.ts"]
|
||||||
"src/**/*.spec.ts",
|
|
||||||
"src/**/*.d.ts"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue