[HIMA-44] FE: checkout dialog

- Removed hardcoded data and using store
- Implemented the cart state
- Dialogs redirect to correct components
This commit is contained in:
Milos Jovanov
2019-02-06 19:07:03 +01:00
parent e0874b0ae6
commit b222b4cb9f
20 changed files with 173 additions and 54 deletions

View File

@@ -11,10 +11,6 @@ export const usersMock: User[] = [
invoice_address: new Address('Karl Schneider', 'Kazmairstraße 34', 80339, 'München'),
shop: true,
payement_method: 'Rechnung',
cart: [
procuctsMock[0],
procuctsMock[1]
],
poossible_addresses: [
new Address('Karl Schneider-Koch','Kazmairstraße 38', 80339, 'München'),
new Address('Julia Schneider-Koch','Kazmairstraße 38', 80339, 'München'),
@@ -29,10 +25,6 @@ export const usersMock: User[] = [
invoice_address: new Address('Karl Schneider-Koch','Kazmairstraße 38', 80339, 'München'),
shop: false,
payement_method: 'Rechnung',
cart: [
procuctsMock[2],
procuctsMock[3]
],
poossible_addresses: [
new Address('Karl Schneider-Koch','Kazmairstraße 38', 80339, 'München'),
new Address('Andrea Schneider-Koch','Kazmairstraße 38', 80339, 'München'),
@@ -48,10 +40,6 @@ export const usersMock: User[] = [
invoice_address: new Address('Michaela Rufus', 'Thierschplatz 128', 80339, 'Berlin'),
shop: true,
payement_method: 'Rechnung',
cart: [
procuctsMock[0],
procuctsMock[1]
],
poossible_addresses: [
new Address('Michaela Rufus', 'Thierschplatz 128', 80339, 'Berlin'),
new Address('Michaela Rufus', 'Thierschplatz 128', 80339, 'Berlin'),

View File

@@ -8,8 +8,6 @@
padding-left: 25px;
padding-right: 30px;
padding-bottom: 32px;
margin-right: 15px;
margin-left: 3px;
margin-top: 10px;
border-radius: 4px;
}

View File

@@ -10,7 +10,7 @@
<img class="img" src="../../../assets/images/Take_now.svg" alt="take now">
<h2 class="title-take-now">Jetzt mitnehmen</h2>
<span class="description description-take-now">Möchten Sie den Artikel jetzt gleich mit nach Hause nehmen?</span>
<span class="price price-take-now">16,95 EUR</span>
<span class="price price-take-now">{{ book.av[0].price.value.value }} {{ currency }}</span>
<a class="btn btn-active" (click)="selectedAction('mitnehmen')">Auswählen</a>
</div>
<div class="option">
@@ -30,7 +30,7 @@
<li *ngFor="let item of locations; let i = index" (click)="selectLocation(i, dropdown)">{{ item.name }}</li>
</ul>
</div>
<span class="price price-take-away">16,95 EUR</span>
<span class="price price-take-away">{{ book.av[0].price.value.value }} {{ currency }}</span>
<a class="btn" (click)="selectedAction('abholung')">Auswählen</a>
</div>
<div class="option">
@@ -39,7 +39,7 @@
<span class="description description-delivery">Möchten Sie den Artikel nach Hause geliefert bekommen?</span>
<div class="delivery" (click)="openDropdown(dropdown)"><img class="check" src="../../../assets/images/Check-green.svg" alt="arrow">Versandkostenfrei</div>
<span class="delivery-date">Lieferdatum {{ currentPickUpDate }}</span>
<span class="price price-order">16,95 EUR</span>
<span class="price price-order">{{ book.av[0].price.value.value }} {{ currency }}</span>
<a class="btn" (click)="selectedAction('versand')">Auswählen</a>
</div>
</div>
@@ -57,13 +57,13 @@
</div>
<div class="line"></div>
<div class="body-content">
<img src="../../../assets/images/Book-2x.png" alt="book">
<span class="book-title">Silberfischchtsy</span>
<img src="{{ imgUrl }}" alt="book">
<span class="book-title">{{ book.pr.name }}</span>
<div class="order-details">
<span><img class="order-book-icon" src="../../../assets/images/Book_Icon.svg" alt="book-icon"> TB I Inger-Maria Mahlke</span>
<span><img class="order-book-icon" src="../../../assets/images/Book_Icon.svg" alt="book-icon"> {{ book.pr.manufacturer }} I {{ book.pr.contributors }}</span>
<span class="order-details-delivery-info">DHL I Lieferung 18.01.</span>
</div>
<span class="price">{{ currentPrice }} EUR</span>
<span class="price">{{ currentPrice }} {{ currency }}</span>
<div class="dropdown_container">
<div (click)="openDropdown(dropdown)" class="dropdown-selected-text" [class.dropdown-selected-text-active]="displayDropdown">
<span class="">{{ currentNumberOfItems }}</span>
@@ -74,7 +74,6 @@
<ul>
<li *ngFor="let item of possibleItems" (click)="setNumberOfItems(item, dropdown)">{{ item }}</li>
</ul>
<!-- <span *ngFor="let item of possibleItems" (click)="setNumberOfItems(item, dropdown)">{{ item }}</span> -->
</div>
</div>
<a class="btn" (click)="switchSteps(true)">Ändern</a>
@@ -83,7 +82,7 @@
<div class="overview">
<span class="items">{{ displayItemsNumber }} Artikel I {{ currentPoints }} Lesepunkte</span>
<div class="overview-price-container">
<span class="overview-price">Zwischensumme {{ currentPrice }} EUR</span>
<span class="overview-price">Zwischensumme {{ currentPrice }} {{ currency }}</span>
<span class="overview-tax">ohne Versandkosten</span>
</div>
</div>
@@ -92,6 +91,6 @@
<a class="btn secondary" (click)="updateCart()">Weiter einkaufen</a>
<a class="btn active" (click)="itemsConfirmed()">Bezahlen</a>
</div>
</div>
</div>
</app-modal>

View File

@@ -108,7 +108,7 @@
&-take-away {
position: relative;
top: 32px;
top: 28px;
}
&-take-now {
@@ -326,6 +326,7 @@
text-overflow: ellipsis;
overflow: hidden;
width: 112px;
white-space: nowrap;
}
.order-details {
@@ -351,6 +352,9 @@
text-align: left;
line-height: 25px;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&-delivery-info {

View File

@@ -1,11 +1,11 @@
import { Component, OnInit, Output, EventEmitter } from '@angular/core';
import { Component, OnInit, Output, EventEmitter, Input } from '@angular/core';
import { ModalService } from '../../core/services/modal.service';
import { Router } from '@angular/router';
import { Store } from '@ngxs/store';
import { ChangeCurrentRoute } from 'src/app/core/store/actions/process.actions';
import { ChangeCurrentRoute, SetCartData } from 'src/app/core/store/actions/process.actions';
import { ItemDTO, CatImageService } from 'cat-service';
const points = 60;
const price = 16.95;
@Component({
selector: 'app-checkout',
@@ -25,13 +25,15 @@ export class CheckoutComponent implements OnInit {
];
currentLocation = this.locations[0];
currentPickUpDate = this.locations[0].date;
imgUrl = '';
// Step two mock data
currentNumberOfItems = 1;
possibleItems = [1, 2, 3, 4];
displayItemsNumber = 1;
currentPrice = price.toLocaleString().replace('.', ',');
currentPrice = '';
currentPoints = points;
currency = '';
// Toggle for dropdown
displayDropdown = false;
@@ -39,13 +41,31 @@ export class CheckoutComponent implements OnInit {
// Trigger other functionality if needed
@Output() closed: EventEmitter<boolean> = new EventEmitter();
private _book: ItemDTO;
@Input() set book(val: ItemDTO) {
if (val) {
this._book = val;
this.catImageService.getImageUrl(val.pr.ean).subscribe((url: string) => {
this.imgUrl = url;
});
}
}
get book() {
return this._book;
}
constructor(
private modalService: ModalService,
private store: Store,
private router: Router
private router: Router,
private catImageService: CatImageService
) { }
ngOnInit() {
this.currentPrice = this.bookPriceString();
this.currency = this.book.av[0].price.value.currency;
}
// STEP ONE
@@ -64,8 +84,6 @@ export class CheckoutComponent implements OnInit {
this.stepTwoImgType = 'truck_Icon.svg';
}
this.switchSteps();
// Logic later
}
// STEP TWO
@@ -73,20 +91,21 @@ export class CheckoutComponent implements OnInit {
this.currentNumberOfItems = numberOfItems;
this.displayItemsNumber = numberOfItems;
this.currentPoints = numberOfItems * points;
this.currentPrice = (Math.round((numberOfItems * price) * 100) / 100).toLocaleString().replace('.', ',');
this.currentPrice = (Math.round((this.bookPrice() * numberOfItems * 100)) / 100).toLocaleString().replace('.', ',');
this.toggleDropdown(element);
}
updateCart() {
// Save item to store
this.store.dispatch(new SetCartData(this.currentNumberOfItems, this._book, { name: 'Artikelsuche', path: 'article-search' }));
this.store.dispatch(new ChangeCurrentRoute('article-search'));
this.router.navigate(['article-search']);
this.closeModal();
}
itemsConfirmed () {
// Redirect to 'Kundensuche'
this.store.dispatch(new SetCartData(this.currentNumberOfItems, this._book, { name: 'Kundensuche', path: 'customer-search' }));
this.store.dispatch(new ChangeCurrentRoute('customer-search'));
this.router.navigate(['customer-search']);
this.closeModal();
}
@@ -103,10 +122,12 @@ export class CheckoutComponent implements OnInit {
this.closed.emit(dialogSubmited);
this.modalService.close(this.id);
this.defaultValues();
this.stepOne = true;
}
switchSteps(reset: boolean = false) {
if (reset) {
console.log('Should swtich');
this.defaultValues();
}
@@ -123,7 +144,14 @@ export class CheckoutComponent implements OnInit {
this.currentNumberOfItems = 1;
this.displayItemsNumber = 1;
this.currentPoints = points;
this.currentPrice = price.toLocaleString().replace('.', ',');
this.stepOne = true;
this.currentPrice = this.bookPriceString();
}
private bookPrice(): number {
return this._book.av[0].price.value.value;
}
private bookPriceString(): string {
return this._book.av[0].price.value.value.toLocaleString().replace('.', ',');
}
}

View File

@@ -60,7 +60,6 @@ export class CustomerSearchComponent implements OnInit {
}
navigateToRoute(route: string) {
console.log('change route', route);
this.store.dispatch(new ChangeCurrentRoute(route));
this.router.navigate([route]);
}
@@ -102,7 +101,6 @@ export class CustomerSearchComponent implements OnInit {
}
createProcessIfDosntExists() {
console.log('createProcessIfDosntExists', this.searchError);
if (!this.searchError) {
this.loadProcesses();
if (this.processes.length === 0) {

View File

@@ -8,8 +8,6 @@
padding-left: 25px;
padding-right: 30px;
padding-bottom: 32px;
margin-right: 15px;
margin-left: 3px;
margin-top: 10px;
border-radius: 4px;
}

View File

@@ -9,8 +9,6 @@
padding-left: 25px;
padding-right: 30px;
padding-bottom: 32px;
margin-right: 15px;
margin-left: 3px;
margin-top: 10px;
border-radius: 4px;
}

View File

@@ -6,6 +6,14 @@
<div class="pt-3" (click)="selectProcess(process)">
<span class="process-name">{{ process.name }}</span>
</div>
<ng-container *ngIf="process.cart">
<div>
<img class="process-cart-icon" src="../../../assets/images/Shopping_Cart.svg">
</div>
<div class="pt-3">
<span class="process-cart-number">{{ cartCount }}</span>
</div>
</ng-container>
<div>
<a (click)="deleteProcess(process)">
<img class="process-delete-icon" src="/assets/images/close.svg">

View File

@@ -6,7 +6,7 @@
.grid-container {
display: grid;
grid-template-columns: min-content max-content min-content;
grid-template-columns: min-content max-content max-content max-content min-content;
grid-column-gap: 1vh;
height: 36px;
padding-top: 2px;
@@ -17,6 +17,11 @@
margin-top: 6px;
}
.process-cart-icon {
margin-top: 6px;
width: 19px;
}
.process-leading-icon {
width: 25px;
}
@@ -35,7 +40,14 @@
}
.process-name {
font-size: 17px;
font-size: 15px;
font-weight: bold;
color: $color-active;
margin-top: 5px;
}
.process-cart-number {
font-size: 15px;
font-weight: bold;
color: $color-active;
margin-top: 5px;

View File

@@ -3,6 +3,7 @@ import { Process } from 'src/app/core/models/process.model';
import { Router } from '@angular/router';
import { Store } from '@ngxs/store';
import { DeleteProcess, SelectProcess } from 'src/app/core/store/actions/process.actions';
import { Cart } from '../../core/models/cart.model';
@Component({
selector: 'app-process-tab',
@@ -13,6 +14,7 @@ export class ProcessTabComponent implements OnInit {
@Input() process: Process;
@Input() processes: Array<Process>;
cartCount = 0;
constructor(
private store: Store,
@@ -29,6 +31,11 @@ export class ProcessTabComponent implements OnInit {
}
ngOnInit() {
if (this.process.cart) {
this.process.cart.forEach((items: Cart) => {
this.cartCount += items.quantity;
});
}
}
}

View File

@@ -6,8 +6,6 @@
grid-gap: 7vh;
background-color: white;
padding: 24px;
margin-right: 15px;
margin-left: 3px;
margin-top: 10px;
border-radius: 5px;
}

View File

@@ -6,5 +6,6 @@
</div>
<button class="btn" (click)="openModal()">Open checkout</button>
<app-checkout #checkout (closed)="cartActionCompleted($event)"></app-checkout>
<!-- <app-shopping-cart-feedback #feedback></app-shopping-cart-feedback> -->
<ng-container *ngIf="item">
<app-checkout #checkout (closed)="cartActionCompleted($event)" [book]="item"></app-checkout>
</ng-container>

View File

@@ -8,8 +8,6 @@
padding-left: 25px;
padding-right: 30px;
padding-bottom: 32px;
margin-right: 15px;
margin-left: 3px;
margin-top: 10px;
border-radius: 4px;
color: white;

View File

@@ -0,0 +1,6 @@
import { ItemDTO } from 'cat-service';
export interface Cart {
book: ItemDTO;
quantity: number;
}

View File

@@ -1,6 +1,7 @@
import { Breadcrumb } from './breadcrumb.model';
import { Search } from './search.model';
import { User } from './user.model';
import { Cart } from './cart.model';
export interface Process {
id: number;
@@ -11,4 +12,5 @@ export interface Process {
breadcrumbs: Breadcrumb[];
search: Search;
users: User[];
cart: Cart[]
}

View File

@@ -9,7 +9,6 @@ export interface User {
invoice_address: Address;
shop: boolean;
payement_method: string;
cart?: Product[];
poossible_addresses: Address[];
}

View File

@@ -1,5 +1,7 @@
import { Process } from '../../models/process.model';
import { Search } from '../../models/search.model';
import { ItemDTO } from 'cat-service';
import { Breadcrumb } from '../../models/breadcrumb.model';
export const ADD_PROCESS = '[PROCESS] Add';
export const DELETE_PROCESS = '[PROCESS] Delete';
@@ -8,6 +10,7 @@ export const CHANGE_CURRENT_ROUTE = '[PROCESS] Change current route';
export const ADD_SEARCH = '[PROCESS] Add search';
export const SEARCH_USER = '[PROCESS] Search for user';
export const SET_USER_NAME = '[PROCESS] Set the users name in tab';
export const SET_CART = '[PROCESS] Set cart data for user';
export class AddProcess {
static readonly type = ADD_PROCESS;
@@ -50,3 +53,9 @@ export class SethUserName {
constructor(public payload: string) {}
}
export class SetCartData {
static readonly type = SET_CART;
constructor(public quantity: number, public payload: ItemDTO, public breadcrumb: Breadcrumb) {}
}

View File

@@ -4,6 +4,7 @@ import * as actions from '../actions/process.actions';
import { UserService } from '../../services/user.service';
import { User } from '../../models/user.model';
import { Breadcrumb } from '../../models/breadcrumb.model';
import { Cart } from '../../models/cart.model';
export class ProcessStateModel {
processes: Process[];
@@ -216,7 +217,6 @@ export class ProcessState {
name: payload,
path:'/customer-search-result'
}
]
}
} else {
@@ -261,4 +261,61 @@ export class ProcessState {
processes: [...newProcessState]
});
}
@Action(actions.SetCartData)
setCartData(ctx: StateContext<ProcessStateModel>, { quantity , payload, breadcrumb }: actions.SetCartData) {
const state = ctx.getState();
const newProcessState = state.processes.map(
(process: Process) => {
if (process.selected === true) {
let currentCart = process.cart ? process.cart : [];
const itemExists = currentCart.filter((item: Cart) => item.book.id === payload.id);
if (itemExists.length > 0) {
// Update item in cart
currentCart = currentCart.map((item: Cart) => {
if (item.book.id === payload.id) {
return {
quantity: item.quantity + quantity,
book: payload
};
}
return item;
});
return {
...process,
breadcrumbs: [
breadcrumb
],
cart: [
...currentCart
],
};
} else {
// Add new item to cart
return {
...process,
breadcrumbs: [
breadcrumb
],
cart: [
...currentCart,
{
quantity: quantity,
book: payload
}
],
};
}
} else {
return process;
}
}
);
ctx.patchState({
...state,
processes: [...newProcessState]
});
}
}

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="19px" viewBox="0 0 20 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 52.2 (67145) - http://www.bohemiancoding.com/sketch -->
<title>Shopping_Cart</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
<g id="UC1_11_Hugendubel_Instoreapp_Kunden_Kundesuche_1" transform="translate(-78.000000, -109.000000)" fill="#172062" stroke="#172062">
<path d="M84.00632,123.807692 C84.1972541,124.124617 84.3076923,124.493573 84.3076923,124.884615 C84.3076923,126.038462 83.3461538,127 82.1923077,127 C81.0384615,127 80.0769231,126.038462 80.0769231,124.884615 C80.0769231,123.730769 81.0384615,122.769231 82.1923077,122.769231 C82.2451751,122.769231 82.2976389,122.771249 82.3496249,122.775213 L83.2307692,120.538462 L82.2307692,111.076923 L79,111.076923 L79,110 L82.6923077,110 C82.9615385,110 83.1923077,110.192308 83.2307692,110.461538 L83.4123195,112.153846 L96.4615385,112.153846 C96.7692308,112.153846 97,112.384615 97,112.692308 L97,118 C97,118.269231 96.8076923,118.461538 96.5769231,118.5 L84.1364469,121.10119 L83.5,122.692308 L94.3461538,122.692308 L94.3461538,122.840609 C94.5185376,122.794089 94.6990907,122.769231 94.8846154,122.769231 C96.0384615,122.769231 97,123.730769 97,124.884615 C97,126.038462 96.0384615,127 94.8846154,127 C93.7307692,127 92.7692308,126.038462 92.7692308,124.884615 C92.7692308,124.493573 92.879669,124.124617 93.0706031,123.807692 L84.00632,123.807692 Z M83.5278515,113.230769 L84.2531293,119.991395 L95.9230769,117.576923 L95.9230769,113.230769 L83.5278515,113.230769 Z M94.8846154,123.807692 C94.3076923,123.807692 93.8076923,124.269231 93.8076923,124.884615 C93.8076923,125.5 94.2692308,125.961538 94.8846154,125.961538 C95.5,125.961538 95.9615385,125.5 95.9615385,124.884615 C95.9615385,124.269231 95.4615385,123.807692 94.8846154,123.807692 Z M82.1923077,123.807692 C81.6153846,123.807692 81.1153846,124.269231 81.1153846,124.884615 C81.1153846,125.5 81.5769231,125.961538 82.1923077,125.961538 C82.8076923,125.961538 83.2692308,125.5 83.2692308,124.884615 C83.2692308,124.269231 82.7692308,123.807692 82.1923077,123.807692 Z" id="Shopping_Cart"></path>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.3 KiB