mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-31 09:37:15 +01:00
Merged in feature/HIMA-53-create-shopping-cart-screen (pull request #30)
[HIMA-53] Cart component
This commit is contained in:
@@ -11,6 +11,7 @@ import { SearchResultsComponent } from './components/search-results/search-resul
|
||||
import { ProductDetailsComponent } from './components/product-details/product-details.component';
|
||||
import { BarcodeSearchComponent } from './modules/barcode-search/barcode-search.component';
|
||||
import { NewsletterSignupComponent } from './modules/newsletter-signup/newsletter-signup.component';
|
||||
import { CartReviewComponent } from './modules/cart/components/cart-review/cart-review.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/dashboard', pathMatch: 'full' },
|
||||
@@ -23,7 +24,8 @@ const routes: Routes = [
|
||||
{ path: 'product-details/:id', component: ProductDetailsComponent },
|
||||
{ path: 'article-scan', component: BarcodeSearchComponent },
|
||||
{ path: 'newsletter', component: NewsletterSignupComponent },
|
||||
{ path: 'debug', loadChildren: './modules/debug/debug.module#DebugModule' }
|
||||
{ path: 'debug', loadChildren: './modules/debug/debug.module#DebugModule' },
|
||||
{ path: 'cart', component: CartReviewComponent },
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
|
||||
@@ -36,7 +36,7 @@ import { BreadcrumbsState } from './core/store/state/breadcrumbs.state';
|
||||
import { FilterState } from './core/store/state/filter.state';
|
||||
import { CheckoutComponent } from './components/checkout/checkout.component';
|
||||
import { ModalComponent } from './shared/components/modal/modal.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
const states = [FeedState, ProcessState, BreadcrumbsState, FilterState];
|
||||
|
||||
@@ -70,7 +70,7 @@ export function _feedServiceEndpointProviderFactory(conf: ConfigService) {
|
||||
ProductCardComponent,
|
||||
ProductDetailsComponent,
|
||||
CheckoutComponent,
|
||||
ModalComponent
|
||||
ModalComponent,
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
@@ -83,7 +83,8 @@ export function _feedServiceEndpointProviderFactory(conf: ConfigService) {
|
||||
NgxsLoggerPluginModule,
|
||||
CatServiceModule,
|
||||
FeedServiceModule,
|
||||
FormsModule
|
||||
FormsModule,
|
||||
ReactiveFormsModule
|
||||
],
|
||||
providers: [
|
||||
{
|
||||
|
||||
@@ -26,7 +26,7 @@ export class BreadcrumbsComponent implements OnInit {
|
||||
getBreadcrumbsFromCurentProcess(processes: Process[]) {
|
||||
const currentProcess = processes.find(p => p.selected === true);
|
||||
if (currentProcess) {
|
||||
this.currentRoute = `/${currentProcess.currentRoute}`;
|
||||
this.currentRoute = `${currentProcess.currentRoute}`;
|
||||
this.breadcrumbs = currentProcess.breadcrumbs;
|
||||
this.bredcrumbDots = currentProcess.breadcrumbs.length > 3;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
<span class="process-name">{{ process.name }}</span>
|
||||
</div>
|
||||
<ng-container *ngIf="process.cart">
|
||||
<div>
|
||||
<div (click)="openCart()">
|
||||
<img class="process-cart-icon" src="../../../assets/images/Shopping_Cart.svg">
|
||||
</div>
|
||||
<div class="pt-3">
|
||||
|
||||
@@ -2,8 +2,10 @@ import { Component, OnInit, Input } from '@angular/core';
|
||||
import { Process } from 'src/app/core/models/process.model';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store } from '@ngxs/store';
|
||||
import { DeleteProcess, SelectProcess, PreventProductLoad } from 'src/app/core/store/actions/process.actions';
|
||||
import { DeleteProcess, SelectProcess, PreventProductLoad, ChangeCurrentRoute } from '../../core/store/actions/process.actions';
|
||||
import { Cart } from '../../core/models/cart.model';
|
||||
import { AddBreadcrumb } from '../../core/store/actions/process.actions';
|
||||
import { Breadcrumb } from '../../core/models/breadcrumb.model';
|
||||
|
||||
@Component({
|
||||
selector: 'app-process-tab',
|
||||
@@ -39,4 +41,15 @@ export class ProcessTabComponent implements OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
openCart() {
|
||||
const newBread: Breadcrumb = {
|
||||
name: 'Warenkorb',
|
||||
path: 'cart'
|
||||
}
|
||||
|
||||
this.store.dispatch(new AddBreadcrumb(newBread));
|
||||
this.store.dispatch(new ChangeCurrentRoute('cart'));
|
||||
this.router.navigate(['cart']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,5 +17,5 @@ export interface Process {
|
||||
itemsDTO: ItemDTO[];
|
||||
selectedItem: ItemDTO;
|
||||
preventLoading: boolean;
|
||||
editUser: User;
|
||||
activeUser: User;
|
||||
}
|
||||
|
||||
@@ -10,12 +10,13 @@ export const SELECT_PROCESS = '[PROCESS] Select';
|
||||
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_ACTIVE_USER = '[PROCESS] Set active user in tab';
|
||||
export const SET_CART = '[PROCESS] Set cart data for user';
|
||||
export const PREVENT_PRODUCT_LOAD = '[POCESS] Prevent product load';
|
||||
export const ALLOW_PRODUCT_LOAD = '[POCESS] Allow product load';
|
||||
export const ADD_USER = '[PROCESS] Add new user to store';
|
||||
export const SET_EDIT_USER = '[PROCESS] User which data will be updated';
|
||||
export const ADD_BREADCRUMB = '[PROCESS] Add breadcrumb';
|
||||
|
||||
export class AddProcess {
|
||||
static readonly type = ADD_PROCESS;
|
||||
@@ -53,10 +54,10 @@ export class SearchUser {
|
||||
constructor(public payload: string) {}
|
||||
}
|
||||
|
||||
export class SethUserName {
|
||||
static readonly type = SET_USER_NAME;
|
||||
export class SetActiveUser {
|
||||
static readonly type = SET_ACTIVE_USER;
|
||||
|
||||
constructor(public payload: string) {}
|
||||
constructor(public payload: User) {}
|
||||
}
|
||||
|
||||
export class SetCartData {
|
||||
@@ -83,3 +84,9 @@ export class SetUserDetails {
|
||||
|
||||
constructor(public payload: User) {}
|
||||
}
|
||||
|
||||
export class AddBreadcrumb {
|
||||
static readonly type = ADD_BREADCRUMB;
|
||||
|
||||
constructor(public payload: Breadcrumb) {}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,13 @@ export class ProcessState {
|
||||
}
|
||||
|
||||
@Selector()
|
||||
static getEditUser(state: ProcessStateModel) {
|
||||
return state.processes.find(t => t.selected === true).editUser;
|
||||
static getActiveUser(state: ProcessStateModel) {
|
||||
return state.processes.find(t => t.selected === true).activeUser;
|
||||
}
|
||||
|
||||
@Selector()
|
||||
static getCart(state: ProcessStateModel) {
|
||||
return state.processes.find(t => t.selected === true).cart;
|
||||
}
|
||||
|
||||
@Action(actions.AddProcess)
|
||||
@@ -289,13 +294,13 @@ export class ProcessState {
|
||||
});
|
||||
}
|
||||
|
||||
@Action(actions.SethUserName)
|
||||
setUserName(ctx: StateContext<ProcessStateModel>, { payload }: actions.SethUserName) {
|
||||
@Action(actions.SetActiveUser)
|
||||
setActiveUser(ctx: StateContext<ProcessStateModel>, { payload }: actions.SetActiveUser) {
|
||||
const state = ctx.getState();
|
||||
const newProcessState = state.processes.map(
|
||||
(process: Process) => {
|
||||
if (process.selected === true) {
|
||||
return { ...process, name: payload };
|
||||
return { ...process, name: payload.name, activeUser: payload };
|
||||
} else {
|
||||
return process;
|
||||
}
|
||||
@@ -497,7 +502,7 @@ export class ProcessState {
|
||||
if (process.selected === true) {
|
||||
return {
|
||||
...process,
|
||||
editUser: payload,
|
||||
activeUser: payload,
|
||||
breadcrumbs: [
|
||||
...process.breadcrumbs,
|
||||
{
|
||||
@@ -512,4 +517,20 @@ export class ProcessState {
|
||||
)
|
||||
});
|
||||
}
|
||||
|
||||
@Action(actions.AddBreadcrumb)
|
||||
addBreadcrumb(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddBreadcrumb) {
|
||||
const state = ctx.getState();
|
||||
ctx.patchState({
|
||||
...state,
|
||||
processes: state.processes.map(
|
||||
process => {
|
||||
if (process.selected === true) {
|
||||
return {...process, breadcrumbs: [...process.breadcrumbs, payload]};
|
||||
}
|
||||
return {...process};
|
||||
}
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
18
src/app/modules/cart/cart-modul.ts
Normal file
18
src/app/modules/cart/cart-modul.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||
|
||||
|
||||
import { SharedModule } from 'src/app/shared/shared.module';
|
||||
import { CartReviewComponent } from './components/cart-review/cart-review.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
CartReviewComponent
|
||||
],
|
||||
exports: [
|
||||
CartReviewComponent
|
||||
],
|
||||
imports: [CommonModule, FormsModule, ReactiveFormsModule, SharedModule]
|
||||
})
|
||||
export class CartModule {}
|
||||
@@ -0,0 +1,78 @@
|
||||
<div class="cart-container">
|
||||
<div class="cart-content">
|
||||
|
||||
<div class="cart-list">
|
||||
<div class="cart-title">
|
||||
<span>Warenkorb</span>
|
||||
</div>
|
||||
<div class="cart-description">
|
||||
<span>Überprüfen Sie die Details.</span>
|
||||
</div>
|
||||
<form [formGroup]="invoiceForm">
|
||||
<div class="line"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="placeholder form-control-placeholder" for="invoice_addrees">Rechnungsadresse</label>
|
||||
<input type="text" id="invoice_addrees" class="input form-control" formControlName="invoice_addrees" required #invoicelInput>
|
||||
<a class="inline-btn" >Ändern</a>
|
||||
</div>
|
||||
|
||||
<div class="line"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="placeholder form-control-placeholder" for="notification_type">Benachrichtigung</label>
|
||||
<input type="text" id="notification_type" class="input form-control" formControlName="notification_type" required #notificationInput>
|
||||
<a class="inline-btn" (click)="redirecrtToUserDetails()">Ändern</a>
|
||||
</div>
|
||||
</form>
|
||||
<div class="line"></div>
|
||||
<div class="delivery-title">
|
||||
<img class="img" src="../../../../../assets/images/truck_Icon.svg" alt="truck">
|
||||
<h2>Versand</h2>
|
||||
</div>
|
||||
<form [formGroup]="deliveryForm">
|
||||
<div class="line"></div>
|
||||
|
||||
<div class="form-group">
|
||||
<label class="placeholder form-control-placeholder" for="delivery_addrees">Lieferadresse</label>
|
||||
<input type="text" id="delivery_addrees" class="input form-control" formControlName="delivery_addrees" required #deliveryInput>
|
||||
<a class="inline-btn">Ändern</a>
|
||||
</div>
|
||||
</form>
|
||||
<div class="cart-row" *ngFor="let book of books; let i = index">
|
||||
<div class="line"></div>
|
||||
<div class="row-content">
|
||||
<img src="{{ book.imgUrl }}" alt="book">
|
||||
<span class="book-title">{{ book.book.pr.name }}</span>
|
||||
<div class="order-details">
|
||||
<span><img class="order-book-icon" src="../../../../../assets/images/Book_Icon.svg" alt="book-icon"> {{ book.book.pr.manufacturer }} I {{ book.book.pr.contributors }}</span>
|
||||
<span class="order-details-delivery-info">DHL I Lieferung 18.01.</span>
|
||||
</div>
|
||||
<span class="price">{{ book.price }} {{ book.currency }}</span>
|
||||
<div class="dropdown_container">
|
||||
<div (click)="openDropdown(i)" class="dropdown-selected-text" id="drop_txt_{{i}}">
|
||||
<span class="">{{ book.quantity }}</span>
|
||||
<div class="open-icon" id="drop_img_{{i}}"></div>
|
||||
</div>
|
||||
<div class="dropdown-options" id="drop_{{i}}">
|
||||
<ul>
|
||||
<li *ngFor="let item of possibleItems" (click)="setNumberOfItems(item, i, book)">{{ item }}</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<a class="btn" (click)="recalculate()">Ändern</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="cart-footer">
|
||||
<div class="overview">
|
||||
<span class="items">{{ displayItemsNumber }} Artikel I {{ currentPoints }} Lesepunkte</span>
|
||||
<div class="overview-price-container">
|
||||
<span class="overview-price">Zwischensumme {{ booksTotalSumString }} {{ currency }}</span>
|
||||
<span class="overview-tax">ohne Versandkosten</span>
|
||||
</div>
|
||||
<a class="btn">Weiter</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,385 @@
|
||||
@import "../../../../../assets/scss/variables";
|
||||
|
||||
.cart-container {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px 0px 10px 0px #dce2e9;
|
||||
height: 745px;
|
||||
|
||||
display: grid;
|
||||
grid-template-rows: min-content min-content 1fr min-content;
|
||||
}
|
||||
|
||||
.cart-title {
|
||||
padding-top: 40px;
|
||||
font-weight: bold;
|
||||
font-size: 26px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.cart-description {
|
||||
font-size: 22px;
|
||||
padding-top: 15px;
|
||||
text-align: center;
|
||||
padding-bottom: 30px;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background-image: url('../../../../../assets/images/Line.svg');
|
||||
background-repeat: repeat-x;
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
.cart-content {
|
||||
|
||||
|
||||
.cart-list {
|
||||
width: 100%;
|
||||
height: 637px;
|
||||
overflow-y: scroll;
|
||||
|
||||
.row-content {
|
||||
margin-bottom: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.cart-footer {
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px -2px 24px 0px #dce2e9;
|
||||
height: 108px;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
||||
|
||||
.form-group {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 75%;
|
||||
padding: 15px 0;
|
||||
caret-color: $hima-button-color;
|
||||
border: none;
|
||||
font-size: 16px;
|
||||
color: #000000;
|
||||
text-align: left;
|
||||
line-height: 21px;
|
||||
padding-left: 3%;
|
||||
padding-right: 7%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
border:none;
|
||||
}
|
||||
|
||||
input:disabled {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
text-align: left;
|
||||
line-height: 21px;
|
||||
padding-left: 15px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.inline-btn {
|
||||
padding-right: 5px;
|
||||
width: 100px;
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: $hima-button-color;
|
||||
text-align: left;
|
||||
line-height: 21px;
|
||||
text-align: right;
|
||||
display: block;
|
||||
padding-right: 20px;
|
||||
}
|
||||
|
||||
.delivery-title{
|
||||
padding: 25px 15px 10px 15px;
|
||||
text-align: left;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
h2 {
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
color: #000000;
|
||||
text-align: center;
|
||||
line-height: 21px;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 17px;
|
||||
width: 27px;
|
||||
display: block;
|
||||
padding-right: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.row-content {
|
||||
margin-top: 5px 0px;
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-align: left;
|
||||
|
||||
img {
|
||||
height: 39px;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
.book-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: 112px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.order-details {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
height: 50px;
|
||||
width: 215px;
|
||||
position: relative;
|
||||
top: 13px;
|
||||
|
||||
.order-book-icon {
|
||||
height: 18px;
|
||||
width: 13px;
|
||||
position: relative;
|
||||
top: 2px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
span {
|
||||
font-size: 16px;
|
||||
text-align: left;
|
||||
line-height: 25px;
|
||||
width: 100%;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&-delivery-info {
|
||||
font-weight: bold;
|
||||
}
|
||||
}
|
||||
|
||||
.price {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
.dropdown_container {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
width: 35px;
|
||||
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
img {
|
||||
height: 9px;
|
||||
width: 17px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.dropdown-selected-text {
|
||||
padding: 5px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
&-active {
|
||||
background-color: #E9EDF9;
|
||||
}
|
||||
|
||||
.open-icon {
|
||||
background-image: url('../../../../../assets/images/Arrow_Down_2.svg');
|
||||
height: 9px;
|
||||
width: 17px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 5px 4px;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
background-image: url('../../../../../assets/images/Arrow_Up.svg');
|
||||
height: 9px;
|
||||
width: 17px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
padding: 5px 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-options {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
position: fixed;
|
||||
top: 220px;
|
||||
z-index: 10;
|
||||
display: none;
|
||||
cursor: pointer;
|
||||
text-align: left;
|
||||
right: 115px;
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
padding: 15px 10px;
|
||||
margin: 0;
|
||||
background-color: #ffffff;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0px -2px 24px 0px #dce2e9;
|
||||
padding: 15px 0;
|
||||
width: 60px;
|
||||
|
||||
li {
|
||||
padding: 7px 10px;
|
||||
font-weight: 300;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
display: block;
|
||||
|
||||
&:hover {
|
||||
background-color: #E9EDF9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #f70400;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.overview {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
justify-items: center;
|
||||
width: 95%;
|
||||
|
||||
.items {
|
||||
font-size: 16px;
|
||||
color: rgba(167, 185, 203, 1);
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.overview-price-container {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
justify-items: center;
|
||||
flex-direction: column;
|
||||
|
||||
.overview-price {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.overview-tax {
|
||||
font-size: 14px;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
|
||||
.btn {
|
||||
font-family: 'Open Sans';
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
background-color: $hima-button-color;
|
||||
cursor: pointer;
|
||||
text-align: center;
|
||||
border-radius: 25px;
|
||||
color: #ffffff;
|
||||
width: 111px;
|
||||
border: none;
|
||||
padding: 14px 5px 14px 5px;
|
||||
}
|
||||
}
|
||||
|
||||
// OLD IPADS
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
|
||||
}
|
||||
|
||||
// OLD IPADS LANDSCAPE
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 1) {
|
||||
.row-content {
|
||||
margin-left: 15px;
|
||||
justify-content: space-between;
|
||||
|
||||
.btn {
|
||||
margin-right: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RETINA IPADS LANDSCAPE
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1366px) and (orientation: landscape) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.row-content {
|
||||
margin-left: 15px;
|
||||
justify-content: space-between;
|
||||
|
||||
.btn {
|
||||
margin-right: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// RETINA IPADS
|
||||
@media only screen and (min-device-width: 768px) and (max-device-width: 1024px) and (-webkit-min-device-pixel-ratio: 2) {
|
||||
.row-content {
|
||||
margin-left: 15px;
|
||||
justify-content: space-between;
|
||||
|
||||
.btn {
|
||||
margin-right: 36px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { CartReviewComponent } from './cart-review.component';
|
||||
|
||||
describe('CartComponent', () => {
|
||||
let component: CartReviewComponent;
|
||||
let fixture: ComponentFixture<CartReviewComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ CartReviewComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(CartReviewComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,223 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { FormGroup, Validators, FormBuilder } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { Store, Select } from '@ngxs/store';
|
||||
import { Observable } from 'rxjs';
|
||||
import { ProcessState } from '../../../../core/store/state/process.state';
|
||||
import { User } from '../../../../core/models/user.model';
|
||||
import { ChangeCurrentRoute, AddBreadcrumb } from '../../../../core/store/actions/process.actions';
|
||||
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
|
||||
import { ItemDTO, CatImageService } from 'cat-service';
|
||||
import { Cart } from '../../../../core/models/cart.model';
|
||||
|
||||
const points = 60;
|
||||
|
||||
export interface BookData {
|
||||
book: ItemDTO;
|
||||
quantity: number;
|
||||
price: string;
|
||||
currency: string;
|
||||
imgUrl: string;
|
||||
}
|
||||
@Component({
|
||||
selector: 'app-cart',
|
||||
templateUrl: './cart-review.component.html',
|
||||
styleUrls: ['./cart-review.component.scss']
|
||||
})
|
||||
export class CartReviewComponent implements OnInit {
|
||||
@Select(ProcessState.getActiveUser) user$: Observable<User>;
|
||||
@Select(ProcessState.getCart) cart$: Observable<Cart[]>;
|
||||
|
||||
|
||||
user: User;
|
||||
invoiceForm: FormGroup;
|
||||
deliveryForm: FormGroup;
|
||||
|
||||
items = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
|
||||
possibleItems = [1, 2, 3, 4];
|
||||
books: BookData[] = [];
|
||||
|
||||
currentNumberOfItems = 1;
|
||||
displayItemsNumber = 0;
|
||||
currentPrice = '';
|
||||
currentPoints = 0;
|
||||
currency = 'EUR';
|
||||
booksTotalSumString = '';
|
||||
booksTotalSum = 0;
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
private fb: FormBuilder,
|
||||
private router: Router,
|
||||
private catImageService: CatImageService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.invoiceForm = this.buildInvoiceForm(this.fb);
|
||||
this.deliveryForm = this.buildDeliveryForm(this.fb);
|
||||
this.user$.subscribe((user: User) => {
|
||||
if (user) {
|
||||
this.processUserData(user);
|
||||
} else {
|
||||
this.setInputData('invoice_addrees', 'Karl Schneier I Kazmairstraße 34, 80339 München', this.invoiceForm);
|
||||
this.setInputData('notification_type', 'Email', this.invoiceForm);
|
||||
this.setInputData('delivery_addrees', 'Karl Schneier I Kazmairstraße 34, 80339 München', this.deliveryForm);
|
||||
}
|
||||
});
|
||||
|
||||
this.cart$.subscribe((cart: Cart[]) => {
|
||||
if (cart) {
|
||||
this.processCartData(cart);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private processCartData(cart: Cart[]) {
|
||||
let totalSum = 0;
|
||||
let totalQuantity = 0;
|
||||
cart.forEach(async(bookInCart: Cart) => {
|
||||
totalSum += bookInCart.book.av[0].price.value.value * bookInCart.quantity;
|
||||
totalQuantity += bookInCart.quantity;
|
||||
const currency = bookInCart.book.av[0].price.value.currency;
|
||||
const formatedPrice = (+Math.round(bookInCart.book.av[0].price.value.value * 100) / 100).toFixed(2).toLocaleString().replace('.', ',');
|
||||
await this.catImageService.getImageUrl(bookInCart.book.pr.ean).subscribe((url: string) => {
|
||||
this.books.push(
|
||||
{
|
||||
book: bookInCart.book,
|
||||
quantity: bookInCart.quantity,
|
||||
currency: currency,
|
||||
price: formatedPrice,
|
||||
imgUrl: url
|
||||
}
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
this.displayItemsNumber = totalQuantity;
|
||||
this.currentPoints = totalQuantity * points;
|
||||
this.booksTotalSum = totalSum;
|
||||
this.booksTotalSumString = (+Math.round(totalSum * 100) / 100).toFixed(2).toLocaleString().replace('.', ',');
|
||||
}
|
||||
|
||||
private processUserData(user: User) {
|
||||
this.user = user;
|
||||
const invoiceAddress = `${user.invoice_address.street} ${user.invoice_address.zip} ${user.invoice_address.city}`;
|
||||
const deliveryAddress = `${user.delivery_addres.street} ${user.delivery_addres.zip} ${user.delivery_addres.city}`;
|
||||
this.setInputData('invoice_addrees', invoiceAddress ? invoiceAddress : deliveryAddress, this.invoiceForm);
|
||||
this.setInputData('notification_type', 'Email', this.invoiceForm);
|
||||
this.setInputData('delivery_addrees', deliveryAddress, this.deliveryForm);
|
||||
}
|
||||
|
||||
redirecrtToUserDetails() {
|
||||
if (this.user) {
|
||||
const newBread: Breadcrumb = {
|
||||
name: 'Kundendetails',
|
||||
path: 'customer-edit/' + this.user.id
|
||||
}
|
||||
|
||||
this.store.dispatch(new AddBreadcrumb(newBread));
|
||||
const currentRoute = 'customer-edit/' + this.user.id;
|
||||
this.store.dispatch(new ChangeCurrentRoute(currentRoute));
|
||||
this.router.navigate([currentRoute]);
|
||||
}
|
||||
}
|
||||
|
||||
setNumberOfItems (numberOfItems: number, id: number, book: BookData) {
|
||||
const updatedBooks = this.books.map((bookToUpdate: BookData) => {
|
||||
if (bookToUpdate.book.id === book.book.id) {
|
||||
bookToUpdate.quantity = numberOfItems;
|
||||
return bookToUpdate;
|
||||
}
|
||||
|
||||
return bookToUpdate;
|
||||
});
|
||||
|
||||
this.books = updatedBooks;
|
||||
this.openDropdown(id);
|
||||
}
|
||||
|
||||
recalculate() {
|
||||
let totalSum = 0;
|
||||
let totalQuantity = 0;
|
||||
|
||||
this.books.forEach((book: BookData) => {
|
||||
totalSum += book.book.av[0].price.value.value * book.quantity;
|
||||
totalQuantity += book.quantity;
|
||||
});
|
||||
|
||||
this.displayItemsNumber = totalQuantity;
|
||||
this.booksTotalSum = totalSum;
|
||||
this.booksTotalSumString = (+Math.round(totalSum * 100) / 100).toFixed(2).toLocaleString().replace('.', ',');
|
||||
this.currentPoints = totalQuantity * points;
|
||||
}
|
||||
|
||||
openDropdown(id: number) {
|
||||
// Close all other dropdowns
|
||||
for (let i = 0; i < this.items.length - 1; i++) {
|
||||
if (i !== id) {
|
||||
const ele = document.getElementById('drop_' + i);
|
||||
let text = document.getElementById('drop_txt_' + i);
|
||||
let icon = document.getElementById('drop_img_' + i);
|
||||
|
||||
if(text && text.classList.contains('dropdown-selected-text-active')) {
|
||||
text.classList.remove('dropdown-selected-text-active');
|
||||
icon.classList.remove('open-icon');
|
||||
icon.classList.add('close-icon');
|
||||
}
|
||||
|
||||
if (ele && ele.style.display && ele.style.display === 'flex') {
|
||||
icon.classList.remove('close-icon');
|
||||
icon.classList.add('open-icon');
|
||||
ele.style.display = 'none';
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
const ele = document.getElementById('drop_' + id);
|
||||
const text = document.getElementById('drop_txt_' + id);
|
||||
const icon = document.getElementById('drop_img_' + id);
|
||||
|
||||
if(text.classList.contains('dropdown-selected-text-active')) {
|
||||
text.classList.remove('dropdown-selected-text-active');
|
||||
} else {
|
||||
text.classList.add('dropdown-selected-text-active');
|
||||
}
|
||||
|
||||
if (!ele.style.display || ele.style.display === 'none') {
|
||||
// open
|
||||
var rect = icon.getBoundingClientRect();
|
||||
ele.style.top = (rect.top + 33) + 'px';
|
||||
ele.style.left = (rect.left - 30) + 'px';
|
||||
ele.style.display = 'flex';
|
||||
icon.classList.remove('open-icon');
|
||||
icon.classList.add('close-icon');
|
||||
} else {
|
||||
icon.classList.remove('close-icon');
|
||||
icon.classList.add('open-icon');
|
||||
ele.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
private setInputData (field: string, val: string, form: FormGroup) {
|
||||
form.get(field).patchValue(val);
|
||||
form.get(field).disable();
|
||||
}
|
||||
|
||||
get f() { return this.invoiceForm.controls; }
|
||||
|
||||
get deliveryF() { return this.deliveryForm.controls; }
|
||||
|
||||
private buildInvoiceForm(fb: FormBuilder) {
|
||||
return fb.group({
|
||||
invoice_addrees: ['', Validators.required],
|
||||
notification_type: ['', Validators.required],
|
||||
});
|
||||
}
|
||||
|
||||
private buildDeliveryForm(fb: FormBuilder) {
|
||||
return fb.group({
|
||||
delivery_addrees: ['', Validators.required],
|
||||
});
|
||||
}
|
||||
}
|
||||
1
src/app/modules/cart/index.ts
Normal file
1
src/app/modules/cart/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './components/cart-review/cart-review.component';
|
||||
@@ -19,6 +19,7 @@ import { DashboardModule } from './dashboard/dashboard.module';
|
||||
import { NewsletterSignupModule } from './newsletter-signup/newsletter-signup.module';
|
||||
import { ContentPageComponent } from '../pages/content/content.component';
|
||||
import { CustomerSearchModule } from './customer-search/customer-search.module';
|
||||
import { CartModule } from './cart/cart-modul';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
@@ -40,7 +41,8 @@ import { CustomerSearchModule } from './customer-search/customer-search.module';
|
||||
InfiniteScrollModule,
|
||||
BarcodeSearchModule,
|
||||
DashboardModule,
|
||||
CustomerSearchModule
|
||||
CustomerSearchModule,
|
||||
CartModule
|
||||
],
|
||||
exports: [
|
||||
HeaderComponent,
|
||||
|
||||
@@ -140,13 +140,6 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.line {
|
||||
height: 3px;
|
||||
width: 100%;
|
||||
background-image: url('../../../../../assets/images/Line.svg');
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
|
||||
.input {
|
||||
width: 75%;
|
||||
padding: 15px 0;
|
||||
|
||||
@@ -1,19 +1,13 @@
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ProcessState } from '../../../../core/store/state/process.state';
|
||||
import { Observable } from 'rxjs';
|
||||
import { Observable, forkJoin } from 'rxjs';
|
||||
import { User } from '../../../../core/models/user.model';
|
||||
import { Select, Store } from '@ngxs/store';
|
||||
import {
|
||||
FormGroup,
|
||||
FormBuilder,
|
||||
Validators,
|
||||
FormControl
|
||||
} from '@angular/forms';
|
||||
import {
|
||||
SethUserName,
|
||||
ChangeCurrentRoute
|
||||
} from '../../../../core/store/actions/process.actions';
|
||||
import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms';
|
||||
import { SetActiveUser, ChangeCurrentRoute } from '../../../../core/store/actions/process.actions';
|
||||
import { Router } from '@angular/router';
|
||||
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
|
||||
import { switchMap } from 'rxjs/operators';
|
||||
|
||||
@Component({
|
||||
selector: 'app-edit-customer-card',
|
||||
@@ -21,9 +15,12 @@ import { Router } from '@angular/router';
|
||||
styleUrls: ['./edit-customer-card.component.scss']
|
||||
})
|
||||
export class EditCustomerCardComponent implements OnInit {
|
||||
@Select(ProcessState.getEditUser) user$: Observable<User>;
|
||||
@Select(ProcessState.getActiveUser) user$: Observable<User>;
|
||||
@Select(ProcessState.getBreadcrumbs) breadcrumbs$: Observable<Breadcrumb[]>;
|
||||
|
||||
user: User;
|
||||
userForm: FormGroup;
|
||||
breadcrumbs: Breadcrumb[] = [];
|
||||
|
||||
constructor(
|
||||
private store: Store,
|
||||
@@ -51,6 +48,12 @@ export class EditCustomerCardComponent implements OnInit {
|
||||
this.setInputData('delivery_address', address);
|
||||
}
|
||||
});
|
||||
|
||||
this.breadcrumbs$.subscribe((breadcrumbs: Breadcrumb[]) => {
|
||||
if (breadcrumbs) {
|
||||
this.breadcrumbs = breadcrumbs;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
enableInput(field: string, input: any) {
|
||||
@@ -62,24 +65,35 @@ export class EditCustomerCardComponent implements OnInit {
|
||||
} else {
|
||||
// TODO: Save new data
|
||||
if (control.valid) {
|
||||
control.disable();
|
||||
if (!control.value) {
|
||||
control.setErrors({ required: true });
|
||||
} else {
|
||||
control.disable();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
back() {
|
||||
///customer-search-result
|
||||
const currentRoute = 'customer-search-result';
|
||||
this.store.dispatch(new ChangeCurrentRoute(currentRoute, true));
|
||||
this.router.navigate([currentRoute]);
|
||||
if (this.breadcrumbs.length >= 3 &&
|
||||
this.breadcrumbs[this.breadcrumbs.length -2].name === 'Warenkorb'
|
||||
) {
|
||||
const currentRoute = 'cart';
|
||||
this.store.dispatch(new ChangeCurrentRoute(currentRoute, true));
|
||||
this.router.navigate([currentRoute]);
|
||||
} else {
|
||||
const currentRoute = 'customer-search-result';
|
||||
this.store.dispatch(new ChangeCurrentRoute(currentRoute, true));
|
||||
this.router.navigate([currentRoute]);
|
||||
}
|
||||
}
|
||||
|
||||
approve() {
|
||||
this.store.dispatch(new SethUserName(this.userForm.get('name').value));
|
||||
this.store.dispatch(new SetActiveUser(this.user));
|
||||
}
|
||||
|
||||
clear(field: string) {
|
||||
this.userForm.get(field).patchValue('');
|
||||
this.userForm.get(field).patchValue(null);
|
||||
this.userForm.get(field).setErrors(null);
|
||||
}
|
||||
|
||||
@@ -93,27 +107,13 @@ export class EditCustomerCardComponent implements OnInit {
|
||||
}
|
||||
|
||||
private buildForm(fb: FormBuilder) {
|
||||
return fb.group(
|
||||
{
|
||||
name: ['', Validators.required],
|
||||
email: ['', Validators.required],
|
||||
phone_number: ['', Validators.required],
|
||||
pay: ['', Validators.required],
|
||||
invoice_addrees: ['', Validators.required],
|
||||
delivery_address: ['', Validators.required]
|
||||
},
|
||||
{ validators: this.validateAllFormFields }
|
||||
);
|
||||
}
|
||||
|
||||
validateAllFormFields(formGroup: FormGroup) {
|
||||
Object.keys(formGroup.controls).forEach(field => {
|
||||
const control = formGroup.get(field);
|
||||
if (control instanceof FormControl) {
|
||||
control.markAsTouched({ onlySelf: true });
|
||||
} else if (control instanceof FormGroup) {
|
||||
this.validateAllFormFields(control);
|
||||
}
|
||||
return fb.group({
|
||||
name: ['', Validators.required],
|
||||
email: ['', Validators.required],
|
||||
phone_number: ['', Validators.required],
|
||||
pay: ['', Validators.required],
|
||||
invoice_addrees: ['', Validators.required],
|
||||
delivery_address: ['', Validators.required],
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
</div>
|
||||
<div class="user-actions">
|
||||
<a (click)="details(user)">Details</a>
|
||||
<a (click)="approve(user.name)" class="active">Vorgang zuweisen</a>
|
||||
<a (click)="approve(user)" class="active">Vorgang zuweisen</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { Select, Store } from '@ngxs/store';
|
||||
import { ProcessState } from '../../../../core/store/state/process.state';
|
||||
import { Observable } from 'rxjs';
|
||||
import { User } from '../../../../core/models/user.model';
|
||||
import { SethUserName, ChangeCurrentRoute, SetUserDetails } from '../../../../core/store/actions/process.actions';
|
||||
import { SetActiveUser, ChangeCurrentRoute, SetUserDetails } from '../../../../core/store/actions/process.actions';
|
||||
import { Router } from '@angular/router';
|
||||
|
||||
@Component({
|
||||
@@ -35,8 +35,8 @@ export class SearchCustomerResultComponent implements OnInit {
|
||||
this.router.navigate([currentRoute]);
|
||||
}
|
||||
|
||||
approve(name: string): void {
|
||||
this.store.dispatch(new SethUserName(name));
|
||||
approve(user: User): void {
|
||||
this.store.dispatch(new SetActiveUser(user));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user