mirror of
https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend
synced 2025-12-28 22:42:11 +01:00
Merge branch 'feature/1407-Checkout' of https://dev.azure.com/hugendubel/ISA/_git/ISA-Frontend into feature/1407-Checkout
This commit is contained in:
40
angular.json
40
angular.json
@@ -1856,6 +1856,46 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"@ui/spinner": {
|
||||
"projectType": "library",
|
||||
"root": "apps/ui/spinner",
|
||||
"sourceRoot": "apps/ui/spinner/src",
|
||||
"prefix": "ui",
|
||||
"architect": {
|
||||
"build": {
|
||||
"builder": "@angular-devkit/build-angular:ng-packagr",
|
||||
"options": {
|
||||
"tsConfig": "apps/ui/spinner/tsconfig.lib.json",
|
||||
"project": "apps/ui/spinner/ng-package.json"
|
||||
},
|
||||
"configurations": {
|
||||
"production": {
|
||||
"tsConfig": "apps/ui/spinner/tsconfig.lib.prod.json"
|
||||
}
|
||||
}
|
||||
},
|
||||
"test": {
|
||||
"builder": "@angular-devkit/build-angular:karma",
|
||||
"options": {
|
||||
"main": "apps/ui/spinner/src/test.ts",
|
||||
"tsConfig": "apps/ui/spinner/tsconfig.spec.json",
|
||||
"karmaConfig": "apps/ui/spinner/karma.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": {
|
||||
"builder": "@angular-devkit/build-angular:tslint",
|
||||
"options": {
|
||||
"tsConfig": [
|
||||
"apps/ui/spinner/tsconfig.lib.json",
|
||||
"apps/ui/spinner/tsconfig.spec.json"
|
||||
],
|
||||
"exclude": [
|
||||
"**/node_modules/**"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"defaultProject": "sales"
|
||||
|
||||
@@ -110,11 +110,17 @@
|
||||
{{ item?.unitPrice?.value?.value | currency: item?.unitPrice?.value?.currency:'code' }}
|
||||
</div>
|
||||
<div class="product-quantity">
|
||||
<page-quantity-control [ngModel]="item?.quantity" (ngModelChange)="updateItemQuantity(item, $event)"></page-quantity-control>
|
||||
<page-quantity-control
|
||||
[ngModel]="item?.quantity"
|
||||
(ngModelChange)="updateItemQuantity(item, $event)"
|
||||
[showSpinner]="showQuantityControlSpinnerItemId === item.id"
|
||||
></page-quantity-control>
|
||||
</div>
|
||||
<div>
|
||||
<button class="cta-edit" (click)="changeItem(item)">
|
||||
Ändern
|
||||
<button class="cta-edit" (click)="changeItem(item)" [disabled]="showChangeButtonSpinnerItemId">
|
||||
<ui-spinner [show]="showChangeButtonSpinnerItemId === item.id">
|
||||
Ändern
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -133,8 +139,10 @@
|
||||
</strong>
|
||||
<span class="shipping-cost-info">ohne Versandkosten</span>
|
||||
</div>
|
||||
<button class="cta-order" (click)="order()">
|
||||
Bestellen
|
||||
<button class="cta-order" (click)="order()" [disabled]="showOrderButtonSpinner">
|
||||
<ui-spinner [show]="showOrderButtonSpinner">
|
||||
Bestellen
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Component, ChangeDetectionStrategy } from '@angular/core';
|
||||
import { Component, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||
import { Router } from '@angular/router';
|
||||
import { ApplicationService } from '@core/application';
|
||||
import { AvailabilityService } from '@domain/availability';
|
||||
@@ -64,6 +64,10 @@ export class CheckoutReviewComponent {
|
||||
switchMap((processId) => this.domainCheckoutService.getCustomerFeatures({ processId }))
|
||||
);
|
||||
|
||||
showQuantityControlSpinnerItemId: number;
|
||||
showOrderButtonSpinner: boolean;
|
||||
showChangeButtonSpinnerItemId: number;
|
||||
|
||||
constructor(
|
||||
private domainCheckoutService: DomainCheckoutService,
|
||||
private applicationService: ApplicationService,
|
||||
@@ -71,10 +75,12 @@ export class CheckoutReviewComponent {
|
||||
private search: SearchService,
|
||||
private uiModal: UiModalService,
|
||||
private sso: SsoService,
|
||||
private router: Router
|
||||
private router: Router,
|
||||
private cdr: ChangeDetectorRef
|
||||
) {}
|
||||
|
||||
async changeItem(shoppingCartItem: ShoppingCartItemDTO) {
|
||||
this.showChangeButtonSpinnerItemId = shoppingCartItem.id;
|
||||
const item = await this.search
|
||||
.SearchSearch({
|
||||
input: { qs: shoppingCartItem.product.ean },
|
||||
@@ -177,6 +183,9 @@ export class CheckoutReviewComponent {
|
||||
break;
|
||||
}
|
||||
|
||||
this.showChangeButtonSpinnerItemId = undefined;
|
||||
this.cdr.markForCheck();
|
||||
|
||||
this.uiModal.open({
|
||||
content: PurchasingOptionsModalComponent,
|
||||
data: {
|
||||
@@ -191,6 +200,7 @@ export class CheckoutReviewComponent {
|
||||
}
|
||||
|
||||
async updateItemQuantity(shoppingCartItem: ShoppingCartItemDTO, quantity: number) {
|
||||
this.showQuantityControlSpinnerItemId = shoppingCartItem.id;
|
||||
const orderType = shoppingCartItem?.features?.orderType;
|
||||
let availability: AvailabilityDTO;
|
||||
|
||||
@@ -239,15 +249,17 @@ export class CheckoutReviewComponent {
|
||||
} else {
|
||||
// TODO: Set Prev Quantity
|
||||
}
|
||||
this.showQuantityControlSpinnerItemId = undefined;
|
||||
}
|
||||
|
||||
order() {
|
||||
// TODO: Check if Customer is Set
|
||||
// => If not navigate to customer search
|
||||
|
||||
this.showOrderButtonSpinner = true;
|
||||
this.domainCheckoutService.completeCheckout({ processId: this.applicationService.activatedProcessId }).subscribe(() => {
|
||||
this.applicationService.removeProcess(this.applicationService.activatedProcessId);
|
||||
this.applicationService.createProcess();
|
||||
this.showOrderButtonSpinner = false;
|
||||
this.router.navigate(['/cart', 'summary']);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { CheckoutQuantityControlModule } from '../shared/quantity-control/quanti
|
||||
import { ProductImageModule } from 'apps/cdn/product-image/src/public-api';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -18,6 +19,7 @@ import { FormsModule } from '@angular/forms';
|
||||
CheckoutQuantityControlModule,
|
||||
ProductImageModule,
|
||||
FormsModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [CheckoutReviewComponent],
|
||||
declarations: [CheckoutReviewComponent],
|
||||
|
||||
@@ -1,14 +1,42 @@
|
||||
<div class="card" *ngIf="orderData$ | async; let orderData">
|
||||
<div>
|
||||
<ui-icon class="check-icon" icon="check" size="36px"></ui-icon>
|
||||
</div>
|
||||
|
||||
<h1 class="order-header">Bestellbestätigung</h1>
|
||||
<p class="order-info">
|
||||
Nachfolgend erhalten Sie die Übersicht Ihrer Bestellung.
|
||||
Nachfolgend erhalten Sie <br />
|
||||
die Übersicht Ihrer Bestellung.
|
||||
</p>
|
||||
<div class="cta-print-wrapper">
|
||||
|
||||
<div class="row">
|
||||
<div class="order-customer">
|
||||
{{ orderData?.buyer | buyerName }}
|
||||
</div>
|
||||
<div class="grow"></div>
|
||||
<button class="cta-print">Drucken</button>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div class="order-customer"></div>
|
||||
<div class="grow"></div>
|
||||
<div class="sub-row">
|
||||
<span>Belegnummer</span>
|
||||
<strong>{{ orderData.orderNumber }}</strong>
|
||||
</div>
|
||||
<div class="sub-row between">
|
||||
<span>Zielfiliale</span>
|
||||
<strong>{{ orderData.targetBranch.name }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="sub-row">
|
||||
<span>Bestelldatum</span>
|
||||
<strong>{{ orderData.orderDate | date }}</strong>
|
||||
</div>
|
||||
<div class="sub-row between">
|
||||
<span>Adresse</span>
|
||||
<strong>{{ orderData.targetBranch | branchAddress }}</strong>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
</div>
|
||||
|
||||
@@ -2,8 +2,48 @@
|
||||
@apply block box-border;
|
||||
}
|
||||
|
||||
.cta-print-wrapper {
|
||||
.check-icon {
|
||||
@apply mx-auto text-green-700 pt-8;
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
.card {
|
||||
@apply bg-white rounded-card shadow-card;
|
||||
}
|
||||
|
||||
.order-header {
|
||||
@apply text-center text-3xl my-2 mb-2;
|
||||
}
|
||||
|
||||
.order-info {
|
||||
@apply text-center text-lg my-0 mb-2;
|
||||
}
|
||||
|
||||
.cta-print {
|
||||
@apply bg-transparent text-brand font-bold text-xl outline-none border-none;
|
||||
}
|
||||
|
||||
.order-customer {
|
||||
@apply font-bold text-2xl;
|
||||
}
|
||||
|
||||
.grow {
|
||||
@apply flex-grow;
|
||||
}
|
||||
|
||||
.row {
|
||||
@apply flex flex-row items-center mx-8 my-4;
|
||||
}
|
||||
|
||||
.sub-row {
|
||||
@apply flex flex-row flex-grow items-center w-1/2;
|
||||
}
|
||||
|
||||
.between {
|
||||
@apply justify-between;
|
||||
}
|
||||
|
||||
hr {
|
||||
height: 2px;
|
||||
@apply bg-disabled-customer;
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ import { NgModule } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
|
||||
import { CheckoutSummaryComponent } from './checkout-summary.component';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { PageCheckoutPipeModule } from '../pipes/page-checkout-pipe.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule],
|
||||
imports: [CommonModule, UiIconModule, PageCheckoutPipeModule],
|
||||
exports: [CheckoutSummaryComponent],
|
||||
declarations: [CheckoutSummaryComponent],
|
||||
})
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
.option-icon {
|
||||
margin-top: -5px;
|
||||
width: 80px;
|
||||
margin-top: -12px;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-top: -10px;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
@@ -7,9 +7,11 @@
|
||||
<span class="price"
|
||||
>{{ item.catalogAvailability?.price?.value?.value | currency: ' ' }} {{ item.catalogAvailability?.price?.value?.currency }}</span
|
||||
>
|
||||
|
||||
<div class="grow"></div>
|
||||
<span class="delivery">Versandkostenfrei</span>
|
||||
<span class="date">Versanddatum <strong>27.02.21</strong></span>
|
||||
<div class="grow"></div>
|
||||
|
||||
<div>
|
||||
<button type="button" class="select-option" (click)="select()">
|
||||
Auswählen
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
.option-icon {
|
||||
@apply text-ucla-blue mx-auto;
|
||||
width: 50px;
|
||||
width: 40px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
</div>
|
||||
<div class="quantity">
|
||||
<page-quantity-control
|
||||
[showSpinner]="purchasingOptionsModalStore.selectFetchingAvailability | async"
|
||||
[ngModel]="quantity$ | async"
|
||||
(ngModelChange)="purchasingOptionsModalStore.setQuantity($event)"
|
||||
></page-quantity-control>
|
||||
@@ -58,12 +59,20 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="actions" *ngIf="option$ | async; let option">
|
||||
<button class="cta-continue-shopping" [disabled]="(canAdd$ | async) === false" (click)="continue(true)">Weiter einkaufen</button>
|
||||
<button class="cta-continue-shopping" [disabled]="(canAdd$ | async) === false" (click)="continue(true)">
|
||||
<ui-spinner [show]="activeSpinner && activeSpinner === 'continue-shopping'">
|
||||
Weiter einkaufen
|
||||
</ui-spinner>
|
||||
</button>
|
||||
<button *ngIf="option === 'take-away'" class="cta-continue" [disabled]="(canAdd$ | async) === false" (click)="continue()">
|
||||
Reservieren
|
||||
<ui-spinner [show]="activeSpinner && activeSpinner === 'continue'">
|
||||
Reservieren
|
||||
</ui-spinner>
|
||||
</button>
|
||||
<button *ngIf="option !== 'take-away'" class="cta-continue" [disabled]="(canAdd$ | async) === false" (click)="continue()">
|
||||
Fortfahren
|
||||
<ui-spinner [show]="activeSpinner && activeSpinner === 'continue'">
|
||||
Fortfahren
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
}
|
||||
|
||||
.options-wrapper {
|
||||
@apply flex flex-row justify-evenly items-stretch;
|
||||
@apply flex flex-row justify-evenly items-stretch mt-2;
|
||||
}
|
||||
|
||||
.option-product-summary {
|
||||
@@ -72,6 +72,10 @@ img.thumbnail {
|
||||
|
||||
.cta-continue-shopping {
|
||||
@apply text-brand border-2 border-solid border-brand bg-white font-bold text-lg px-4 py-2 rounded-full;
|
||||
|
||||
::ng-deep.spin {
|
||||
@apply text-brand;
|
||||
}
|
||||
}
|
||||
|
||||
.cta-continue {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ApplicationService } from '@core/application';
|
||||
import { DomainCheckoutService } from '@domain/checkout';
|
||||
import { AddToShoppingCartDTO } from '@swagger/checkout';
|
||||
import { UiModalRef } from '@ui/modal';
|
||||
import { first, map, mergeMap } from 'rxjs/operators';
|
||||
import { delay, first, map, mergeMap } from 'rxjs/operators';
|
||||
import { PurchasingOptionsModalData } from './purchasing-options-modal.data';
|
||||
import { PurchasingOptionsModalStore } from './purchasing-options-modal.store';
|
||||
|
||||
@@ -34,6 +34,8 @@ export class PurchasingOptionsModalComponent {
|
||||
|
||||
readonly branch$ = this.purchasingOptionsModalStore.selectBranch;
|
||||
|
||||
activeSpinner: string;
|
||||
|
||||
constructor(
|
||||
public modalRef: UiModalRef<any, PurchasingOptionsModalData>,
|
||||
public purchasingOptionsModalStore: PurchasingOptionsModalStore,
|
||||
@@ -50,6 +52,8 @@ export class PurchasingOptionsModalComponent {
|
||||
}
|
||||
|
||||
async continue(navigate: boolean = false) {
|
||||
this.activeSpinner = navigate ? 'continue-shopping' : 'continue';
|
||||
|
||||
try {
|
||||
const processId = await this.purchasingOptionsModalStore.selectProcessId.pipe(first()).toPromise();
|
||||
const item = await this.item$.pipe(first()).toPromise();
|
||||
@@ -120,5 +124,6 @@ export class PurchasingOptionsModalComponent {
|
||||
} catch (error) {
|
||||
console.log('PurchasingOptionsModalComponent.continue', error);
|
||||
}
|
||||
this.activeSpinner = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ import { PickUpDropdownComponent } from './pick-up-option/pick-up-dropdown/pick-
|
||||
import { PageCheckoutPipeModule } from '../../pipes/page-checkout-pipe.module';
|
||||
import { ProductImageModule } from 'apps/cdn/product-image/src/public-api';
|
||||
import { CheckoutQuantityControlModule } from '../../shared/quantity-control/quantity-control.module';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -28,6 +29,7 @@ import { CheckoutQuantityControlModule } from '../../shared/quantity-control/qua
|
||||
PageCheckoutPipeModule,
|
||||
ProductImageModule,
|
||||
CheckoutQuantityControlModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [PurchasingOptionsModalComponent],
|
||||
declarations: [
|
||||
|
||||
@@ -18,6 +18,7 @@ interface PurchasingOptionsModalState {
|
||||
branch?: BranchDTO;
|
||||
processId?: number;
|
||||
availability?: AvailabilityDTO;
|
||||
fetchingAvailability?: boolean;
|
||||
availableOptions: PurchasingOptions[];
|
||||
availableBranches: BranchDTO[];
|
||||
quantity: number;
|
||||
@@ -64,6 +65,8 @@ export class PurchasingOptionsModalStore extends ComponentStore<PurchasingOption
|
||||
|
||||
readonly selectFilterResult = this.select((s) => s.filterResult);
|
||||
|
||||
readonly selectFetchingAvailability = this.select((s) => s.fetchingAvailability);
|
||||
|
||||
readonly selectOlaAvailability = this.select(
|
||||
(s): OLAAvailabilityDTO => ({
|
||||
status: s.availability?.availabilityType,
|
||||
@@ -249,6 +252,7 @@ export class PurchasingOptionsModalStore extends ComponentStore<PurchasingOption
|
||||
let availability$: Observable<AvailabilityDTO> = NEVER;
|
||||
|
||||
if (!isNullOrUndefined(item) && quantity > 0 && isString(option)) {
|
||||
this.patchState({ fetchingAvailability: true });
|
||||
switch (option) {
|
||||
case 'take-away':
|
||||
if (!isNullOrUndefined(branch)) {
|
||||
@@ -278,8 +282,13 @@ export class PurchasingOptionsModalStore extends ComponentStore<PurchasingOption
|
||||
}
|
||||
return availability$.pipe(
|
||||
tapResponse(
|
||||
(availability) => this.setAvailability(availability),
|
||||
() => this.setAvailability(null)
|
||||
(availability) => {
|
||||
this.setAvailability(availability);
|
||||
this.patchState({ fetchingAvailability: false });
|
||||
},
|
||||
() => {
|
||||
this.setAvailability(null), this.patchState({ fetchingAvailability: false });
|
||||
}
|
||||
)
|
||||
);
|
||||
})
|
||||
|
||||
13
apps/page/checkout/src/lib/pipes/branch-address.pipe.ts
Normal file
13
apps/page/checkout/src/lib/pipes/branch-address.pipe.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { BranchDTO } from '@swagger/checkout';
|
||||
|
||||
@Pipe({
|
||||
name: 'branchAddress',
|
||||
})
|
||||
export class BranchAddressPipe implements PipeTransform {
|
||||
transform(branch: BranchDTO, ...args: any[]): any {
|
||||
if (branch) {
|
||||
return `${branch?.address?.street} ${branch?.address?.streetNumber}, ${branch?.address?.zipCode} ${branch?.address?.city}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
19
apps/page/checkout/src/lib/pipes/buyer-name.pipe.ts
Normal file
19
apps/page/checkout/src/lib/pipes/buyer-name.pipe.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Pipe, PipeTransform } from '@angular/core';
|
||||
import { BuyerDTO } from '@swagger/checkout';
|
||||
|
||||
@Pipe({
|
||||
name: 'buyerName',
|
||||
})
|
||||
export class BuyerNamePipe implements PipeTransform {
|
||||
transform(buyer: BuyerDTO, ...args: any[]): any {
|
||||
if (buyer) {
|
||||
const organisationParts = [buyer?.organisation?.name].filter((f) => !!f);
|
||||
|
||||
const customerParts = [buyer?.lastName, buyer?.firstName].filter((f) => !!f);
|
||||
|
||||
return [organisationParts.join(), customerParts.join(' ')].filter((f) => !!f).join(' - ');
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BranchAddressPipe } from './branch-address.pipe';
|
||||
import { BuyerNamePipe } from './buyer-name.pipe';
|
||||
import { PayerAddressPipe } from './payer-address.pipe';
|
||||
import { PurchaseOptionIconPipe } from './purchase-option-icon.pipe';
|
||||
import { PurchaseOptionNamePipe } from './purchase-option-name.pipe';
|
||||
@@ -6,7 +8,23 @@ import { ShippingAddressPipe } from './shipping-address.pipe';
|
||||
import { TrimPipe } from './trim.pipe';
|
||||
|
||||
@NgModule({
|
||||
exports: [PayerAddressPipe, ShippingAddressPipe, TrimPipe, PurchaseOptionNamePipe, PurchaseOptionIconPipe],
|
||||
declarations: [PayerAddressPipe, ShippingAddressPipe, TrimPipe, PurchaseOptionNamePipe, PurchaseOptionIconPipe],
|
||||
exports: [
|
||||
PayerAddressPipe,
|
||||
ShippingAddressPipe,
|
||||
TrimPipe,
|
||||
PurchaseOptionNamePipe,
|
||||
PurchaseOptionIconPipe,
|
||||
BuyerNamePipe,
|
||||
BranchAddressPipe,
|
||||
],
|
||||
declarations: [
|
||||
PayerAddressPipe,
|
||||
ShippingAddressPipe,
|
||||
TrimPipe,
|
||||
PurchaseOptionNamePipe,
|
||||
PurchaseOptionIconPipe,
|
||||
BuyerNamePipe,
|
||||
BranchAddressPipe,
|
||||
],
|
||||
})
|
||||
export class PageCheckoutPipeModule {}
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
<div *ngIf="showDropdown" (click)="showDropdown = false" class="backdrop"></div>
|
||||
<div class="quantity-control-wrapper" *ngIf="quantity">
|
||||
<button class="current-quantity" type="button" (click)="showDropdown = true" *ngIf="!customInput">
|
||||
{{ quantity }}
|
||||
<ui-icon class="r90deg" size="14px" icon="arrow_head"></ui-icon>
|
||||
</button>
|
||||
<ui-spinner [show]="showSpinner">
|
||||
<button class="current-quantity" type="button" (click)="showDropdown = true" *ngIf="!customInput">
|
||||
{{ quantity }}
|
||||
<ui-icon class="r90deg" size="14px" icon="arrow_head"></ui-icon>
|
||||
</button>
|
||||
</ui-spinner>
|
||||
<input #quantity class="current-quantity" type="number" *ngIf="customInput" placeholder="..." />
|
||||
<div class="quantity-list" *ngIf="showDropdown">
|
||||
<button class="quantity-list-item del" type="button" (click)="close()">
|
||||
|
||||
@@ -33,6 +33,9 @@ export class QuantityControlComponent implements ControlValueAccessor {
|
||||
@Input()
|
||||
disabled: boolean;
|
||||
|
||||
@Input()
|
||||
showSpinner: boolean;
|
||||
|
||||
onChange = (_: number) => {};
|
||||
onTouched = () => {};
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
import { QuantityControlComponent } from './quantity-control.component';
|
||||
|
||||
@NgModule({
|
||||
imports: [CommonModule, UiIconModule],
|
||||
imports: [CommonModule, UiIconModule, UiSpinnerModule],
|
||||
exports: [QuantityControlComponent],
|
||||
declarations: [QuantityControlComponent],
|
||||
})
|
||||
|
||||
@@ -195,11 +195,10 @@
|
||||
</div>
|
||||
|
||||
<div class="center sticky-bottom">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled">
|
||||
<ui-spinner [show]="!control.enabled">
|
||||
Speichern
|
||||
</ng-container>
|
||||
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -188,11 +188,10 @@
|
||||
</div>
|
||||
|
||||
<div class="center sticky-bottom">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled">
|
||||
<ui-spinner [show]="!control.enabled">
|
||||
Speichern
|
||||
</ng-container>
|
||||
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -195,11 +195,10 @@
|
||||
</div>
|
||||
|
||||
<div class="center sticky-bottom">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled">
|
||||
<ui-spinner [show]="!control.enabled">
|
||||
Speichern
|
||||
</ng-container>
|
||||
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -192,11 +192,10 @@
|
||||
</div>
|
||||
|
||||
<div class="center sticky-bottom">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled" [ngSwitch]="control.enabled">
|
||||
<ng-container *ngSwitchCase="true">
|
||||
<button class="create-customer-submit" type="submit" [disabled]="control.invalid || control.disabled">
|
||||
<ui-spinner [show]="!control.enabled">
|
||||
Speichern
|
||||
</ng-container>
|
||||
<ui-icon class="spin" icon="loading" size="18px" *ngSwitchCase="false"></ui-icon>
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -78,3 +78,7 @@ page-customer-type-selector {
|
||||
|
||||
.organisation-header {
|
||||
}
|
||||
|
||||
::ng-deep.spin {
|
||||
@apply text-white;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import { AddressSelectionModalModule } from '../modals/address-selection-modal/a
|
||||
import { CantAddCustomerToCartModalModule } from '../modals/cant-add-customer-to-cart-modal/cant-add-customer-to-cart.module';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { UiCheckboxModule } from '@ui/checkbox';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@@ -29,6 +30,7 @@ import { UiCheckboxModule } from '@ui/checkbox';
|
||||
AddressSelectionModalModule,
|
||||
CantAddCustomerToCartModalModule,
|
||||
UiCheckboxModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [CustomerCreateBranchComponent, CustomerCreateGuestComponent, CustomerCreateOnlineComponent, CustomerCreateB2BComponent],
|
||||
declarations: [
|
||||
|
||||
@@ -129,12 +129,16 @@
|
||||
</div>
|
||||
|
||||
<div class="card-customer-footer">
|
||||
<button *ngIf="cartExists$ | async; else cartEmpty" class="cta-to-cart" (click)="continue()">
|
||||
Weiter zum Warenkorb
|
||||
<button *ngIf="cartExists$ | async; else cartEmpty" class="cta-to-cart" (click)="continue()" [disabled]="showSpinner">
|
||||
<ui-spinner [show]="showSpinner">
|
||||
Weiter zum Warenkorb
|
||||
</ui-spinner>
|
||||
</button>
|
||||
<ng-template #cartEmpty>
|
||||
<button class="cta-to-cart" (click)="continue()">
|
||||
Weiter zur Artikelsuche
|
||||
<button class="cta-to-cart" (click)="continue()" [disabled]="showSpinner">
|
||||
<ui-spinner [show]="showSpinner">
|
||||
Weiter zur Artikelsuche
|
||||
</ui-spinner>
|
||||
</button>
|
||||
</ng-template>
|
||||
</div>
|
||||
|
||||
@@ -42,6 +42,7 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
isWebshopOrGuest$: Observable<boolean>;
|
||||
cartExists$: Observable<boolean>;
|
||||
hasCustomerCard$: Observable<boolean>;
|
||||
showSpinner: boolean;
|
||||
|
||||
private currentBreadcrumb: Breadcrumb;
|
||||
|
||||
@@ -152,6 +153,7 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
}
|
||||
|
||||
async continue() {
|
||||
this.showSpinner = true;
|
||||
const customer = await this.customer$.pipe(first()).toPromise();
|
||||
|
||||
// Check if customer can be added to the checkout
|
||||
@@ -170,6 +172,7 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
upgradeableTo: canBeExtendedTo,
|
||||
} as CantAddCustomerToCartData,
|
||||
});
|
||||
this.showSpinner = false;
|
||||
return;
|
||||
} else {
|
||||
const updateDestination = await this.checkoutService
|
||||
@@ -190,6 +193,7 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
} as CantAddCustomerToCartData,
|
||||
});
|
||||
|
||||
this.showSpinner = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -251,6 +255,8 @@ export class CustomerDetailsComponent implements OnInit {
|
||||
} else {
|
||||
this.router.navigate(['/product/search']);
|
||||
}
|
||||
|
||||
this.showSpinner = false;
|
||||
}
|
||||
|
||||
getCusomterFeatures(custoemr: CustomerDTO): { [key: string]: string } {
|
||||
|
||||
@@ -27,6 +27,7 @@ import { CardTemplateComponent } from './shared/card-template/card-template.comp
|
||||
import { CustomerOrdersComponent } from './customer-orders/customer-orders.component';
|
||||
import { UiCommonModule } from '@ui/common';
|
||||
import { CustomerHistoryComponent } from './customer-history/customer-history.component';
|
||||
import { UiSpinnerModule } from 'apps/ui/spinner/src/lib/ui-spinner.module';
|
||||
@NgModule({
|
||||
imports: [
|
||||
CommonModule,
|
||||
@@ -40,6 +41,7 @@ import { CustomerHistoryComponent } from './customer-history/customer-history.co
|
||||
FormsModule,
|
||||
UiRadioModule,
|
||||
UiCommonModule,
|
||||
UiSpinnerModule,
|
||||
],
|
||||
exports: [CustomerDetailsComponent],
|
||||
declarations: [
|
||||
|
||||
@@ -23,6 +23,8 @@ export class BranchesAvalabilityOverviewComponent implements OnInit, OnDestroy {
|
||||
branchInfos: BranchInfoView[] = [];
|
||||
filteredBranchInfos: BranchInfoView[] = [];
|
||||
userBranch: BranchDTO;
|
||||
@Output() loaded = new EventEmitter<void>();
|
||||
|
||||
@Output() destroymodal: EventEmitter<boolean> = new EventEmitter();
|
||||
|
||||
destroy$ = new Subject();
|
||||
@@ -76,6 +78,7 @@ export class BranchesAvalabilityOverviewComponent implements OnInit, OnDestroy {
|
||||
.subscribe((t) => {
|
||||
this.branchInfos = t.filter((b) => b && b.load);
|
||||
this.filteredBranchInfos = this.loadDefaultBranches();
|
||||
this.loaded.emit();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -218,9 +218,9 @@
|
||||
</div>
|
||||
</ng-template>
|
||||
<div class="actions align-right" [ngClass]="{ 'action-partly-loaded': !fullyLoaded }">
|
||||
<app-button (action)="openBranchesAvailabilityModal()" *ngIf="product.formatIcon !== 'EB' && product.formatIcon !== 'DL'"
|
||||
>weitere Verfügbarkeiten</app-button
|
||||
>
|
||||
<app-button (action)="openBranchesAvailabilityModal()" *ngIf="product.formatIcon !== 'EB' && product.formatIcon !== 'DL'">
|
||||
weitere Verfügbarkeiten
|
||||
</app-button>
|
||||
<app-button
|
||||
[primary]="true"
|
||||
[load]="true"
|
||||
@@ -281,6 +281,7 @@
|
||||
|
||||
<ng-container *ngIf="item && loadBranchesInfoComponent">
|
||||
<app-branches-avalability-overview
|
||||
(loaded)="branchesAvailabilityInfo.openDialog()"
|
||||
(destroymodal)="destroyAvailabilityModal($event)"
|
||||
[item]="item"
|
||||
#branchesAvailabilityInfo
|
||||
|
||||
@@ -512,7 +512,6 @@ export class ProductDetailsComponent implements OnInit, OnDestroy {
|
||||
openBranchesAvailabilityModal() {
|
||||
this.loadBranchesInfoComponent = true;
|
||||
this.detectChanges();
|
||||
this.branchesAvailabilityInfo.openDialog();
|
||||
}
|
||||
|
||||
destroyAvailabilityModal() {
|
||||
|
||||
25
apps/ui/spinner/README.md
Normal file
25
apps/ui/spinner/README.md
Normal file
@@ -0,0 +1,25 @@
|
||||
# Spinner
|
||||
|
||||
This library was generated with [Angular CLI](https://github.com/angular/angular-cli) version 10.1.2.
|
||||
|
||||
## Code scaffolding
|
||||
|
||||
Run `ng generate component component-name --project spinner` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module --project spinner`.
|
||||
|
||||
> Note: Don't forget to add `--project spinner` or else it will be added to the default project in your `angular.json` file.
|
||||
|
||||
## Build
|
||||
|
||||
Run `ng build spinner` to build the project. The build artifacts will be stored in the `dist/` directory.
|
||||
|
||||
## Publishing
|
||||
|
||||
After building your library with `ng build spinner`, go to the dist folder `cd dist/spinner` and run `npm publish`.
|
||||
|
||||
## Running unit tests
|
||||
|
||||
Run `ng test spinner` to execute the unit tests via [Karma](https://karma-runner.github.io).
|
||||
|
||||
## Further help
|
||||
|
||||
To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
|
||||
32
apps/ui/spinner/karma.conf.js
Normal file
32
apps/ui/spinner/karma.conf.js
Normal file
@@ -0,0 +1,32 @@
|
||||
// Karma configuration file, see link for more information
|
||||
// https://karma-runner.github.io/1.0/config/configuration-file.html
|
||||
|
||||
module.exports = function (config) {
|
||||
config.set({
|
||||
basePath: '',
|
||||
frameworks: ['jasmine', '@angular-devkit/build-angular'],
|
||||
plugins: [
|
||||
require('karma-jasmine'),
|
||||
require('karma-chrome-launcher'),
|
||||
require('karma-jasmine-html-reporter'),
|
||||
require('karma-coverage-istanbul-reporter'),
|
||||
require('@angular-devkit/build-angular/plugins/karma'),
|
||||
],
|
||||
client: {
|
||||
clearContext: false, // leave Jasmine Spec Runner output visible in browser
|
||||
},
|
||||
coverageIstanbulReporter: {
|
||||
dir: require('path').join(__dirname, '../../../coverage/ui/spinner'),
|
||||
reports: ['html', 'lcovonly', 'text-summary'],
|
||||
fixWebpackSourcePaths: true,
|
||||
},
|
||||
reporters: ['progress', 'kjhtml'],
|
||||
port: 9876,
|
||||
colors: true,
|
||||
logLevel: config.LOG_INFO,
|
||||
autoWatch: true,
|
||||
browsers: ['Chrome'],
|
||||
singleRun: false,
|
||||
restartOnFileChange: true,
|
||||
});
|
||||
};
|
||||
7
apps/ui/spinner/ng-package.json
Normal file
7
apps/ui/spinner/ng-package.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"$schema": "../../../node_modules/ng-packagr/ng-package.schema.json",
|
||||
"dest": "../../../dist/ui/spinner",
|
||||
"lib": {
|
||||
"entryFile": "src/public-api.ts"
|
||||
}
|
||||
}
|
||||
11
apps/ui/spinner/package.json
Normal file
11
apps/ui/spinner/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "@ui/spinner",
|
||||
"version": "0.0.1",
|
||||
"peerDependencies": {
|
||||
"@angular/common": "^10.1.2",
|
||||
"@angular/core": "^10.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.0"
|
||||
}
|
||||
}
|
||||
5
apps/ui/spinner/src/lib/ui-spinner.component.html
Normal file
5
apps/ui/spinner/src/lib/ui-spinner.component.html
Normal file
@@ -0,0 +1,5 @@
|
||||
<!-- <ng-container [ngSwitch]="show"> -->
|
||||
<ui-icon *ngIf="show" class="spin" icon="spinner" size="28px"></ui-icon>
|
||||
<span class="content" [class.invisible]="show">
|
||||
<ng-content></ng-content>
|
||||
</span>
|
||||
16
apps/ui/spinner/src/lib/ui-spinner.component.scss
Normal file
16
apps/ui/spinner/src/lib/ui-spinner.component.scss
Normal file
@@ -0,0 +1,16 @@
|
||||
:host {
|
||||
@apply flex items-center relative;
|
||||
}
|
||||
|
||||
.content {
|
||||
@apply w-full;
|
||||
}
|
||||
|
||||
.spin {
|
||||
@apply animate-spin absolute;
|
||||
left: calc(50% - 14px);
|
||||
}
|
||||
|
||||
.invisible {
|
||||
visibility: hidden;
|
||||
}
|
||||
15
apps/ui/spinner/src/lib/ui-spinner.component.ts
Normal file
15
apps/ui/spinner/src/lib/ui-spinner.component.ts
Normal file
@@ -0,0 +1,15 @@
|
||||
import { Component, Input, OnInit } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'ui-spinner',
|
||||
templateUrl: 'ui-spinner.component.html',
|
||||
styleUrls: ['./ui-spinner.component.scss'],
|
||||
})
|
||||
export class SpinnerComponent implements OnInit {
|
||||
@Input()
|
||||
show: boolean;
|
||||
|
||||
constructor() {}
|
||||
|
||||
ngOnInit(): void {}
|
||||
}
|
||||
11
apps/ui/spinner/src/lib/ui-spinner.module.ts
Normal file
11
apps/ui/spinner/src/lib/ui-spinner.module.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { UiIconModule } from '@ui/icon';
|
||||
import { SpinnerComponent } from './ui-spinner.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [SpinnerComponent],
|
||||
imports: [UiIconModule, CommonModule],
|
||||
exports: [SpinnerComponent],
|
||||
})
|
||||
export class UiSpinnerModule {}
|
||||
4
apps/ui/spinner/src/public-api.ts
Normal file
4
apps/ui/spinner/src/public-api.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
/*
|
||||
* Public API Surface of spinner
|
||||
*/
|
||||
export * from './lib';
|
||||
24
apps/ui/spinner/src/test.ts
Normal file
24
apps/ui/spinner/src/test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone';
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: {
|
||||
context(
|
||||
path: string,
|
||||
deep?: boolean,
|
||||
filter?: RegExp
|
||||
): {
|
||||
keys(): string[];
|
||||
<T>(id: string): T;
|
||||
};
|
||||
};
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
||||
25
apps/ui/spinner/tsconfig.lib.json
Normal file
25
apps/ui/spinner/tsconfig.lib.json
Normal file
@@ -0,0 +1,25 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/lib",
|
||||
"target": "es2015",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"inlineSources": true,
|
||||
"types": [],
|
||||
"lib": [
|
||||
"dom",
|
||||
"es2018"
|
||||
]
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true,
|
||||
"strictMetadataEmit": true,
|
||||
"enableResourceInlining": true
|
||||
},
|
||||
"exclude": [
|
||||
"src/test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
||||
10
apps/ui/spinner/tsconfig.lib.prod.json
Normal file
10
apps/ui/spinner/tsconfig.lib.prod.json
Normal file
@@ -0,0 +1,10 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "./tsconfig.lib.json",
|
||||
"compilerOptions": {
|
||||
"declarationMap": false
|
||||
},
|
||||
"angularCompilerOptions": {
|
||||
"enableIvy": false
|
||||
}
|
||||
}
|
||||
17
apps/ui/spinner/tsconfig.spec.json
Normal file
17
apps/ui/spinner/tsconfig.spec.json
Normal file
@@ -0,0 +1,17 @@
|
||||
/* To learn more about this file see: https://angular.io/config/tsconfig. */
|
||||
{
|
||||
"extends": "../../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../../out-tsc/spec",
|
||||
"types": [
|
||||
"jasmine"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"src/test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
||||
17
apps/ui/spinner/tslint.json
Normal file
17
apps/ui/spinner/tslint.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"extends": "../../../tslint.json",
|
||||
"rules": {
|
||||
"directive-selector": [
|
||||
true,
|
||||
"attribute",
|
||||
"ui",
|
||||
"camelCase"
|
||||
],
|
||||
"component-selector": [
|
||||
true,
|
||||
"element",
|
||||
"ui",
|
||||
"kebab-case"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -176,6 +176,9 @@
|
||||
],
|
||||
"@cdn/product-image": [
|
||||
"apps/cdn/product-image/cdn-product-image/src/public-api.ts"
|
||||
],
|
||||
"@ui/spinner": [
|
||||
"apps/ui/spinner/src/public-api.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user