From 0641a268b8cb3b7fcb8bedaff7f393f04d6e4923 Mon Sep 17 00:00:00 2001 From: constantin Date: Wed, 6 Nov 2024 14:49:13 +0100 Subject: [PATCH] ez claps 01-04 --- .vscode/extensions.json | 4 - .vscode/launch.json | 20 -- .vscode/tasks.json | 42 --- angular.json | 3 +- package-lock.json | 276 +++++------------- src/app/app.config.ts | 7 +- src/app/app.routes.ts | 8 +- .../product-list/product-list.component.html | 1 - .../product-list/product-list.component.ts | 17 -- .../cart/cart.component.css} | 0 src/app/product/cart/cart.component.html | 25 ++ src/app/product/cart/cart.component.spec.ts | 23 ++ src/app/product/cart/cart.component.ts | 44 +++ .../product-alerts.component.css | 0 .../product-alerts.component.html | 3 + .../product-alerts.component.spec.ts | 23 ++ .../product-alerts.component.ts | 18 ++ .../product-detail.component.css | 0 .../product-detail.component.html | 6 + .../product-detail.component.spec.ts | 23 ++ .../product-detail.component.ts | 39 +++ .../product-list/product-list.component.css | 0 .../product-list/product-list.component.html | 17 ++ .../product-list.component.spec.ts | 0 .../product-list/product-list.component.ts | 32 ++ src/app/{ => product}/products.ts | 2 +- src/app/product/service/cart.service.spec.ts | 16 + src/app/product/service/cart.service.ts | 33 +++ src/app/product/shipping.ts | 4 + .../product/shipping/shipping.component.css | 0 .../product/shipping/shipping.component.html | 5 + .../shipping/shipping.component.spec.ts | 23 ++ .../product/shipping/shipping.component.ts | 28 ++ src/app/top-bar/top-bar.component.html | 3 +- 34 files changed, 450 insertions(+), 295 deletions(-) delete mode 100644 .vscode/extensions.json delete mode 100644 .vscode/launch.json delete mode 100644 .vscode/tasks.json delete mode 100644 src/app/product-list/product-list.component.html delete mode 100644 src/app/product-list/product-list.component.ts rename src/app/{product-list/product-list.component.css => product/cart/cart.component.css} (100%) create mode 100644 src/app/product/cart/cart.component.html create mode 100644 src/app/product/cart/cart.component.spec.ts create mode 100644 src/app/product/cart/cart.component.ts create mode 100644 src/app/product/product-alerts/product-alerts.component.css create mode 100644 src/app/product/product-alerts/product-alerts.component.html create mode 100644 src/app/product/product-alerts/product-alerts.component.spec.ts create mode 100644 src/app/product/product-alerts/product-alerts.component.ts create mode 100644 src/app/product/product-detail/product-detail.component.css create mode 100644 src/app/product/product-detail/product-detail.component.html create mode 100644 src/app/product/product-detail/product-detail.component.spec.ts create mode 100644 src/app/product/product-detail/product-detail.component.ts create mode 100644 src/app/product/product-list/product-list.component.css create mode 100644 src/app/product/product-list/product-list.component.html rename src/app/{ => product}/product-list/product-list.component.spec.ts (100%) create mode 100644 src/app/product/product-list/product-list.component.ts rename src/app/{ => product}/products.ts (92%) create mode 100644 src/app/product/service/cart.service.spec.ts create mode 100644 src/app/product/service/cart.service.ts create mode 100644 src/app/product/shipping.ts create mode 100644 src/app/product/shipping/shipping.component.css create mode 100644 src/app/product/shipping/shipping.component.html create mode 100644 src/app/product/shipping/shipping.component.spec.ts create mode 100644 src/app/product/shipping/shipping.component.ts diff --git a/.vscode/extensions.json b/.vscode/extensions.json deleted file mode 100644 index 77b3745..0000000 --- a/.vscode/extensions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 - "recommendations": ["angular.ng-template"] -} diff --git a/.vscode/launch.json b/.vscode/launch.json deleted file mode 100644 index 925af83..0000000 --- a/.vscode/launch.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "ng serve", - "type": "chrome", - "request": "launch", - "preLaunchTask": "npm: start", - "url": "http://localhost:4200/" - }, - { - "name": "ng test", - "type": "chrome", - "request": "launch", - "preLaunchTask": "npm: test", - "url": "http://localhost:9876/debug.html" - } - ] -} diff --git a/.vscode/tasks.json b/.vscode/tasks.json deleted file mode 100644 index a298b5b..0000000 --- a/.vscode/tasks.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "start", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "(.*?)" - }, - "endsPattern": { - "regexp": "bundle generation complete" - } - } - } - }, - { - "type": "npm", - "script": "test", - "isBackground": true, - "problemMatcher": { - "owner": "typescript", - "pattern": "$tsc", - "background": { - "activeOnStart": true, - "beginsPattern": { - "regexp": "(.*?)" - }, - "endsPattern": { - "regexp": "bundle generation complete" - } - } - } - } - ] -} diff --git a/angular.json b/angular.json index 1b3899b..61ca8e6 100644 --- a/angular.json +++ b/angular.json @@ -24,7 +24,8 @@ { "glob": "**/*", "input": "public" - } + }, + "src/assets" ], "styles": [ "src/styles.css" diff --git a/package-lock.json b/package-lock.json index c60992e..76453ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -450,6 +450,34 @@ "typescript": ">=5.4 <5.6" } }, + "node_modules/@angular/compiler-cli/node_modules/chokidar": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", + "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "dev": true, + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@angular/compiler-cli/node_modules/readdirp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", + "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "dev": true, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/core": { "version": "18.2.8", "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.2.8.tgz", @@ -5531,19 +5559,39 @@ "license": "MIT" }, "node_modules/chokidar": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", - "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, - "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" }, "engines": { - "node": ">= 14.16.0" + "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/chownr": { @@ -8773,31 +8821,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/karma/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", @@ -8837,19 +8860,6 @@ "dev": true, "license": "MIT" }, - "node_modules/karma/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/karma/node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -8860,32 +8870,6 @@ "node": ">=8" } }, - "node_modules/karma/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/karma/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -11410,17 +11394,27 @@ } }, "node_modules/readdirp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", - "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, - "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, "engines": { - "node": ">= 14.16.0" + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/reflect-metadata": { @@ -11853,70 +11847,6 @@ } } }, - "node_modules/sass/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/sass/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/sass/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/sass/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/sax": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.4.1.tgz", @@ -14102,31 +14032,6 @@ "balanced-match": "^1.0.0" } }, - "node_modules/webpack-dev-server/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "10.4.5", "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", @@ -14148,19 +14053,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/webpack-dev-server/node_modules/http-proxy-middleware": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", @@ -14202,32 +14094,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/webpack-dev-server/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "5.0.10", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", diff --git a/src/app/app.config.ts b/src/app/app.config.ts index c778438..2ad4fc7 100644 --- a/src/app/app.config.ts +++ b/src/app/app.config.ts @@ -1,7 +1,12 @@ import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core'; import { provideRouter } from '@angular/router'; import { routes } from './app.routes'; +import {provideHttpClient} from '@angular/common/http'; export const appConfig: ApplicationConfig = { - providers: [provideZoneChangeDetection({ eventCoalescing: true }), provideRouter(routes)] + providers: [ + provideZoneChangeDetection({ eventCoalescing: true }), + provideRouter(routes), + provideHttpClient(), + ] }; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 6aeb858..a04a62c 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,6 +1,12 @@ import { Routes } from '@angular/router'; -import {ProductListComponent} from './product-list/product-list.component'; +import {ProductListComponent} from './product/product-list/product-list.component'; +import {ProductDetailComponent} from './product/product-detail/product-detail.component'; +import {CartComponent} from './product/cart/cart.component'; +import {ShippingComponent} from './product/shipping/shipping.component'; export const routes: Routes = [ { path: '', component: ProductListComponent }, + { path: 'products/:productId', component: ProductDetailComponent }, + { path: 'cart', component: CartComponent }, + { path: 'shipping', component: ShippingComponent }, ]; diff --git a/src/app/product-list/product-list.component.html b/src/app/product-list/product-list.component.html deleted file mode 100644 index 1007667..0000000 --- a/src/app/product-list/product-list.component.html +++ /dev/null @@ -1 +0,0 @@ -

Products

diff --git a/src/app/product-list/product-list.component.ts b/src/app/product-list/product-list.component.ts deleted file mode 100644 index 5bfe608..0000000 --- a/src/app/product-list/product-list.component.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Component } from '@angular/core'; -import { products } from '../products'; - -@Component({ - selector: 'app-product-list', - standalone: true, - imports: [], - templateUrl: './product-list.component.html', - styleUrl: './product-list.component.css' -}) -export class ProductListComponent { - products = [...products]; - - share() { - window.alert('The product has been shared!'); - } -} diff --git a/src/app/product-list/product-list.component.css b/src/app/product/cart/cart.component.css similarity index 100% rename from src/app/product-list/product-list.component.css rename to src/app/product/cart/cart.component.css diff --git a/src/app/product/cart/cart.component.html b/src/app/product/cart/cart.component.html new file mode 100644 index 0000000..f9a5437 --- /dev/null +++ b/src/app/product/cart/cart.component.html @@ -0,0 +1,25 @@ +Shipping Prices + + +

{{ product.name }}

+

{{ product.price | currency }}

+
+
+ +
+
+ + + +
+
+ + + +
+ +
diff --git a/src/app/product/cart/cart.component.spec.ts b/src/app/product/cart/cart.component.spec.ts new file mode 100644 index 0000000..03dcc4a --- /dev/null +++ b/src/app/product/cart/cart.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { CartComponent } from './cart.component'; + +describe('CartComponent', () => { + let component: CartComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [CartComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(CartComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product/cart/cart.component.ts b/src/app/product/cart/cart.component.ts new file mode 100644 index 0000000..d4c1619 --- /dev/null +++ b/src/app/product/cart/cart.component.ts @@ -0,0 +1,44 @@ +import {Component, OnInit} from '@angular/core'; +import {CartService} from '../service/cart.service'; +import {CurrencyPipe, NgForOf} from '@angular/common'; +import {Product} from '../products'; +import {RouterLink} from '@angular/router'; +import {FormBuilder, FormGroup, ReactiveFormsModule} from '@angular/forms'; + +@Component({ + selector: 'app-cart', + standalone: true, + imports: [ + NgForOf, + CurrencyPipe, + RouterLink, + ReactiveFormsModule + ], + templateUrl: './cart.component.html', + styleUrl: './cart.component.css' +}) +export class CartComponent implements OnInit { + protected _items: Product[] = []; + + protected checkoutForm!: FormGroup; + + constructor( + private _cartService: CartService, + private _formBuilder: FormBuilder + ) { + } + + ngOnInit(): void { + this._items = this._cartService.items; + this.checkoutForm = this._formBuilder.group({ + name: '', + address: '' + }); + } + + onSubmit(): void { + this._items = this._cartService.clearCart(); + console.warn('Your order has been submitted', this.checkoutForm.value); + this.checkoutForm.reset(); + } +} diff --git a/src/app/product/product-alerts/product-alerts.component.css b/src/app/product/product-alerts/product-alerts.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product/product-alerts/product-alerts.component.html b/src/app/product/product-alerts/product-alerts.component.html new file mode 100644 index 0000000..451ca13 --- /dev/null +++ b/src/app/product/product-alerts/product-alerts.component.html @@ -0,0 +1,3 @@ +

+ +

diff --git a/src/app/product/product-alerts/product-alerts.component.spec.ts b/src/app/product/product-alerts/product-alerts.component.spec.ts new file mode 100644 index 0000000..6709df8 --- /dev/null +++ b/src/app/product/product-alerts/product-alerts.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProductAlertsComponent } from './product-alerts.component'; + +describe('ProductAlertsComponent', () => { + let component: ProductAlertsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ProductAlertsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProductAlertsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product/product-alerts/product-alerts.component.ts b/src/app/product/product-alerts/product-alerts.component.ts new file mode 100644 index 0000000..a262397 --- /dev/null +++ b/src/app/product/product-alerts/product-alerts.component.ts @@ -0,0 +1,18 @@ +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {Product} from '../products'; +import {NgIf} from '@angular/common'; + +@Component({ + selector: 'app-product-alerts', + standalone: true, + imports: [ + NgIf + ], + templateUrl: './product-alerts.component.html', + styleUrl: './product-alerts.component.css' +}) +export class ProductAlertsComponent { + @Input() product: Product | undefined; + + @Output() notify: EventEmitter = new EventEmitter(); +} diff --git a/src/app/product/product-detail/product-detail.component.css b/src/app/product/product-detail/product-detail.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product/product-detail/product-detail.component.html b/src/app/product/product-detail/product-detail.component.html new file mode 100644 index 0000000..3f1a746 --- /dev/null +++ b/src/app/product/product-detail/product-detail.component.html @@ -0,0 +1,6 @@ + +

{{_product.name}}

+

{{_product.description}}

+

Price: {{_product.price | currency }}

+ +
diff --git a/src/app/product/product-detail/product-detail.component.spec.ts b/src/app/product/product-detail/product-detail.component.spec.ts new file mode 100644 index 0000000..7283be7 --- /dev/null +++ b/src/app/product/product-detail/product-detail.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ProductDetailComponent } from './product-detail.component'; + +describe('ProductDetailComponent', () => { + let component: ProductDetailComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ProductDetailComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ProductDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product/product-detail/product-detail.component.ts b/src/app/product/product-detail/product-detail.component.ts new file mode 100644 index 0000000..1812f1f --- /dev/null +++ b/src/app/product/product-detail/product-detail.component.ts @@ -0,0 +1,39 @@ +import {Component, OnInit} from '@angular/core'; +import {Product, products} from '../products'; +import {CurrencyPipe, NgIf} from '@angular/common'; +import {ActivatedRoute} from '@angular/router'; +import {CartService} from '../service/cart.service'; + +@Component({ + selector: 'app-product-detail', + standalone: true, + imports: [ + NgIf, + CurrencyPipe + ], + templateUrl: './product-detail.component.html', + styleUrl: './product-detail.component.css' +}) +export class ProductDetailComponent implements OnInit{ + _product: Product | undefined; + constructor( + private route: ActivatedRoute, + private cartService: CartService + ) { + } + + ngOnInit(): void { + const routeParams = this.route.snapshot.paramMap; + const productIdFromRoute = Number(routeParams.get('productId')); + + this._product = products.find(product => product.id === productIdFromRoute); + } + + addToCart(product: Product) { + console.log(product) + this.cartService.addToCart(product); + + window.alert('Your product has been added to the cart!'); + + } +} diff --git a/src/app/product/product-list/product-list.component.css b/src/app/product/product-list/product-list.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product/product-list/product-list.component.html b/src/app/product/product-list/product-list.component.html new file mode 100644 index 0000000..f2bafc4 --- /dev/null +++ b/src/app/product/product-list/product-list.component.html @@ -0,0 +1,17 @@ +

Products

+ +

+ + {{ product.name }} + +

+

+ {{ product.description }} +

+ + +
+
diff --git a/src/app/product-list/product-list.component.spec.ts b/src/app/product/product-list/product-list.component.spec.ts similarity index 100% rename from src/app/product-list/product-list.component.spec.ts rename to src/app/product/product-list/product-list.component.spec.ts diff --git a/src/app/product/product-list/product-list.component.ts b/src/app/product/product-list/product-list.component.ts new file mode 100644 index 0000000..ca69f0e --- /dev/null +++ b/src/app/product/product-list/product-list.component.ts @@ -0,0 +1,32 @@ +import { Component } from '@angular/core'; +import { products } from '../products'; +import {ProductDetailComponent} from '../product-detail/product-detail.component'; +import {NgForOf, NgIf} from '@angular/common'; +import {ProductAlertsComponent} from '../product-alerts/product-alerts.component'; +import {RouterLink} from '@angular/router'; + +@Component({ + selector: 'app-product-list', + standalone: true, + imports: [ + ProductDetailComponent, + NgForOf, + NgIf, + ProductAlertsComponent, + RouterLink + ], + templateUrl: './product-list.component.html', + styleUrl: './product-list.component.css' +}) +export class ProductListComponent { + products = [...products]; + + share() { + window.alert('The product has been shared!'); + } + + + onNotify() { + window.alert('You will be notified when the product goes on sale'); + } +} diff --git a/src/app/products.ts b/src/app/product/products.ts similarity index 92% rename from src/app/products.ts rename to src/app/product/products.ts index 1bd45bd..4d99807 100644 --- a/src/app/products.ts +++ b/src/app/product/products.ts @@ -5,7 +5,7 @@ export interface Product { description: string; } -export const products = [ +export const products: Product[] = [ { id: 1, name: 'Phone XL', diff --git a/src/app/product/service/cart.service.spec.ts b/src/app/product/service/cart.service.spec.ts new file mode 100644 index 0000000..cb4a750 --- /dev/null +++ b/src/app/product/service/cart.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { CartService } from './cart.service'; + +describe('CartService', () => { + let service: CartService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(CartService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/product/service/cart.service.ts b/src/app/product/service/cart.service.ts new file mode 100644 index 0000000..52d6402 --- /dev/null +++ b/src/app/product/service/cart.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import {Product} from '../products'; +import {HttpClient} from '@angular/common/http'; +import {Shipping} from '../shipping'; +import {Observable} from 'rxjs'; + +@Injectable({ + providedIn: 'root' +}) +export class CartService { + private _items: Product[] = []; + + constructor(private http: HttpClient) { + } + + public addToCart(product: Product): void { + this._items.push(product); + } + + public get items() { + return this._items; + } + + public clearCart(): Product[] { + this._items = []; + + return this._items; + } + + public getShippingPrices(): Observable { + return this.http.get('/assets/shipping.json'); + } +} diff --git a/src/app/product/shipping.ts b/src/app/product/shipping.ts new file mode 100644 index 0000000..40e66fe --- /dev/null +++ b/src/app/product/shipping.ts @@ -0,0 +1,4 @@ +export interface Shipping { + type: string; + price: number; +} diff --git a/src/app/product/shipping/shipping.component.css b/src/app/product/shipping/shipping.component.css new file mode 100644 index 0000000..e69de29 diff --git a/src/app/product/shipping/shipping.component.html b/src/app/product/shipping/shipping.component.html new file mode 100644 index 0000000..677674e --- /dev/null +++ b/src/app/product/shipping/shipping.component.html @@ -0,0 +1,5 @@ +

Shipping Prices

+
+ {{ shipping.type }} + {{ shipping.price | currency }} +
diff --git a/src/app/product/shipping/shipping.component.spec.ts b/src/app/product/shipping/shipping.component.spec.ts new file mode 100644 index 0000000..b7d6707 --- /dev/null +++ b/src/app/product/shipping/shipping.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ShippingComponent } from './shipping.component'; + +describe('ShippingComponent', () => { + let component: ShippingComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ShippingComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(ShippingComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/product/shipping/shipping.component.ts b/src/app/product/shipping/shipping.component.ts new file mode 100644 index 0000000..42b7be1 --- /dev/null +++ b/src/app/product/shipping/shipping.component.ts @@ -0,0 +1,28 @@ +import {Component, OnInit} from '@angular/core'; +import {CartService} from '../service/cart.service'; +import {Observable} from 'rxjs'; +import {Shipping} from '../shipping'; +import {AsyncPipe, CurrencyPipe, NgForOf} from '@angular/common'; + +@Component({ + selector: 'app-shipping', + standalone: true, + imports: [ + AsyncPipe, + CurrencyPipe, + NgForOf + ], + templateUrl: './shipping.component.html', + styleUrl: './shipping.component.css' +}) +export class ShippingComponent implements OnInit { + protected shippingCosts!: Observable; + + constructor(private cartService: CartService) { + } + + ngOnInit(): void { + this.shippingCosts = this.cartService.getShippingPrices(); + } + +} diff --git a/src/app/top-bar/top-bar.component.html b/src/app/top-bar/top-bar.component.html index 86bbf82..e1f0e18 100644 --- a/src/app/top-bar/top-bar.component.html +++ b/src/app/top-bar/top-bar.component.html @@ -1,5 +1,4 @@

My Store

- -shopping_cartCheckout +shopping_cartCheckout