Merge branch 'feature/HIMA-129-popup-after-vorgang-zugewiesen' into develop

This commit is contained in:
Eraldo Hasanaj
2019-03-08 16:43:32 +01:00
16 changed files with 1269 additions and 194 deletions

View File

@@ -6,4 +6,4 @@ export interface BookData {
price: string;
currency: string;
imgUrl: string;
}
}

View File

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

View File

@@ -14,6 +14,7 @@ export const ADD_SEARCH = '[PROCESS] Add search';
export const SEARCH_USER = '[PROCESS] Search for user';
export const SET_ACTIVE_USER = '[PROCESS] Set active user in tab';
export const SET_CART = '[PROCESS] Set cart data for user';
export const UPDATE_CART_ITEM_QUANTITY = '[PROCESS] update cart item quantity';
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';
@@ -82,6 +83,12 @@ export class SetCartData {
) {}
}
export class UpdateCartItemQuantity {
static readonly type = UPDATE_CART_ITEM_QUANTITY;
constructor(public quantity: number, public payload: number) {}
}
export class PreventProductLoad {
static readonly type = PREVENT_PRODUCT_LOAD;
}

View File

@@ -35,7 +35,7 @@ export class ProcessState {
constructor(
private usersService: UserService,
protected productService: ProductService
) { }
) {}
@Selector()
static getState(state: ProcessStateModel) {
@@ -71,11 +71,13 @@ export class ProcessState {
static getSelectedFilterItems(state: ProcessStateModel): FilterItem[] {
const selectedProcess = state.processes.find(t => t.selected === true);
const filterItems: FilterItem[] = [];
selectedProcess.selectedFilters.map(f => f.items.map(i => {
if (i.selected === true) {
filterItems.push(i);
}
}));
selectedProcess.selectedFilters.map(f =>
f.items.map(i => {
if (i.selected === true) {
filterItems.push(i);
}
})
);
return filterItems;
}
@@ -408,6 +410,32 @@ export class ProcessState {
});
}
@Action(actions.UpdateCartItemQuantity)
updateCartItemQuantity(
ctx: StateContext<ProcessStateModel>,
{ quantity, payload }: actions.UpdateCartItemQuantity
) {
const state = ctx.getState();
const newProcessState = state.processes.map((process: Process) => {
if (process.selected === true) {
return {
...process,
cart: process.cart.map((cart: Cart, index: number) => {
if (index === payload) {
return { ...cart, quantity: quantity };
}
return cart;
})
};
}
return process;
});
ctx.patchState({
...state,
processes: newProcessState
});
}
@Action(GetProducts)
getProducts(ctx: StateContext<ProcessStateModel>, { payload }: GetProducts) {
const state = ctx.getState();
@@ -445,14 +473,14 @@ export class ProcessState {
processes:
payload.skip === 0
? this.changeProducResultsForCurrentProcess(
state.processes,
items,
''
)
state.processes,
items,
''
)
: this.extendProducResultsForCurrentProcess(
state.processes,
items
)
state.processes,
items
)
});
}
});
@@ -658,15 +686,18 @@ export class ProcessState {
}
@Action(actions.ResetBreadcrumbsTo)
resetBreadCrumbs(ctx: StateContext<ProcessStateModel>, { payload }: actions.ResetBreadcrumbsTo) {
resetBreadCrumbs(
ctx: StateContext<ProcessStateModel>,
{ payload }: actions.ResetBreadcrumbsTo
) {
const state = ctx.getState();
ctx.patchState({
...state,
processes: state.processes.map(p => {
if (p.selected === true) {
return {...p, breadcrumbs: [payload]};
return { ...p, breadcrumbs: [payload] };
}
return {...p};
return { ...p };
})
});
}
@@ -768,7 +799,10 @@ export class ProcessState {
}
@Action(CurrentPageLoaded)
setCurrentPage(ctx: StateContext<ProcessStateModel>, { page }: CurrentPageLoaded) {
setCurrentPage(
ctx: StateContext<ProcessStateModel>,
{ page }: CurrentPageLoaded
) {
const state = ctx.getState();
ctx.patchState({
...state,
@@ -782,7 +816,10 @@ export class ProcessState {
}
@Action(actions.AddSelectedFilter)
addSelectedFilterToCurrentProcess(ctx: StateContext<ProcessStateModel>, { payload }: actions.AddSelectedFilter) {
addSelectedFilterToCurrentProcess(
ctx: StateContext<ProcessStateModel>,
{ payload }: actions.AddSelectedFilter
) {
const state = ctx.getState();
ctx.patchState({
...state,
@@ -790,7 +827,10 @@ export class ProcessState {
if (process.selected === true) {
let filters = [];
if (process.selectedFilters) {
filters = [...process.selectedFilters.filter(f => f.id !== payload.id), payload];
filters = [
...process.selectedFilters.filter(f => f.id !== payload.id),
payload
];
} else {
filters.push(payload);
}
@@ -802,20 +842,24 @@ export class ProcessState {
}
@Action(actions.RemoveSelectedFilter)
removeSelectedFilterFromCurrentProcess(ctx: StateContext<ProcessStateModel>, { payload }: actions.RemoveSelectedFilter) {
removeSelectedFilterFromCurrentProcess(
ctx: StateContext<ProcessStateModel>,
{ payload }: actions.RemoveSelectedFilter
) {
const state = ctx.getState();
const updatedProcesses = state.processes.map(process => {
if (process.selected === true) {
const updatedFilters = process.selectedFilters.map(
f => {
return {...f, items: f.items.map(i => {
const updatedFilters = process.selectedFilters.map(f => {
return {
...f,
items: f.items.map(i => {
if (i.id === payload.id && i.selected === true) {
return <FilterItem>{ ...i, selected: false };
}
return i;
})};
}
);
})
};
});
return { ...process, selectedFilters: updatedFilters };
}
return process;

View File

@@ -40,8 +40,7 @@ import { LoadingModule, ModalModule, ButtonModule } from '@libs/ui';
SearchResultsComponent,
ProductCardComponent,
ProductDetailsComponent,
CheckoutComponent,
ProductCardLoadingComponent,
ProductCardLoadingComponent
],
imports: [
CommonModule,
@@ -70,7 +69,7 @@ import { LoadingModule, ModalModule, ButtonModule } from '@libs/ui';
MenuComponent,
BreadcrumbsComponent,
InfiniteScrollModule,
ProcessModule,
ProcessModule
]
})
export class ComponentsModule {}

View File

@@ -0,0 +1,210 @@
<app-modal id="customer-select-modal">
<div class="edit-modal" *ngIf="stepOne">
<div class="header">
<h1>Wie möchten Sie den Artikel erhalten?</h1>
<img
(click)="closeModal()"
class="close-icon"
src="../../../assets/images/close.svg"
alt="close"
/>
</div>
<div class="body">
<div class="option">
<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"
>{{ totalCartPrice }} {{ currency }}</span
>
<!-- <app-button class="modal-btn" (action)="selectedAction('mitnehmen')">Auswählen</app-button> -->
<app-button class="modal-btn">Auswählen</app-button>
</div>
<div class="option">
<img
class="img"
src="../../../assets/images/Package_Icon.svg"
alt="package"
/>
<h2>Abholung</h2>
<span class="description description-take-away"
>Möchten Sie den Artikel in einer unserer Fillialen abholen?</span
>
<div
class="dropdown-select-text"
(click)="openDropdown(dropdown)"
#selectedText
[class.dropdown-select-text-active]="displayDropdown"
>
<span class="location location-take-away">{{
currentLocation.name
}}</span>
<img
class="dropdown-icon"
src="../../../assets/images/Arrow_Down_2.svg"
alt="arrow"
*ngIf="!displayDropdown"
/>
<img
class="dropdown-icon"
src="../../../assets/images/Arrow_Up.svg"
alt="arrow"
*ngIf="displayDropdown"
/>
</div>
<span class="location location-date-take-away"
>Lieferdatum {{ currentPickUpDate }}</span
>
<div class="location location-dropdown" #dropdown>
<ul>
<li
*ngFor="let item of locations; let i = index"
(click)="selectLocation(i, dropdown)"
>
{{ item.name }}
</li>
</ul>
</div>
<span class="price price-take-away"
>{{ totalCartPrice }} {{ currency }}</span
>
<!-- <app-button class="modal-btn" (action)="selectedAction('abholung')">Auswählen</app-button> -->
<app-button class="modal-btn">Auswählen</app-button>
</div>
<div class="option">
<img
class="img"
src="../../../assets/images/truck_Icon.svg"
alt="truck"
/>
<h2>Versand</h2>
<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"
>{{ totalCartPrice }} {{ currency }}</span
>
<app-button
[primary]="true"
class="modal-btn"
(action)="selectedAction('versand')"
>Auswählen</app-button
>
</div>
</div>
</div>
<div class="customer-select-modal" *ngIf="!stepOne">
<div class="header">
<h1>Vorgang wurde dem Kunden zugewiesen</h1>
<img
(click)="closeModal()"
class="close-icon"
src="../../../assets/images/close.svg"
alt="close"
/>
</div>
<div class="modal-body">
<div class="body-heading">
<img
(click)="closeModal()"
class="close-icon"
src="../../../assets/images/{{ stepTwoImgType }}"
alt="truck"
/>
<h1>Versand</h1>
</div>
<div class="line"></div>
<div class="body-content">
<ng-container *ngFor="let item of (cart | async); let i = index">
<div class="content-item">
<img src="{{ getImageUrl(item.book.pr.ean) | async }}" alt="book" />
<span class="book-title">{{ item.book.pr.name }}</span>
<div class="order-details">
<span
><img
class="order-book-icon"
src="../../../../../assets/images/Book_Icon.svg"
alt="book-icon"
/>
{{ item.book.pr.manufacturer }} I
{{ item.book.pr.contributors }}</span
>
<span class="order-details-delivery-info"
>DHL I Lieferung 18.01.</span
>
</div>
<span class="price">{{ item.price }} {{ item.currency }}</span>
<div class="dropdown_container">
<div
(click)="openDropdown(dropdown)"
class="dropdown-selected-text"
[class.dropdown-selected-text-active]="displayDropdown"
>
<span class="">{{ item.quantity }}</span>
<img
class="dropdown-icon"
src="../../../assets/images/Arrow_Down_2.svg"
alt="arrow"
*ngIf="!displayDropdown"
/>
<img
class="dropdown-icon"
src="../../../assets/images/Arrow_Up.svg"
alt="arrow"
*ngIf="displayDropdown"
/>
</div>
<div class="dropdown-options" #dropdown>
<ul>
<li
*ngFor="let item of possibleItems"
(click)="setNumberOfItems(i, item, dropdown)"
>
{{ item }}
</li>
</ul>
</div>
</div>
<app-button (action)="switchSteps(true)">Ändern</app-button>
</div>
</ng-container>
</div>
<div class="line bottom-line"></div>
<div class="overview">
<span class="items"
>{{ displayItemsNumber }} Artikel I
{{ currentPoints }} Lesepunkte</span
>
<div class="overview-price-container">
<span class="overview-price"
>Zwischensumme {{ totalCartPrice }} {{ currency }}</span
>
<span class="overview-tax">ohne Versandkosten</span>
</div>
</div>
</div>
<div class="modal-footer">
<app-button (action)="asignUserToProcess()">Weiter einkaufen</app-button>
<app-button [primary]="true" (action)="itemsConfirmed()"
>Warenkorb</app-button
>
</div>
</div>
</app-modal>

View File

@@ -0,0 +1,466 @@
.edit-modal,
.customer-select-modal {
font-family: 'Open Sans';
line-height: 21px;
margin: 16px 0;
display: flex;
align-items: center;
flex-direction: column;
h1 {
font-size: 20px;
font-weight: bold;
}
.header {
.close-icon {
position: absolute;
top: 25px;
right: 25px;
height: 21px;
}
.close-icon:hover {
cursor: pointer;
}
}
}
.edit-modal {
height: 479px;
width: 737px;
justify-content: center;
.header {
padding-top: 20px;
}
.body {
width: 100%;
height: 100%;
display: flex;
justify-content: space-around;
align-items: center;
text-align: center;
.option {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100%;
.description {
font-size: 16px;
max-width: 193px;
margin-bottom: 25px;
&-take-away {
position: relative;
top: 12px;
}
&-take-now {
position: relative;
top: 30px;
}
&-delivery {
position: relative;
top: 9px;
}
}
h2 {
font-size: 26px;
font-weight: bold;
position: absolute;
top: 156px;
}
.title-take-now {
width: 153px;
line-height: 32px;
}
.img {
display: block;
position: absolute;
top: 112px;
}
.dropdown-icon {
height: 9px;
width: 17px;
}
.check {
height: 12px;
width: 16px;
padding-right: 5px;
}
.price {
font-size: 20px;
font-weight: bold;
// margin-bottom: 20px;
&-take-away {
position: relative;
top: 28px;
}
&-take-now {
position: relative;
top: 57px;
}
&-order {
position: relative;
top: 33px;
}
}
.modal-btn {
position: absolute;
bottom: 25px;
}
.delivery {
display: flex;
justify-content: space-between;
align-items: center;
width: 165px;
font-size: 16px;
cursor: pointer;
text-align: left;
position: relative;
top: 7px;
&-date {
font-size: 14px;
font-weight: 300;
width: 165px;
position: relative;
top: 10px;
}
}
.location {
display: flex;
justify-content: space-between;
align-items: center;
width: 135px;
font-size: 16px;
font-weight: bold;
cursor: pointer;
text-align: left;
&-take-away {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
}
&-date-take-away {
font-size: 14px;
font-weight: 300;
cursor: default;
width: 165px;
text-align: left;
padding-top: 3px;
position: relative;
top: 5px;
left: 7px;
}
&-dropdown {
display: flex;
flex-direction: column;
position: fixed;
top: 344px;
left: 224px;
z-index: 10;
display: none;
cursor: pointer;
width: 225px;
background-color: #ffffff;
border-radius: 5px;
box-shadow: 0px -2px 24px 0px #dce2e9;
overflow: hidden;
ul {
list-style: none;
width: 100%;
padding: 15px 10px;
margin: 0;
li {
// padding: 5px 0 5px 20px;
padding: 7px 10px;
font-weight: 300;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: block;
&:hover {
background-color: #e9edf9;
}
}
}
span {
padding: 5px 0 5px 20px;
font-weight: 300;
width: 100%;
&:hover {
background-color: #e9edf9;
}
}
}
}
.dropdown-select-text {
display: flex;
justify-content: center;
align-items: center;
position: relative;
top: 9px;
padding: 5px;
&-active {
background-color: #e9edf9;
}
&:hover {
cursor: pointer;
}
}
}
}
}
.customer-select-modal {
max-height: 594px;
width: 737px;
justify-content: flex-start;
.header {
h1 {
margin-top: 30px;
}
}
.modal-body {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
flex-direction: column;
margin-top: 15px;
.body-heading {
display: flex;
justify-content: flex-start;
align-items: center;
width: 100%;
margin-bottom: 8px;
img {
height: 16px;
width: 26px;
margin-right: 13px;
margin-top: 3px;
margin-left: 25px;
}
}
}
.line {
height: 3px;
width: 100%;
background-image: url('../../../../../assets/images/Line.svg');
background-repeat: repeat-x;
}
.body-content {
display: grid;
width: 97%;
overflow: scroll;
max-height: 450px;
.content-item {
margin-top: 15px;
display: flex;
justify-content: space-around;
align-items: center;
text-align: left;
margin-bottom: 15px;
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: 8px;
}
span {
font-size: 16px;
text-align: left;
line-height: 25px;
width: 100%;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&-delivery-info {
font-weight: 600;
}
}
}
.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;
font-weight: 600;
&-active {
background-color: #e9edf9;
}
}
.dropdown-options {
display: flex;
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;
}
}
}
}
}
}
.bottom-line {
margin-top: 30px;
}
.overview {
display: flex;
justify-content: space-between;
justify-items: center;
width: 93%;
margin-top: 30px;
.items {
font-size: 16px;
font-weight: 600;
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;
}
}
}
.modal-footer {
display: flex;
justify-content: flex-end;
align-items: center;
width: 93%;
margin-top: 30px;
}
}

View File

@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CustomerSelectConfirmationComponent } from './customer-select-confirmation.component';
describe('CustomerSelectConfirmationComponent', () => {
let component: CustomerSelectConfirmationComponent;
let fixture: ComponentFixture<CustomerSelectConfirmationComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CustomerSelectConfirmationComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CustomerSelectConfirmationComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,153 @@
import {
Component,
OnInit,
OnDestroy,
Output,
EventEmitter
} from '@angular/core';
import { ModalService } from '@libs/ui';
import { Store } from '@ngxs/store';
import { Observable } from 'rxjs';
import { ProcessState } from 'apps/sales/src/app/core/store/state/process.state';
import { Cart } from 'apps/sales/src/app/core/models/cart.model';
import { CatImageService, ItemDTO } from 'cat-service';
import { map } from 'rxjs/operators';
import { BookData } from 'apps/sales/src/app/core/models/book-data.model';
import { UpdateCartItemQuantity } from 'apps/sales/src/app/core/store/actions/process.actions';
import { Router } from '@angular/router';
@Component({
selector: 'app-customer-select-confirmation',
templateUrl: './customer-select-confirmation.component.html',
styleUrls: ['./customer-select-confirmation.component.scss']
})
export class CustomerSelectConfirmationComponent implements OnInit, OnDestroy {
id = 'customer-select-modal';
cart: Observable<BookData[]>;
displayDropdown = false;
possibleItems = [1, 2, 3, 4];
currentPoints = 60;
_totalCartPrice = 0;
stepOne = false;
stepTwoImgType = 'truck_Icon.svg';
get totalCartPrice() {
if (this._totalCartPrice) {
return this._totalCartPrice
.toFixed(2)
.toLocaleString()
.replace('.', ',');
}
}
// Step one mock data
locations = [
{ name: 'München Karlsplatz', date: '01.05.2019' },
{ name: 'München Marienplatz', date: '01.05.2019' },
{ name: 'München Ollenhauerstraße', date: '01.05.2019' },
{ name: 'München Pasing Bahnhofsplatz', date: '01.05.2019' },
{ name: 'München Theatinerstraße', date: '01.05.2019' }
];
currentLocation = this.locations[0];
currentPickUpDate = this.locations[0].date;
currency: string;
@Output() closed: EventEmitter<boolean> = new EventEmitter();
constructor(
private modalService: ModalService,
private store: Store,
private catImageService: CatImageService,
private router: Router
) {}
ngOnInit() {
this.cart = this.store.select(ProcessState.getCart).pipe(
map((items: Cart[]) => {
if (items) {
return items.map((item: Cart) => {
this._totalCartPrice += this.bookPrice(item.book, item.quantity);
this.currency = item.book.av[0].price.value.currency;
return <BookData>{
book: item.book,
price: this.bookPriceString(item.book, item.quantity),
currency: item.book.av[0].price.value.currency,
quantity: item.quantity
};
});
}
return null;
})
);
}
ngOnDestroy() {}
openDialog() {
this.modalService.open(this.id);
}
closeModal() {
this.modalService.close(this.id);
}
openDropdown(element: any) {
this.toggleDropdown(element);
}
private toggleDropdown(element: any) {
element.style.display = this.displayDropdown ? 'none' : 'flex';
this.displayDropdown = !this.displayDropdown;
}
getImageUrl(ean: string): Observable<String> {
return this.catImageService.getImageUrl(ean);
}
setNumberOfItems(index: number, quantity: number, element: any) {
this._totalCartPrice = 0;
this.store.dispatch(new UpdateCartItemQuantity(quantity, index));
this.toggleDropdown(element);
}
private bookPriceString(book: ItemDTO, quantity: number): string {
const formatedPrice = (
+Math.round(book.av[0].price.value.value * quantity * 100) / 100
).toFixed(2);
return formatedPrice.toLocaleString().replace('.', ',');
}
private bookPrice(book: ItemDTO, quantity: number): number {
return +Math.round(book.av[0].price.value.value * quantity * 100) / 100;
}
asignUserToProcess() {
this.closeModal();
this.closed.emit(false);
}
itemsConfirmed() {
this.closeModal();
this.closed.emit(true);
}
switchSteps(reset: boolean = false) {
this.displayDropdown = false;
this.stepOne = !this.stepOne;
}
selectedAction(action: string) {
if (action === 'mitnehmen') {
this.stepTwoImgType = 'Take_now.svg';
} else if (action === 'abholung') {
this.stepTwoImgType = 'Package_Icon.svg';
} else {
this.stepTwoImgType = 'truck_Icon.svg';
}
this.switchSteps();
}
selectLocation(locationIndx: number, dropdown: any) {
this.currentLocation = this.locations[locationIndx];
this.currentPickUpDate = this.currentLocation.date;
this.toggleDropdown(dropdown);
}
}

View File

@@ -28,9 +28,14 @@
</div>
<div class="user-actions">
<app-button (action)="details(user)">Details</app-button>
<app-button [primary]="true" (action)="approve(user)">Vorgang zuweisen</app-button>
<app-button [primary]="true" (action)="approve(user)"
>Vorgang zuweisen</app-button
>
</div>
</div>
<app-customer-select-confirmation
(closed)="userChecked(user, $event)"
></app-customer-select-confirmation>
</div>
<div class="note">
<span class="note-text">

View File

@@ -1,10 +1,17 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
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 { SetActiveUser, ChangeCurrentRoute, SetUserDetails } from '../../../../core/store/actions/process.actions';
import {
SetActiveUser,
ChangeCurrentRoute,
SetUserDetails,
AddBreadcrumb
} from '../../../../core/store/actions/process.actions';
import { Router } from '@angular/router';
import { CustomerSelectConfirmationComponent } from '../customer-select-confirmation/customer-select-confirmation.component';
import { Breadcrumb } from 'apps/sales/src/app/core/models/breadcrumb.model';
@Component({
selector: 'app-search-customer-result',
@@ -12,15 +19,13 @@ import { Router } from '@angular/router';
styleUrls: ['./search-customer-result.component.scss']
})
export class SearchCustomerResultComponent implements OnInit {
@Select(ProcessState.getUsers) users$: Observable<User[]>;
@ViewChild(CustomerSelectConfirmationComponent)
customerSelectConfirmationDialog: CustomerSelectConfirmationComponent;
users: User[] = [];
constructor(
private store: Store,
private router: Router,
) { }
constructor(private store: Store, private router: Router) {}
ngOnInit() {
this.users$.subscribe((users: User[]) => {
@@ -36,7 +41,20 @@ export class SearchCustomerResultComponent implements OnInit {
}
approve(user: User): void {
this.store.dispatch(new SetActiveUser(user));
this.customerSelectConfirmationDialog.openDialog();
}
userChecked(user: User, navigate: boolean) {
this.store.dispatch(new SetActiveUser(user));
if (navigate === true) {
const newBread: Breadcrumb = {
name: 'Warenkorb',
path: 'cart'
};
this.store.dispatch(new AddBreadcrumb(newBread));
this.store.dispatch(new ChangeCurrentRoute('cart'));
this.router.navigate(['cart']);
}
}
}

View File

@@ -13,13 +13,16 @@ import { SearchCustomerResultComponent } from './components/search-customer-resu
import { EditBillingAddressComponent } from './pages/edit-billing-address/edit-billing-address.component';
import { NewsletterSignupModule } from '../newsletter-signup/newsletter-signup.module';
import { RouterModule } from '@angular/router';
import {
import {
CardModule,
SearchInputModule,
InputModule,
LoadingModule,
ButtonModule
ButtonModule,
ModalModule
} from '@libs/ui';
import { CustomerSelectConfirmationComponent } from './components/customer-select-confirmation/customer-select-confirmation.component';
import { CheckoutComponent } from '../../components/checkout/checkout.component';
@NgModule({
declarations: [
@@ -29,7 +32,9 @@ import {
CustomerSearchComponent,
EditCustomerCardComponent,
BillingAddressComponent,
EditBillingAddressComponent
EditBillingAddressComponent,
CustomerSelectConfirmationComponent,
CheckoutComponent
],
exports: [
SearchCustomerResultComponent,
@@ -38,7 +43,9 @@ import {
CustomerSearchComponent,
EditCustomerCardComponent,
BillingAddressComponent,
EditBillingAddressComponent
EditBillingAddressComponent,
CustomerSelectConfirmationComponent,
CheckoutComponent
],
imports: [
CommonModule,
@@ -51,7 +58,8 @@ import {
SearchInputModule,
InputModule,
LoadingModule,
ButtonModule
ButtonModule,
ModalModule
]
})
export class CustomerSearchModule {}

View File

@@ -1,148 +1,271 @@
<div class="customer-edit-container" *ngIf="user">
<div class="customer-section">
<div><span class="customer-section-header">Bestellungen</span></div>
<div class="customer-section">
<div><span class="customer-section-header">Bestellungen</span></div>
</div>
<div class="customer-section-edit">
<div class="customer-section-edit-title">
<span>Kundendetails</span>
</div>
<div class="customer-section-edit">
<div class="customer-section-edit-title">
<span>Kundendetails</span>
</div>
<div class="align-center customer-section-edit-description">
<span>Sind Ihre Kundendaten korrekt?</span>
</div>
<div class="edit-wrapper">
<form [formGroup]="userForm">
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="name">Name</label>
<input type="text" id="name" class="input form-control" formControlName="name" [ngClass]="{ 'error-visible': f.name.errors }" required #nameInput>
</div>
<div class="line-actions">
<ng-container *ngIf="f.name.disabled">
<app-button (action)="enableInput('name', nameInput)">Ändern</app-button>
</ng-container>
<ng-container *ngIf="!f.name.disabled">
<img (click)="clear('name')" class="clear-icon" src="../../../assets/images/close.svg" alt="close" *ngIf="!f.name.errors">
<app-button (action)="enableInput('name', nameInput)">Ändern</app-button>
</ng-container>
<div *ngIf="f.name.errors" class="invalid-feedback">
<div>Name wird benötigt</div>
</div>
<div class="align-center customer-section-edit-description">
<span>Sind Ihre Kundendaten korrekt?</span>
</div>
<div class="edit-wrapper">
<form [formGroup]="userForm">
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="name"
>Name</label
>
<input
type="text"
id="name"
class="input form-control"
formControlName="name"
[ngClass]="{ 'error-visible': f.name.errors }"
required
#nameInput
/>
</div>
<div class="line-actions">
<ng-container *ngIf="f.name.disabled">
<app-button (action)="enableInput('name', nameInput)"
>Ändern</app-button
>
</ng-container>
<ng-container *ngIf="!f.name.disabled">
<img
(click)="clear('name')"
class="clear-icon"
src="../../../assets/images/close.svg"
alt="close"
*ngIf="!f.name.errors"
/>
<app-button (action)="enableInput('name', nameInput)"
>Ändern</app-button
>
</ng-container>
<div *ngIf="f.name.errors" class="invalid-feedback">
<div>Name wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="email">E-Mail</label>
<input type="text" id="email" class="input form-control" formControlName="email" [ngClass]="{ 'error-visible': f.email.errors }" required #emailInput>
</div>
<div class="line-actions">
<ng-container *ngIf="f.email.disabled">
<app-button (action)="enableInput('email', emailInput)">Ändern</app-button>
</ng-container>
<ng-container *ngIf="!f.email.disabled">
<img (click)="clear('email')" class="clear-icon" src="../../../assets/images/close.svg" alt="close" *ngIf="!f.email.errors">
<app-button (action)="enableInput('email', emailInput)">Speichern</app-button>
</ng-container>
<div *ngIf="f.email.errors" class="invalid-feedback">
<div>E-Mail wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="email"
>E-Mail</label
>
<input
type="text"
id="email"
class="input form-control"
formControlName="email"
[ngClass]="{ 'error-visible': f.email.errors }"
required
#emailInput
/>
</div>
<div class="line-actions">
<ng-container *ngIf="f.email.disabled">
<app-button (action)="enableInput('email', emailInput)"
>Ändern</app-button
>
</ng-container>
<ng-container *ngIf="!f.email.disabled">
<img
(click)="clear('email')"
class="clear-icon"
src="../../../assets/images/close.svg"
alt="close"
*ngIf="!f.email.errors"
/>
<app-button (action)="enableInput('email', emailInput)"
>Speichern</app-button
>
</ng-container>
<div *ngIf="f.email.errors" class="invalid-feedback">
<div>E-Mail wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="phone_number">Telefonnummer</label>
<input type="text" id="phone_number" class="input form-control" formControlName="phone_number" [ngClass]="{ 'error-visible': f.phone_number.errors }" required #phoneInput>
</div>
<div class="line-actions">
<ng-container *ngIf="f.phone_number.disabled">
<app-button (action)="enableInput('phone_number', phoneInput)">Ändern</app-button>
</ng-container>
<ng-container *ngIf="!f.phone_number.disabled">
<img (click)="clear('phone_number')" class="clear-icon" src="../../../assets/images/close.svg" alt="close" *ngIf="!f.phone_number.errors">
<app-button (action)="enableInput('phone_number', phoneInput)">Speichern</app-button>
</ng-container>
<div *ngIf="f.phone_number.errors" class="invalid-feedback">
<div>Telefonnummer wird benötigt</div>
</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label
class="placeholder form-control-placeholder"
for="phone_number"
>Telefonnummer</label
>
<input
type="text"
id="phone_number"
class="input form-control"
formControlName="phone_number"
[ngClass]="{ 'error-visible': f.phone_number.errors }"
required
#phoneInput
/>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="pay">Zahlungsart</label>
<input type="text" id="pay" class="input form-control" formControlName="pay" [ngClass]="{ 'error-visible': f.pay.errors }" required #payInput>
</div>
<div class="line-actions">
<ng-container *ngIf="f.pay.disabled">
<app-button (action)="enableInput('pay', payInput)">Ändern</app-button>
</ng-container>
<ng-container *ngIf="!f.pay.disabled">
<img (click)="clear('pay')" class="clear-icon" src="../../../assets/images/close.svg" alt="close" *ngIf="!f.pay.errors">
<app-button (action)="enableInput('pay', payInput)">Speichern</app-button>
</ng-container>
<div *ngIf="f.pay.errors" class="invalid-feedback">
<div>Zahlungsart wird benötigt</div>
</div>
<div class="line-actions">
<ng-container *ngIf="f.phone_number.disabled">
<app-button (action)="enableInput('phone_number', phoneInput)"
>Ändern</app-button
>
</ng-container>
<ng-container *ngIf="!f.phone_number.disabled">
<img
(click)="clear('phone_number')"
class="clear-icon"
src="../../../assets/images/close.svg"
alt="close"
*ngIf="!f.phone_number.errors"
/>
<app-button (action)="enableInput('phone_number', phoneInput)"
>Speichern</app-button
>
</ng-container>
<div *ngIf="f.phone_number.errors" class="invalid-feedback">
<div>Telefonnummer wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="invoice_addrees">Rechnungsadresse</label>
<input type="text" id="invoice_addrees" class="input form-control" formControlName="invoice_addrees" [ngClass]="{ 'error-visible': f.invoice_addrees.errors }" required #invoiceInput>
</div>
<div class="line-actions">
<app-button (action)="navigateToBillingAddress()">Ändern</app-button>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="pay"
>Zahlungsart</label
>
<input
type="text"
id="pay"
class="input form-control"
formControlName="pay"
[ngClass]="{ 'error-visible': f.pay.errors }"
required
#payInput
/>
</div>
<div class="line-actions">
<ng-container *ngIf="f.pay.disabled">
<app-button (action)="enableInput('pay', payInput)"
>Ändern</app-button
>
</ng-container>
<ng-container *ngIf="!f.pay.disabled">
<img
(click)="clear('pay')"
class="clear-icon"
src="../../../assets/images/close.svg"
alt="close"
*ngIf="!f.pay.errors"
/>
<app-button (action)="enableInput('pay', payInput)"
>Speichern</app-button
>
</ng-container>
<div *ngIf="f.pay.errors" class="invalid-feedback">
<div>Zahlungsart wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label class="placeholder form-control-placeholder" for="delivery_address">Lieferadresse</label>
<input type="text" id="delivery_address" class="input form-control" formControlName="delivery_address" [ngClass]="{ 'error-visible': f.delivery_address.errors }" required #deliveryInput>
</div>
<div class="line-actions">
<ng-container *ngIf="f.delivery_address.disabled">
<app-button (action)="enableInput('delivery_address', deliveryInput)">Ändern</app-button>
</ng-container>
<ng-container *ngIf="!f.delivery_address.disabled">
<img (click)="clear('delivery_address')" class="clear-icon" src="../../../assets/images/close.svg" alt="close" *ngIf="!f.delivery_address.errors">
<app-button (action)="enableInput('delivery_address', deliveryInput)">Speichern</app-button>
</ng-container>
<div *ngIf="f.delivery_address.errors" class="invalid-feedback">
<div>Lieferadresse wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label
class="placeholder form-control-placeholder"
for="invoice_addrees"
>Rechnungsadresse</label
>
<input
type="text"
id="invoice_addrees"
class="input form-control"
formControlName="invoice_addrees"
[ngClass]="{ 'error-visible': f.invoice_addrees.errors }"
required
#invoiceInput
/>
</div>
<div class="line-actions">
<app-button (action)="navigateToBillingAddress()"
>Ändern</app-button
>
</div>
</div>
<div class="line"></div>
<div class="form-group">
<div class="input-container">
<label
class="placeholder form-control-placeholder"
for="delivery_address"
>Lieferadresse</label
>
<input
type="text"
id="delivery_address"
class="input form-control"
formControlName="delivery_address"
[ngClass]="{ 'error-visible': f.delivery_address.errors }"
required
#deliveryInput
/>
</div>
<div class="line-actions">
<ng-container *ngIf="f.delivery_address.disabled">
<app-button
(action)="enableInput('delivery_address', deliveryInput)"
>Ändern</app-button
>
</ng-container>
<ng-container *ngIf="!f.delivery_address.disabled">
<img
(click)="clear('delivery_address')"
class="clear-icon"
src="../../../assets/images/close.svg"
alt="close"
*ngIf="!f.delivery_address.errors"
/>
<app-button
(action)="enableInput('delivery_address', deliveryInput)"
>Speichern</app-button
>
</ng-container>
<div *ngIf="f.delivery_address.errors" class="invalid-feedback">
<div>Lieferadresse wird benötigt</div>
</div>
</div>
<div class="line"></div>
<div class="btn-container">
<app-button (action)="back()">Zurück</app-button>
<app-button [primary]="true" (action)="approve()">Vorgang zuweisen</app-button>
</div>
</form>
</div>
</div>
<div class="line"></div>
<div class="btn-container">
<app-button (action)="back()">Zurück</app-button>
<app-button [primary]="true" (action)="approve()"
>Vorgang zuweisen</app-button
>
</div>
</form>
</div>
</div>
<app-customer-select-confirmation
(closed)="userChecked($event)"
></app-customer-select-confirmation>
</div>

View File

@@ -1,4 +1,4 @@
import { Component, OnInit } from '@angular/core';
import { Component, OnInit, ViewChild } from '@angular/core';
import { ProcessState } from '../../../../core/store/state/process.state';
import { Observable } from 'rxjs';
import { User } from '../../../../core/models/user.model';
@@ -11,6 +11,7 @@ import {
} from '../../../../core/store/actions/process.actions';
import { Router } from '@angular/router';
import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
import { CustomerSelectConfirmationComponent } from '../../components/customer-select-confirmation/customer-select-confirmation.component';
@Component({
selector: 'app-edit-customer-card',
@@ -20,6 +21,8 @@ import { Breadcrumb } from '../../../../core/models/breadcrumb.model';
export class EditCustomerCardComponent implements OnInit {
@Select(ProcessState.getActiveUser) user$: Observable<User>;
@Select(ProcessState.getBreadcrumbs) breadcrumbs$: Observable<Breadcrumb[]>;
@ViewChild(CustomerSelectConfirmationComponent)
customerSelectConfirmationDialog: CustomerSelectConfirmationComponent;
user: User;
userForm: FormGroup;
@@ -95,7 +98,21 @@ export class EditCustomerCardComponent implements OnInit {
}
approve() {
this.customerSelectConfirmationDialog.openDialog();
}
userChecked(navigate: boolean) {
this.store.dispatch(new SetActiveUser(this.user));
if (navigate === true) {
const newBread: Breadcrumb = {
name: 'Warenkorb',
path: 'cart'
};
this.store.dispatch(new AddBreadcrumb(newBread));
this.store.dispatch(new ChangeCurrentRoute('cart'));
this.router.navigate(['cart']);
}
}
clear(field: string) {

View File

@@ -1,22 +1,22 @@
/* tslint:disable */
import { EntityDTO } from './entity-dto';
import { TextDTO } from './text-dto';
import { SpecDTO } from './spec-dto';
import { TextDTO } from './text-dto';
import { AvailabilityDTO } from './availability-dto';
import { StockInfoDTO } from './stock-info-dto';
import { ShelfInfoDTO } from './shelf-info-dto';
export interface ItemDTO extends EntityDTO {
/**
* Texte
*/
te?: Array<TextDTO>;
/**
* Rang
*/
ra?: number;
/**
* Artikel / Produkttyp
*/
tp?: any;
/**
* Ist
*/
@@ -33,9 +33,9 @@ export interface ItemDTO extends EntityDTO {
sp?: Array<SpecDTO>;
/**
* Artikel / Produkttyp
* Texte
*/
tp?: any;
te?: Array<TextDTO>;
/**
* Verfügbarkeit

View File

@@ -6,16 +6,16 @@ import { OrderByDTO } from './order-by-dto';
*/
export interface QueryTokenDTO {
/**
* Katalogbereich
*/
catalogType?: any;
/**
* Lager PK
*/
stockId?: number;
/**
* Bezeichner
*/
friendlyName?: string;
/**
* Eingabewerte z.B. ("qs", "heller süden")
*/
@@ -32,9 +32,9 @@ export interface QueryTokenDTO {
fuzzy?: number;
/**
* Bezeichner
* Katalogbereich
*/
friendlyName?: string;
catalogType?: any;
/**
* Filter