From c7f00de70befd09b5deba230c241827a83ecfe27 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 10:32:12 +0200 Subject: [PATCH 1/7] pipes jonathan --- itenium-socks/angular.json | 3 ++ .../src/app/home/latest-socks.component.html | 2 +- .../src/app/home/latest-socks.component.ts | 3 +- itenium-socks/src/app/price.pipe.spec.ts | 8 +++++ itenium-socks/src/app/price.pipe.ts | 17 ++++++++++ .../src/app/socks/sock-reviews.component.html | 2 +- .../src/app/socks/sock-reviews.component.ts | 3 +- itenium-socks/src/app/time-ago.pipe.spec.ts | 8 +++++ itenium-socks/src/app/time-ago.pipe.ts | 32 +++++++++++++++++++ 9 files changed, 74 insertions(+), 4 deletions(-) create mode 100644 itenium-socks/src/app/price.pipe.spec.ts create mode 100644 itenium-socks/src/app/price.pipe.ts create mode 100644 itenium-socks/src/app/time-ago.pipe.spec.ts create mode 100644 itenium-socks/src/app/time-ago.pipe.ts diff --git a/itenium-socks/angular.json b/itenium-socks/angular.json index e7cfa50..f61caf2 100644 --- a/itenium-socks/angular.json +++ b/itenium-socks/angular.json @@ -100,5 +100,8 @@ } } } + }, + "cli": { + "analytics": false } } diff --git a/itenium-socks/src/app/home/latest-socks.component.html b/itenium-socks/src/app/home/latest-socks.component.html index 9cd2eb7..d07e569 100644 --- a/itenium-socks/src/app/home/latest-socks.component.html +++ b/itenium-socks/src/app/home/latest-socks.component.html @@ -14,7 +14,7 @@

{{ sock.name }}
-
{{ sock.price }}
+
{{ sock.price | price }}
diff --git a/itenium-socks/src/app/home/latest-socks.component.ts b/itenium-socks/src/app/home/latest-socks.component.ts index 9b03950..b8be5e2 100644 --- a/itenium-socks/src/app/home/latest-socks.component.ts +++ b/itenium-socks/src/app/home/latest-socks.component.ts @@ -4,11 +4,12 @@ import { Observable } from 'rxjs'; import { Sock } from '../socks/sock.model'; import { AsyncPipe, NgFor } from '@angular/common'; import { RouterLink } from '@angular/router'; +import { PricePipe } from '../price.pipe'; @Component({ selector: 'app-latest-socks', standalone: true, - imports: [NgFor, AsyncPipe, RouterLink], + imports: [NgFor, AsyncPipe, RouterLink, PricePipe], templateUrl: './latest-socks.component.html' }) export class LatestSocksComponent implements OnInit { diff --git a/itenium-socks/src/app/price.pipe.spec.ts b/itenium-socks/src/app/price.pipe.spec.ts new file mode 100644 index 0000000..7275fcb --- /dev/null +++ b/itenium-socks/src/app/price.pipe.spec.ts @@ -0,0 +1,8 @@ +import { PricePipe } from './price.pipe'; + +describe('PricePipe', () => { + it('create an instance', () => { + const pipe = new PricePipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/itenium-socks/src/app/price.pipe.ts b/itenium-socks/src/app/price.pipe.ts new file mode 100644 index 0000000..43e56c4 --- /dev/null +++ b/itenium-socks/src/app/price.pipe.ts @@ -0,0 +1,17 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'price', + standalone: true +}) +export class PricePipe implements PipeTransform { + + transform(value: number): string { + if (value) { + return `€${value.toFixed(2)}`; + } else { + return '€0.00'; + } + } + +} diff --git a/itenium-socks/src/app/socks/sock-reviews.component.html b/itenium-socks/src/app/socks/sock-reviews.component.html index 696aab3..774dafd 100644 --- a/itenium-socks/src/app/socks/sock-reviews.component.html +++ b/itenium-socks/src/app/socks/sock-reviews.component.html @@ -17,7 +17,7 @@
{{ review.socksId }}
-
On {{ review.added }} by {{ review.email }}
+
On {{ review.added | timeAgo }} by {{ review.email }}
diff --git a/itenium-socks/src/app/socks/sock-reviews.component.ts b/itenium-socks/src/app/socks/sock-reviews.component.ts index fe89cb9..63722ca 100644 --- a/itenium-socks/src/app/socks/sock-reviews.component.ts +++ b/itenium-socks/src/app/socks/sock-reviews.component.ts @@ -3,11 +3,12 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { SocksService } from './socks.service'; import { Review } from './sock.model'; +import { TimeAgoPipe } from '../time-ago.pipe'; @Component({ selector: 'app-sock-reviews', standalone: true, - imports: [NgFor, AsyncPipe], + imports: [NgFor, AsyncPipe, TimeAgoPipe], templateUrl: './sock-reviews.component.html' }) export class SockReviewsComponent { diff --git a/itenium-socks/src/app/time-ago.pipe.spec.ts b/itenium-socks/src/app/time-ago.pipe.spec.ts new file mode 100644 index 0000000..c3d7df2 --- /dev/null +++ b/itenium-socks/src/app/time-ago.pipe.spec.ts @@ -0,0 +1,8 @@ +import { TimeAgoPipe } from './time-ago.pipe'; + +describe('TimeAgoPipe', () => { + it('create an instance', () => { + const pipe = new TimeAgoPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/itenium-socks/src/app/time-ago.pipe.ts b/itenium-socks/src/app/time-ago.pipe.ts new file mode 100644 index 0000000..5379b56 --- /dev/null +++ b/itenium-socks/src/app/time-ago.pipe.ts @@ -0,0 +1,32 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'timeAgo', + standalone: true +}) +export class TimeAgoPipe implements PipeTransform { + + transform(value: any): string { + if (!value) return 'N/A'; + + const time = new Date(value).getTime(); + const now = new Date().getTime(); + const difference = Math.floor((now - time) / 1000); + + if (difference < 30) { + return 'Just now'; + } else if (difference < 60) { + return 'A few seconds ago'; + } else if (difference < 3600) { + const minutes = Math.floor(difference / 60); + return `${minutes} minute${minutes > 1 ? 's' : ''} ago`; + } else if (difference < 86400) { + const hours = Math.floor(difference / 3600); + return `${hours} hour${hours > 1 ? 's' : ''} ago`; + } else { + const days = Math.floor(difference / 86400); + return `${days} day${days > 1 ? 's' : ''} ago`; + } + } + +} From fd17ac6c91afd4d8ae2ddf597330baafc5168558 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 11:09:04 +0200 Subject: [PATCH 2/7] ngfor - Jonathan --- .../src/app/home/latest-socks.component.html | 34 ++++++++++--------- .../src/app/home/latest-socks.component.ts | 2 +- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/itenium-socks/src/app/home/latest-socks.component.html b/itenium-socks/src/app/home/latest-socks.component.html index d07e569..c04b03e 100644 --- a/itenium-socks/src/app/home/latest-socks.component.html +++ b/itenium-socks/src/app/home/latest-socks.component.html @@ -6,23 +6,25 @@

View All Socks diff --git a/itenium-socks/src/app/home/latest-socks.component.ts b/itenium-socks/src/app/home/latest-socks.component.ts index b8be5e2..7906134 100644 --- a/itenium-socks/src/app/home/latest-socks.component.ts +++ b/itenium-socks/src/app/home/latest-socks.component.ts @@ -9,7 +9,7 @@ import { PricePipe } from '../price.pipe'; @Component({ selector: 'app-latest-socks', standalone: true, - imports: [NgFor, AsyncPipe, RouterLink, PricePipe], + imports: [AsyncPipe, RouterLink, PricePipe], templateUrl: './latest-socks.component.html' }) export class LatestSocksComponent implements OnInit { From d3711d88df081e60a72859648d4d1ea36dfb08c2 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 11:22:24 +0200 Subject: [PATCH 3/7] fix --- itenium-socks/src/app/price.pipe.spec.ts | 7 ------- itenium-socks/src/app/time-ago.pipe.spec.ts | 6 ------ itenium-socks/src/app/time-ago.pipe.ts | 2 +- 3 files changed, 1 insertion(+), 14 deletions(-) diff --git a/itenium-socks/src/app/price.pipe.spec.ts b/itenium-socks/src/app/price.pipe.spec.ts index 7275fcb..8cff650 100644 --- a/itenium-socks/src/app/price.pipe.spec.ts +++ b/itenium-socks/src/app/price.pipe.spec.ts @@ -1,8 +1 @@ import { PricePipe } from './price.pipe'; - -describe('PricePipe', () => { - it('create an instance', () => { - const pipe = new PricePipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/itenium-socks/src/app/time-ago.pipe.spec.ts b/itenium-socks/src/app/time-ago.pipe.spec.ts index c3d7df2..0f05974 100644 --- a/itenium-socks/src/app/time-ago.pipe.spec.ts +++ b/itenium-socks/src/app/time-ago.pipe.spec.ts @@ -1,8 +1,2 @@ import { TimeAgoPipe } from './time-ago.pipe'; -describe('TimeAgoPipe', () => { - it('create an instance', () => { - const pipe = new TimeAgoPipe(); - expect(pipe).toBeTruthy(); - }); -}); diff --git a/itenium-socks/src/app/time-ago.pipe.ts b/itenium-socks/src/app/time-ago.pipe.ts index 5379b56..1d1e3b9 100644 --- a/itenium-socks/src/app/time-ago.pipe.ts +++ b/itenium-socks/src/app/time-ago.pipe.ts @@ -6,7 +6,7 @@ import { Pipe, PipeTransform } from '@angular/core'; }) export class TimeAgoPipe implements PipeTransform { - transform(value: any): string { + transform(value: number | Date | string): string { if (!value) return 'N/A'; const time = new Date(value).getTime(); From 590b1066005a55ef7d5f6ffdc6220be59b457da6 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 11:27:51 +0200 Subject: [PATCH 4/7] fix whitespace --- itenium-socks/src/app/home/latest-socks.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itenium-socks/src/app/home/latest-socks.component.html b/itenium-socks/src/app/home/latest-socks.component.html index c04b03e..6362409 100644 --- a/itenium-socks/src/app/home/latest-socks.component.html +++ b/itenium-socks/src/app/home/latest-socks.component.html @@ -24,7 +24,7 @@
{{ sock.price | price }}
} - +
View All Socks From 4dd8a00711e9bf2e491204ac7da56fb8dfb56635 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 11:29:24 +0200 Subject: [PATCH 5/7] fix again --- itenium-socks/src/app/price.pipe.spec.ts | 1 - itenium-socks/src/app/time-ago.pipe.spec.ts | 2 -- 2 files changed, 3 deletions(-) delete mode 100644 itenium-socks/src/app/price.pipe.spec.ts delete mode 100644 itenium-socks/src/app/time-ago.pipe.spec.ts diff --git a/itenium-socks/src/app/price.pipe.spec.ts b/itenium-socks/src/app/price.pipe.spec.ts deleted file mode 100644 index 8cff650..0000000 --- a/itenium-socks/src/app/price.pipe.spec.ts +++ /dev/null @@ -1 +0,0 @@ -import { PricePipe } from './price.pipe'; diff --git a/itenium-socks/src/app/time-ago.pipe.spec.ts b/itenium-socks/src/app/time-ago.pipe.spec.ts deleted file mode 100644 index 0f05974..0000000 --- a/itenium-socks/src/app/time-ago.pipe.spec.ts +++ /dev/null @@ -1,2 +0,0 @@ -import { TimeAgoPipe } from './time-ago.pipe'; - From 91bbc9212b412dacfcaba42386aa7ddcf65ee8ee Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 11:38:07 +0200 Subject: [PATCH 6/7] remove ngfor --- itenium-socks/src/app/home/latest-socks.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/itenium-socks/src/app/home/latest-socks.component.ts b/itenium-socks/src/app/home/latest-socks.component.ts index 7906134..f817894 100644 --- a/itenium-socks/src/app/home/latest-socks.component.ts +++ b/itenium-socks/src/app/home/latest-socks.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core'; import { SocksService } from '../socks/socks.service'; import { Observable } from 'rxjs'; import { Sock } from '../socks/sock.model'; -import { AsyncPipe, NgFor } from '@angular/common'; +import { AsyncPipe } from '@angular/common'; import { RouterLink } from '@angular/router'; import { PricePipe } from '../price.pipe'; From 0619dfcb3ecf83bffcb982b34260519a980af6d2 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 13:44:37 +0200 Subject: [PATCH 7/7] exercise 4 - Templates - Socks Shop --- itenium-socks/package-lock.json | 13 ++++ itenium-socks/package.json | 1 + .../src/app/socks/shop.component.html | 25 +++++++- itenium-socks/src/app/socks/shop.component.ts | 61 ++++++++++++++++++- 4 files changed, 96 insertions(+), 4 deletions(-) diff --git a/itenium-socks/package-lock.json b/itenium-socks/package-lock.json index 295c374..a0436b2 100644 --- a/itenium-socks/package-lock.json +++ b/itenium-socks/package-lock.json @@ -18,6 +18,7 @@ "@angular/router": "^18.0.0", "@fortawesome/angular-fontawesome": "^0.15.0", "@fortawesome/fontawesome-free": "^6.5.2", + "ngx-pagination": "^6.0.3", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" @@ -9054,6 +9055,18 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/ngx-pagination": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ngx-pagination/-/ngx-pagination-6.0.3.tgz", + "integrity": "sha512-lONjTQ7hFPh1SyhwDrRd5ZwM4NMGQ7bNR6vLrs6mrU0Z8Q1zCcWbf/pvyp4DOlGyd9uyZxRy2wUsSZLeIPjbAw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=13.0.0", + "@angular/core": ">=13.0.0" + } + }, "node_modules/nice-napi": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", diff --git a/itenium-socks/package.json b/itenium-socks/package.json index 6b3a9d6..9da08d2 100644 --- a/itenium-socks/package.json +++ b/itenium-socks/package.json @@ -20,6 +20,7 @@ "@angular/router": "^18.0.0", "@fortawesome/angular-fontawesome": "^0.15.0", "@fortawesome/fontawesome-free": "^6.5.2", + "ngx-pagination": "^6.0.3", "rxjs": "~7.8.0", "tslib": "^2.3.0", "zone.js": "~0.14.3" diff --git a/itenium-socks/src/app/socks/shop.component.html b/itenium-socks/src/app/socks/shop.component.html index a0139e2..d7cab49 100644 --- a/itenium-socks/src/app/socks/shop.component.html +++ b/itenium-socks/src/app/socks/shop.component.html @@ -5,8 +5,25 @@

Our Socks

+
+ + + +
-
+ +
+ + +
diff --git a/itenium-socks/src/app/socks/shop.component.ts b/itenium-socks/src/app/socks/shop.component.ts index 33c897b..134d9a6 100644 --- a/itenium-socks/src/app/socks/shop.component.ts +++ b/itenium-socks/src/app/socks/shop.component.ts @@ -1,21 +1,78 @@ import { Component } from '@angular/core'; import { SocksService } from './socks.service'; -import { Observable } from 'rxjs'; +import { Observable,BehaviorSubject, combineLatest } from 'rxjs'; import { Sock } from './sock.model'; import { AsyncPipe, NgFor } from '@angular/common'; +import { NgxPaginationModule } from 'ngx-pagination'; +import { map } from 'rxjs/operators'; +import { PricePipe } from '../price.pipe'; @Component({ selector: 'app-shop', standalone: true, - imports: [NgFor, AsyncPipe], + imports: [NgFor, AsyncPipe, NgxPaginationModule, PricePipe], templateUrl: './shop.component.html' }) export class ShopComponent { socks$!: Observable; + filteredSocks$!: Observable; + + public nameFilterSubject = new BehaviorSubject(''); + public colorFilterSubject = new BehaviorSubject(''); + public sortBySubject = new BehaviorSubject('name'); + public currentPageSubject = new BehaviorSubject(1); + public pageSize = 10; constructor(private socksService: SocksService) {} ngOnInit(): void { this.socks$ = this.socksService.get(); + + this.filteredSocks$ = combineLatest([ + this.socks$, + this.nameFilterSubject.asObservable(), + this.colorFilterSubject.asObservable(), + this.sortBySubject.asObservable(), + this.currentPageSubject.asObservable() + ]).pipe( + map(([socks, nameFilter, colorFilter, sortBy, currentPage]) => { + let filtered = socks.filter(sock => + sock.name.toLowerCase().includes(nameFilter.toLowerCase()) && + sock.variant.toLowerCase().includes(colorFilter.toLowerCase()) + ); + + filtered = filtered.sort((a, b) => { + if (sortBy === 'name') { + return a.name.localeCompare(b.name); + } else if (sortBy === 'price') { + return a.price - b.price; + } + return 0; + }); + + const startIndex = (currentPage - 1) * this.pageSize; + return filtered.slice(startIndex, startIndex + this.pageSize); + }) + ); } + + onFilterName(event: Event) { + const name = (event.target as HTMLInputElement).value; + this.nameFilterSubject.next(name); + } + + onFilterColor(event: Event) { + const color = (event.target as HTMLInputElement).value; + this.colorFilterSubject.next(color); + } + + onSortBy(event: Event) { + const sortBy = (event.target as HTMLInputElement).value; + this.sortBySubject.next(sortBy); + } + + onPageChange(page: number) { + this.currentPageSubject.next(page); + } + }