feat: Implement multi-step order flow with product configuration, user data input, and order summary page.
This commit is contained in:
@@ -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 },
|
||||
];
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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>
|
||||
@@ -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%;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,5 +76,7 @@ export class Productconfigpage {
|
||||
},
|
||||
totalPrice: this.totalPrice,
|
||||
});
|
||||
|
||||
window.location.href = '/user-data';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
<div class="row row--gutters">
|
||||
<div class="col-md-6">
|
||||
<sdx-input id="email" label="E-Mail" name="email" required></sdx-input>
|
||||
</div>
|
||||
|
||||
<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="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 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-dialog-content>
|
||||
</sdx-dialog>
|
||||
</sdx-progress-full-step>
|
||||
|
||||
</sdx-progress-full>
|
||||
</div>
|
||||
@@ -0,0 +1,6 @@
|
||||
.userdatapage {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
height: 100vh;
|
||||
}
|
||||
@@ -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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user