feat: Implement multi-step order flow with product configuration, user data input, and order summary page.

This commit is contained in:
2025-11-27 13:07:05 +01:00
parent 0a03f9be60
commit 292ed397ab
10 changed files with 223 additions and 43 deletions

View File

@@ -1,8 +1,12 @@
import { Routes } from '@angular/router';
import { Productspage } from './productspage/productspage';
import { Productconfigpage } from './productconfigpage/productconfigpage';
import { Userdatapage } from './userdatapage/userdatapage';
import { Ordersummarypage } from './ordersummarypage/ordersummarypage';
export const routes: Routes = [
{ path: '', component: Productspage },
{ path: 'products/:id', component: Productconfigpage },
{ path: 'user-data', component: Userdatapage },
{ path: 'order-success', component: Ordersummarypage },
];

View File

@@ -28,10 +28,13 @@ export interface IProductConfig {
}
export interface IUserData {
fullName: string;
firstName: string;
lastName: string;
email: string;
phone: string;
city: string;
address: string;
zipCode: string;
city: string;
}
export interface IPaymentMethod {

View File

@@ -1 +1,29 @@
<p>ordersummarypage works!</p>
<div class="summary">
<sdx-card layout="notification" notification-type="confirmation" icon-name="icon-check-mark-circle-filled"
label="Order confirmation" label-aria-level="4">
Your order has been confirmed.
Shipping number: {{ order.shippingNumber }}
</sdx-card>
<!-- show shipping number and summary of whole order -->
<sdx-card layout="notification" notification-type="confirmation" icon-name="icon-check-mark-circle-filled"
label="Order summary" label-aria-level="4">
{{ order.product?.name }}
<br>
Gesamtpreis: {{ totalPrice }} CHF
<h5>Added ingredients</h5>
@if(order.config?.extraBacon){
<sdx-input-item type="checkbox" checked disabled>
Extra Bacon
</sdx-input-item>
}
@else {
<sdx-input-item type="checkbox" disabled>
Extra Bacon
</sdx-input-item>
}
<p>Salad amount: {{ order.config?.saladAmount || 'normal' }}</p>
<h3>Shipping Number:</h3>
<h4>{{ order.shippingNumber }}</h4>
</sdx-card>
</div>

View File

@@ -0,0 +1,13 @@
.summary {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
gap: 1rem;
height: 100vh;
}
.summary sdx-card {
width: 50%;
}

View File

@@ -1,11 +1,39 @@
import { Component } from '@angular/core';
import { Component , inject, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { OrderService } from '../services/order.service';
@Component({
selector: 'app-ordersummarypage',
imports: [],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
templateUrl: './ordersummarypage.html',
styleUrl: './ordersummarypage.scss',
})
export class Ordersummarypage {
orderService = inject(OrderService);
get totalPrice() {
const order = this.orderService.getOrder();
return (order.product?.basePrice ?? 0) + (order.config?.priceDelta ?? 0);
}
get saladAmount(): number {
const order = this.orderService.getOrder();
switch (order.config?.saladAmount) {
case 'less':
return 1;
case 'normal':
return 2;
case 'much':
return 3;
}
return 2;
}
get order() {
const order = this.orderService.getOrder();
const basePrice = order.product?.basePrice ?? 0;
return order;
}
}

View File

@@ -76,5 +76,7 @@ export class Productconfigpage {
},
totalPrice: this.totalPrice,
});
window.location.href = '/user-data';
}
}

View File

@@ -16,7 +16,7 @@ export class OrderService {
this.currentOrder = { ...this.currentOrder, ...partialOrder };
}
public placeOrder(): string {
public placeOrder(): IOrder {
// Logic to send order
const finalOrder = this.getOrder();
@@ -26,6 +26,6 @@ export class OrderService {
console.log('Order placed:', this.getOrder());
return shippingID;
return this.getOrder();
}
}

View File

@@ -1,38 +1,84 @@
<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();">
<div class="userdatapage">
<sdx-progress-full id="progress" #progress theme="horizontal"
sr-hint="Your current progress in completing your purchase" value="2">
<sdx-progress-full-step label="Your order" [summary]="productName">
<a href="/products/{{productId}}">Change quantity, add or remove ingredients</a>
<sdx-button-group>
<sdx-button label="Next" (click)="progress.nextStep()"></sdx-button>
</sdx-button-group>
</sdx-progress-full-step>
<sdx-dialog-toggle>
<sdx-button id="contact-opener" label="Rückruf anfordern"></sdx-button>
</sdx-dialog-toggle>
<sdx-progress-full-step label="Personal details" summary="First Name,
Last Name,
E-Mail,
Phone">
<div class="row row--gutters">
<div class="col-md-6">
<sdx-input-group type="radio" name="salutation" inline="inline" label="Salutation" required>
<sdx-input-item value="misses" id="misses">Misses</sdx-input-item>
<sdx-input-item value="mister" id="mister">Mister</sdx-input-item>
</sdx-input-group>
</div>
</div>
<sdx-dialog-content>
<p>We will be happy to put you through to one of our employees now.</p>
<div class="row row--gutters">
<div class="col-md-6">
<sdx-input id="firstName" label="First name" name="firstName" required></sdx-input>
</div>
<p class="margin-bottom-4">
<sdx-input
id="contact-input"
label="How can we contact you by phone?"
#phoneNumber>
</sdx-input>
</p>
<div class="col-md-6">
<sdx-input id="lastName" label="Last name" name="lastName" required></sdx-input>
</div>
</div>
<sdx-button-group>
<sdx-button
label="Call back now"
(click)="saveContactData(phoneNumber.value)">
</sdx-button>
<div class="row row--gutters">
<div class="col-md-6">
<sdx-input id="email" label="E-Mail" name="email" required></sdx-input>
</div>
<sdx-button
label="Cancel"
theme="secondary"
onclick="document.getElementById('contact-modal').close()">
</sdx-button>
</sdx-button-group>
</sdx-dialog-content>
</sdx-dialog>
<div class="col-md-6">
<sdx-input id="phone" label="Phone" name="phone"></sdx-input>
</div>
</div>
<div class="row row--gutters">
<div class="col-md-6">
<sdx-input id="city" label="City" name="city"></sdx-input>
</div>
<div class="col-md-6">
<sdx-input id="address" label="Address" name="address"></sdx-input>
</div>
</div>
<div class="row row--gutters">
<div class="col-md-6">
<sdx-input id="zipCode" label="Zip Code" name="zipCode"></sdx-input>
</div>
</div>
<div class="row row--gutters">
<div class="col-xs-12">
<sdx-button-group>
<sdx-button label="Next" (click)="progress.nextStep(); saveData()"></sdx-button>
<sdx-button label="Back" (click)="progress.previousStep()" theme="secondary"></sdx-button>
</sdx-button-group>
</div>
</div>
</sdx-progress-full-step>
<sdx-progress-full-step label="Payment method">
<sdx-option-picker #payments options='[
{ "name": "Twint", "value": "twint", "checked": true, "srHint": "Twint" },
{ "name": "Visa", "value": "visa", "srHint": "Visa" },
{ "name": "Mastercard", "value": "mastercard", "srHint": "Mastercard" }
]' (change)="setPaymentMethod(payments.value)"></sdx-option-picker>
<sdx-button-group>
<sdx-button label="Finish Order" (click)="progress.nextStep(); saveData(); finishOrder();"></sdx-button>
<sdx-button label="Back" (click)="progress.previousStep()" theme="secondary"></sdx-button>
</sdx-button-group>
</sdx-progress-full-step>
</sdx-progress-full>
</div>

View File

@@ -0,0 +1,6 @@
.userdatapage {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

View File

@@ -1,5 +1,8 @@
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { Component, CUSTOM_ELEMENTS_SCHEMA, inject } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { Router } from '@angular/router';
import { IPaymentMethod, IProduct, IUserData } from '../models/order.interface';
import { OrderService } from '../services/order.service';
@Component({
selector: 'app-userdatapage',
@@ -10,4 +13,51 @@ import { FormsModule } from '@angular/forms';
})
export class Userdatapage {
orderService = inject(OrderService);
router = inject(Router);
paymentMethod: 'twint' | 'visa' | 'mastercard' = 'twint';
get productName() {
const product: IProduct = JSON.parse(localStorage.getItem('cart') || '{}').product;
return product?.name;
}
get productId() {
const product: IProduct = JSON.parse(localStorage.getItem('cart') || '{}').product;
return product?.id;
}
public saveData() {
const contactData: IUserData = {
firstName: (document.getElementById('firstName') as HTMLInputElement)?.value,
lastName: (document.getElementById('lastName') as HTMLInputElement)?.value,
email: (document.getElementById('email') as HTMLInputElement)?.value,
phone: (document.getElementById('phone') as HTMLInputElement)?.value,
city: (document.getElementById('city') as HTMLInputElement)?.value,
address: (document.getElementById('address') as HTMLInputElement)?.value,
zipCode: (document.getElementById('zipCode') as HTMLInputElement)?.value,
};
const cart = JSON.parse(localStorage.getItem('cart') || '{}');
this.orderService.updateOrder({
userData: contactData,
paymentMethod: { type: this.paymentMethod },
product: cart.product,
config: cart.config
});
console.log(contactData, this.paymentMethod);
}
public finishOrder() {
this.orderService.placeOrder();
this.router.navigate(['/order-success']);
}
public setPaymentMethod(values: any) {
if (Array.isArray(values) && values.length > 0) {
this.paymentMethod = values[0] as 'twint' | 'visa' | 'mastercard';
}
}
}