From c7f00de70befd09b5deba230c241827a83ecfe27 Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 10:32:12 +0200 Subject: [PATCH 01/12] 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 02/12] 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 03/12] 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 04/12] 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 05/12] 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 06/12] 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 07/12] 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); + } + } From f4b77429b3f534e205f89fb7c94455fad3dc5c1a Mon Sep 17 00:00:00 2001 From: jonathanrasquin Date: Fri, 31 May 2024 14:10:43 +0200 Subject: [PATCH 08/12] exercise 5 - Templates - No image --- itenium-socks/public/images/placeholder.jpg | Bin 0 -> 109242 bytes .../src/app/socks/shop.component.html | 2 +- itenium-socks/src/app/socks/shop.component.ts | 5 +++++ 3 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 itenium-socks/public/images/placeholder.jpg diff --git a/itenium-socks/public/images/placeholder.jpg b/itenium-socks/public/images/placeholder.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9064588b366e74d52b2282d4ad0440aabbf3aed3 GIT binary patch literal 109242 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
+ +

Enter Bank Details

+

Free shipping and return policy!

+ + +
+ + + +
diff --git a/itenium-socks/src/app/socks/sock.component.scss b/itenium-socks/src/app/socks/sock.component.scss new file mode 100644 index 0000000..2755bbc --- /dev/null +++ b/itenium-socks/src/app/socks/sock.component.scss @@ -0,0 +1,32 @@ +.badge { + display: inline-block; + padding: 0.25em 0.4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: 0.25rem; + background-color: red; + color: white; +} + +.alert { + position: fixed; + top: 20px; + left: 10%; + transform: translateX(-50%); + padding: 10px; + background-color: #28a745; /* Success background color */ + color: white; + border-radius: 5px; +} + +.alert.success { + background-color: #28a745; +} + +.alert.failure { + background-color: #dc3545; +} diff --git a/itenium-socks/src/app/socks/sock.component.ts b/itenium-socks/src/app/socks/sock.component.ts index 1618e41..0410cb2 100644 --- a/itenium-socks/src/app/socks/sock.component.ts +++ b/itenium-socks/src/app/socks/sock.component.ts @@ -2,16 +2,23 @@ import { Component } from '@angular/core'; import { Observable } from 'rxjs'; import { Sock } from './sock.model'; import { SocksService } from './socks.service'; -import { AsyncPipe, NgIf, TitleCasePipe } from '@angular/common'; +import { AsyncPipe, NgIf, TitleCasePipe, CommonModule } from '@angular/common'; +import { ModalComponent } from '../modal/modal.component'; + @Component({ selector: 'app-sock', standalone: true, - imports: [NgIf, AsyncPipe, TitleCasePipe], - templateUrl: './sock.component.html' + imports: [NgIf, AsyncPipe, TitleCasePipe, ModalComponent, CommonModule], + templateUrl: './sock.component.html', + styleUrls: ['./sock.component.scss'] }) export class SockComponent { sock$!: Observable; + showModal = false; + showAlert = false; + alertMessage = ''; + alertType = ''; constructor(private socksService: SocksService) {} @@ -22,8 +29,26 @@ export class SockComponent { } buy(): void { + this.showModal = true; + + } + + onCloseModal() { + this.showModal = false; + } + + onConfirmPurchase() { const sockId = +window.location.pathname.split('/')[2]; this.socksService.buySocks(sockId).subscribe(); + this.showModal = false; + this.showAlertMessage('Purchase successful!', 'success'); + } + + showAlertMessage(message: string, type: string) { + this.alertMessage = message; + this.alertType = type; + this.showAlert = true; + setTimeout(() => this.showAlert = false, 3000); } addReview(): void {