feat: implement product configuration and order management with service refactoring and UI updates
This commit is contained in:
25
package-lock.json
generated
25
package-lock.json
generated
@@ -461,7 +461,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/common/-/common-21.0.0.tgz",
|
||||||
"integrity": "sha512-uFvQDYU5X5nEnI9C4Bkdxcu4aIzNesGLJzmFlnwChVxB4BxIRF0uHL0oRhdkInGTIzPDJPH4nF6B/22c5gDVqA==",
|
"integrity": "sha512-uFvQDYU5X5nEnI9C4Bkdxcu4aIzNesGLJzmFlnwChVxB4BxIRF0uHL0oRhdkInGTIzPDJPH4nF6B/22c5gDVqA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -478,7 +477,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.0.0.tgz",
|
||||||
"integrity": "sha512-6jCH3UYga5iokj5F40SR4dlwo9ZRMkT8YzHCTijwZuDX9zvugp9jPof092RvIeNsTvCMVfGWuM9yZ1DRUsU/yg==",
|
"integrity": "sha512-6jCH3UYga5iokj5F40SR4dlwo9ZRMkT8YzHCTijwZuDX9zvugp9jPof092RvIeNsTvCMVfGWuM9yZ1DRUsU/yg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -492,7 +490,6 @@
|
|||||||
"integrity": "sha512-KTXp+e2UPGyfFew6Wq95ULpHWQ20dhqkAMZ6x6MCYfOe2ccdnGYsAbLLmnWGmSg5BaOI4B0x/1XCFZf/n6WDgA==",
|
"integrity": "sha512-KTXp+e2UPGyfFew6Wq95ULpHWQ20dhqkAMZ6x6MCYfOe2ccdnGYsAbLLmnWGmSg5BaOI4B0x/1XCFZf/n6WDgA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.28.4",
|
"@babel/core": "7.28.4",
|
||||||
"@jridgewell/sourcemap-codec": "^1.4.14",
|
"@jridgewell/sourcemap-codec": "^1.4.14",
|
||||||
@@ -525,7 +522,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@angular/core/-/core-21.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/core/-/core-21.0.0.tgz",
|
||||||
"integrity": "sha512-bqi8fT4csyITeX8vdN5FJDBWx5wuWzdCg4mKSjHd+onVzZLyZ8bcnuAKz4mklgvjvwuXoRYukmclUurLwfq3Rg==",
|
"integrity": "sha512-bqi8fT4csyITeX8vdN5FJDBWx5wuWzdCg4mKSjHd+onVzZLyZ8bcnuAKz4mklgvjvwuXoRYukmclUurLwfq3Rg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -570,7 +566,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.0.0.tgz",
|
||||||
"integrity": "sha512-KQrANla4RBLhcGkwlndqsKzBwVFOWQr1640CfBVjj2oz4M3dW5hyMtXivBACvuwyUhYU/qJbqlDMBXl/OUSudQ==",
|
"integrity": "sha512-KQrANla4RBLhcGkwlndqsKzBwVFOWQr1640CfBVjj2oz4M3dW5hyMtXivBACvuwyUhYU/qJbqlDMBXl/OUSudQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
@@ -692,7 +687,6 @@
|
|||||||
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
"integrity": "sha512-2BCOP7TN8M+gVDj7/ht3hsaO/B/n5oDbiAyyvnRlNOs+u1o+JWNYTQrmpuNp1/Wq2gcFrI01JAW+paEKDMx/CA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.27.1",
|
"@babel/code-frame": "^7.27.1",
|
||||||
"@babel/generator": "^7.28.3",
|
"@babel/generator": "^7.28.3",
|
||||||
@@ -1052,7 +1046,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
@@ -1096,7 +1089,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
}
|
}
|
||||||
@@ -1813,7 +1805,6 @@
|
|||||||
"integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==",
|
"integrity": "sha512-X7/+dG9SLpSzRkwgG5/xiIzW0oMrV3C0HOa7YHG1WnrLK+vCQHfte4k/T80059YBdei29RBC3s+pSMvPJDU9/A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@inquirer/checkbox": "^4.3.0",
|
"@inquirer/checkbox": "^4.3.0",
|
||||||
"@inquirer/confirm": "^5.1.19",
|
"@inquirer/confirm": "^5.1.19",
|
||||||
@@ -3965,8 +3956,7 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.0.0.tgz",
|
||||||
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
"integrity": "sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@stencil/core": {
|
"node_modules/@stencil/core": {
|
||||||
"version": "4.25.1",
|
"version": "4.25.1",
|
||||||
@@ -4512,7 +4502,6 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"baseline-browser-mapping": "^2.8.25",
|
"baseline-browser-mapping": "^2.8.25",
|
||||||
"caniuse-lite": "^1.0.30001754",
|
"caniuse-lite": "^1.0.30001754",
|
||||||
@@ -4702,7 +4691,6 @@
|
|||||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readdirp": "^4.0.1"
|
"readdirp": "^4.0.1"
|
||||||
},
|
},
|
||||||
@@ -5431,7 +5419,6 @@
|
|||||||
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
"integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"accepts": "^2.0.0",
|
"accepts": "^2.0.0",
|
||||||
"body-parser": "^2.2.0",
|
"body-parser": "^2.2.0",
|
||||||
@@ -6192,7 +6179,6 @@
|
|||||||
"integrity": "sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==",
|
"integrity": "sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@acemir/cssom": "^0.9.23",
|
"@acemir/cssom": "^0.9.23",
|
||||||
"@asamuzakjp/dom-selector": "^6.7.4",
|
"@asamuzakjp/dom-selector": "^6.7.4",
|
||||||
@@ -6293,7 +6279,6 @@
|
|||||||
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
|
"integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cli-truncate": "^5.0.0",
|
"cli-truncate": "^5.0.0",
|
||||||
"colorette": "^2.0.20",
|
"colorette": "^2.0.20",
|
||||||
@@ -7792,7 +7777,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
"resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz",
|
||||||
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
"integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.1.0"
|
"tslib": "^2.1.0"
|
||||||
}
|
}
|
||||||
@@ -8487,8 +8471,7 @@
|
|||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||||
"license": "0BSD",
|
"license": "0BSD"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/tuf-js": {
|
"node_modules/tuf-js": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
@@ -8526,7 +8509,6 @@
|
|||||||
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -8659,7 +8641,6 @@
|
|||||||
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
"integrity": "sha512-BxAKBWmIbrDgrokdGZH1IgkIk/5mMHDreLDmCJ0qpyJaAteP8NvMhkwr/ZCQNqNH97bw/dANTE9PDzqwJghfMQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.5.0",
|
"fdir": "^6.5.0",
|
||||||
@@ -9219,7 +9200,6 @@
|
|||||||
"integrity": "sha512-2Fqty3MM9CDwOVet/jaQalYlbcjATZwPYGcqpiYQqgQ/dLC7GuHdISKgTYIVF/kaishKxLzleKWWfbSDklyIKg==",
|
"integrity": "sha512-2Fqty3MM9CDwOVet/jaQalYlbcjATZwPYGcqpiYQqgQ/dLC7GuHdISKgTYIVF/kaishKxLzleKWWfbSDklyIKg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vitest/expect": "4.0.10",
|
"@vitest/expect": "4.0.10",
|
||||||
"@vitest/mocker": "4.0.10",
|
"@vitest/mocker": "4.0.10",
|
||||||
@@ -9740,7 +9720,6 @@
|
|||||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,5 +4,5 @@ import { Productconfigpage } from './productconfigpage/productconfigpage';
|
|||||||
|
|
||||||
export const routes: Routes = [
|
export const routes: Routes = [
|
||||||
{ path: '', component: Productspage },
|
{ path: '', component: Productspage },
|
||||||
{ path: 'product/:id', component: Productconfigpage },
|
{ path: 'products/:id', component: Productconfigpage },
|
||||||
];
|
];
|
||||||
|
|||||||
39
src/app/models/order.interface.ts
Normal file
39
src/app/models/order.interface.ts
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
// src/app/models/order.interface.ts
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definiert die Struktur der gesamten Bestellung.
|
||||||
|
* Alle Felder sind optional ('?'), da die Bestellung schrittweise befüllt wird.
|
||||||
|
*/
|
||||||
|
export interface IOrder {
|
||||||
|
product?: IProduct;
|
||||||
|
config?: IProductConfig;
|
||||||
|
userData?: IUserData;
|
||||||
|
paymentMethod?: IPaymentMethod;
|
||||||
|
shippingNumber?: string;
|
||||||
|
totalPrice?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProduct {
|
||||||
|
id: number;
|
||||||
|
name: string;
|
||||||
|
basePrice: number;
|
||||||
|
bestChoice: boolean;
|
||||||
|
img?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IProductConfig {
|
||||||
|
extraBacon: boolean;
|
||||||
|
saladAmount: 'less' | 'normal' | 'much';
|
||||||
|
priceDelta: number; // Preisunterschied durch Konfiguration
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IUserData {
|
||||||
|
fullName: string;
|
||||||
|
address: string;
|
||||||
|
zipCode: string;
|
||||||
|
city: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IPaymentMethod {
|
||||||
|
type: 'twint' | 'visa' | 'mastercard';
|
||||||
|
}
|
||||||
@@ -1,6 +1,27 @@
|
|||||||
<div class="main">
|
<div class="main">
|
||||||
<img [src]="product?.img" alt="" srcset="">
|
<h1>Configure your <br>{{product?.name}}</h1>
|
||||||
<sdx-numeric-stepper [label]="product?.name" sr-hint="Number of products" max="10"
|
<img [src]="product?.img" alt="burger picture" srcset="">
|
||||||
oninput="console.log('Value:', arguments[0].target.value)">
|
|
||||||
</sdx-numeric-stepper>
|
<div class="options">
|
||||||
|
|
||||||
|
<sdx-input-group type="checkbox" inline>
|
||||||
|
<sdx-input-item value="bacon" #baconCheckbox>Want to add extra bacon?</sdx-input-item>
|
||||||
|
</sdx-input-group>
|
||||||
|
|
||||||
|
<sdx-select
|
||||||
|
label="How much Salad do you want?"
|
||||||
|
placeholder="Choose your option…"
|
||||||
|
#saladSelect> <sdx-select-option value="less">Less (-0.50 CHF)</sdx-select-option>
|
||||||
|
<sdx-select-option value="normal">Normal</sdx-select-option>
|
||||||
|
<sdx-select-option value="much">Much (+0.50 CHF)</sdx-select-option>
|
||||||
|
</sdx-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="price-summary s-heading-s">
|
||||||
|
Total Price: {{ totalPrice }} </div>
|
||||||
|
|
||||||
|
<sdx-button
|
||||||
|
label="Order"
|
||||||
|
(click)="addToCart(baconCheckbox.checked, saladSelect.value[0])">
|
||||||
|
</sdx-button>
|
||||||
</div>
|
</div>
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
padding: 5vw;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
img {
|
||||||
|
width: 350px;
|
||||||
|
border-radius: 24px;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.options {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,10 +1,12 @@
|
|||||||
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject } from '@angular/core';
|
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject } from '@angular/core';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { Products } from '../products.service';
|
import { Products } from '../services/products.service';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
import { OrderService } from '../services/order.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-productconfigpage',
|
selector: 'app-productconfigpage',
|
||||||
imports: [],
|
imports: [FormsModule],
|
||||||
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
templateUrl: './productconfigpage.html',
|
templateUrl: './productconfigpage.html',
|
||||||
styleUrl: './productconfigpage.scss',
|
styleUrl: './productconfigpage.scss',
|
||||||
@@ -12,7 +14,67 @@ import { Products } from '../products.service';
|
|||||||
export class Productconfigpage {
|
export class Productconfigpage {
|
||||||
private selectedProduct = inject(ActivatedRoute);
|
private selectedProduct = inject(ActivatedRoute);
|
||||||
productService = inject(Products);
|
productService = inject(Products);
|
||||||
|
orderService = inject(OrderService);
|
||||||
|
|
||||||
productId = this.selectedProduct.snapshot.paramMap.get('id');
|
productId = this.selectedProduct.snapshot.paramMap.get('id');
|
||||||
product = this.productService.getProductList().find((p) => p.id === Number(this.productId));
|
product = this.productService.getProductList().find((p) => p.id === Number(this.productId));
|
||||||
|
|
||||||
|
// Add index signature so template can safely use options[option.key]
|
||||||
|
extraBacon: boolean = false;
|
||||||
|
saladAmount: 'less' | 'normal' | 'much' = 'normal';
|
||||||
|
|
||||||
|
console = console;
|
||||||
|
|
||||||
|
get priceDelta(): number {
|
||||||
|
let delta = 0;
|
||||||
|
// Greift direkt auf this.extraBacon zu
|
||||||
|
if (this.extraBacon) {
|
||||||
|
delta += 1.5;
|
||||||
|
}
|
||||||
|
// Greift direkt auf this.saladAmount zu
|
||||||
|
switch (this.saladAmount) {
|
||||||
|
case 'less':
|
||||||
|
delta -= 0.5;
|
||||||
|
break;
|
||||||
|
case 'much':
|
||||||
|
delta += 0.5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wandle die Funktion in einen GETTER um (keine Argumente!)
|
||||||
|
get totalPrice(): number {
|
||||||
|
// Ruft den Getter this.priceDelta auf
|
||||||
|
return (this.product?.basePrice || 0) + this.priceDelta;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
addToCart(isBaconChecked: boolean, selectedSaladAmount: 'less' | 'normal' | 'much') {
|
||||||
|
|
||||||
|
// set the variables
|
||||||
|
this.extraBacon = isBaconChecked;
|
||||||
|
this.saladAmount = selectedSaladAmount;
|
||||||
|
|
||||||
|
// save to localStorage
|
||||||
|
localStorage.setItem('cart', JSON.stringify({
|
||||||
|
product: this.product,
|
||||||
|
config: {
|
||||||
|
extraBacon: this.extraBacon,
|
||||||
|
saladAmount: this.saladAmount,
|
||||||
|
priceDelta: this.priceDelta,
|
||||||
|
},
|
||||||
|
totalPrice: this.totalPrice,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.orderService.updateOrder({
|
||||||
|
product: this.product,
|
||||||
|
config: {
|
||||||
|
extraBacon: this.extraBacon,
|
||||||
|
saladAmount: this.saladAmount,
|
||||||
|
priceDelta: this.priceDelta,
|
||||||
|
},
|
||||||
|
totalPrice: this.totalPrice,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import { Injectable } from '@angular/core';
|
|
||||||
|
|
||||||
@Injectable({
|
|
||||||
providedIn: 'root',
|
|
||||||
})
|
|
||||||
export class Products {
|
|
||||||
getProductList() {
|
|
||||||
return [
|
|
||||||
{ id: 1, name: 'Rindburger', price: 14.95, img: '/rindburger.png' },
|
|
||||||
{ id: 2, name: 'Pouletburger', price: 16.95, img: '/krabsburger.png' },
|
|
||||||
{ id: 3, name: 'Veggieburger', price: 20.95, img: '/veggieburger.png' },
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -5,9 +5,10 @@
|
|||||||
<div class="products">
|
<div class="products">
|
||||||
|
|
||||||
@for (item of productList; track $index) {
|
@for (item of productList; track $index) {
|
||||||
<sdx-card [label]="item.name" label-aria-level="3" [imageSrc]="item.img" image-alt="burger">
|
<sdx-card [label]="item.name + ' - CHF ' + item.basePrice"
|
||||||
<p>{{item.price}}</p>
|
[background]="item.bestChoice ? 'blue' : 'white'" object-fit="cover" label-aria-level="3"
|
||||||
<sdx-button icon-name="icon-shopping-trolley" label="Jetzt bestellen"></sdx-button>
|
[imageSrc]="item.img" image-alt="burger" href-label="Order now!" [href]="'/products/' + item.id">
|
||||||
|
|
||||||
</sdx-card>
|
</sdx-card>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
@@ -2,15 +2,16 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
padding: 10px 20px;
|
||||||
|
border-bottom: #333 2px solid;
|
||||||
|
|
||||||
img {
|
img {
|
||||||
height: 40px;
|
height: 60px;
|
||||||
}
|
}
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 24px;
|
font-size: 32px;
|
||||||
color: #333;
|
color: #333;
|
||||||
border-bottom: #333 2px solid;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -24,6 +25,10 @@
|
|||||||
|
|
||||||
sdx-card {
|
sdx-card {
|
||||||
height: auto;
|
height: auto;
|
||||||
object-fit: cover;
|
width: 350px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { Component, inject, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
import { Component, inject, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
import { Products } from '../products.service';
|
import { Products } from '../services/products.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-productspage',
|
selector: 'app-productspage',
|
||||||
|
|||||||
31
src/app/services/order.service.ts
Normal file
31
src/app/services/order.service.ts
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { IOrder } from '../models/order.interface';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class OrderService {
|
||||||
|
|
||||||
|
private currentOrder: IOrder = {};
|
||||||
|
|
||||||
|
public getOrder(): IOrder {
|
||||||
|
return this.currentOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public updateOrder(partialOrder: Partial<IOrder>): void {
|
||||||
|
this.currentOrder = { ...this.currentOrder, ...partialOrder };
|
||||||
|
}
|
||||||
|
|
||||||
|
public placeOrder(): string {
|
||||||
|
// Logic to send order
|
||||||
|
|
||||||
|
const finalOrder = this.getOrder();
|
||||||
|
|
||||||
|
const shippingID = "SC-" + Math.floor(Math.random() * 1000000).toString().padStart(6, '0');
|
||||||
|
this.updateOrder({ shippingNumber: shippingID });
|
||||||
|
|
||||||
|
console.log('Order placed:', this.getOrder());
|
||||||
|
|
||||||
|
return shippingID;
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/app/services/products.service.ts
Normal file
40
src/app/services/products.service.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { IProduct } from '../models/order.interface';
|
||||||
|
|
||||||
|
@Injectable({
|
||||||
|
providedIn: 'root',
|
||||||
|
})
|
||||||
|
export class Products {
|
||||||
|
public getProductList(): IProduct[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: 1,
|
||||||
|
name: 'Classic Burger',
|
||||||
|
basePrice: 8.5,
|
||||||
|
bestChoice: false,
|
||||||
|
img: 'rindburger.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 2,
|
||||||
|
name: 'Mr.Krabs Burger',
|
||||||
|
basePrice: 9.5,
|
||||||
|
bestChoice: true,
|
||||||
|
img: 'krabsburger.png',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 3,
|
||||||
|
name: 'Veggie Burger',
|
||||||
|
basePrice: 10.0,
|
||||||
|
bestChoice: false,
|
||||||
|
img: 'veggieburger.png',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getProductById(id: number) {
|
||||||
|
return this.getProductList().find((product) => {
|
||||||
|
return product.id === id;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1 +1,38 @@
|
|||||||
<p>userdatapage works!</p>
|
<sdx-dialog
|
||||||
|
label="Call back now"
|
||||||
|
type="closable-modal"
|
||||||
|
id="contact-modal" icon-name="icon-call-centre"
|
||||||
|
display-change-callback="
|
||||||
|
/* Fügt Fokus-Logik hinzu, wenn nötig */
|
||||||
|
if (arguments[0] === 'open') document.querySelector('#contact-input').doFocus();
|
||||||
|
if (arguments[0] === 'closing') document.querySelector('#contact-opener').doFocus();">
|
||||||
|
|
||||||
|
<sdx-dialog-toggle>
|
||||||
|
<sdx-button id="contact-opener" label="Rückruf anfordern"></sdx-button>
|
||||||
|
</sdx-dialog-toggle>
|
||||||
|
|
||||||
|
<sdx-dialog-content>
|
||||||
|
<p>We will be happy to put you through to one of our employees now.</p>
|
||||||
|
|
||||||
|
<p class="margin-bottom-4">
|
||||||
|
<sdx-input
|
||||||
|
id="contact-input"
|
||||||
|
label="How can we contact you by phone?"
|
||||||
|
#phoneNumber>
|
||||||
|
</sdx-input>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<sdx-button-group>
|
||||||
|
<sdx-button
|
||||||
|
label="Call back now"
|
||||||
|
(click)="saveContactData(phoneNumber.value)">
|
||||||
|
</sdx-button>
|
||||||
|
|
||||||
|
<sdx-button
|
||||||
|
label="Cancel"
|
||||||
|
theme="secondary"
|
||||||
|
onclick="document.getElementById('contact-modal').close()">
|
||||||
|
</sdx-button>
|
||||||
|
</sdx-button-group>
|
||||||
|
</sdx-dialog-content>
|
||||||
|
</sdx-dialog>
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||||
|
import { FormsModule } from '@angular/forms';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-userdatapage',
|
selector: 'app-userdatapage',
|
||||||
imports: [],
|
imports: [FormsModule],
|
||||||
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
||||||
templateUrl: './userdatapage.html',
|
templateUrl: './userdatapage.html',
|
||||||
styleUrl: './userdatapage.scss',
|
styleUrl: './userdatapage.scss',
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user