File

feature-libs/cart/quick-order/components/quick-order/quick-order.component.ts

Implements

OnInit OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector cx-quick-order
templateUrl ./quick-order.component.html

Index

Properties
Methods
Accessors

Constructor

constructor(activeCartService: ActiveCartService, component: CmsComponentData<CmsQuickOrderComponent>, globalMessageService: GlobalMessageService, quickOrderService: QuickOrderFacade, quickOrderStatePersistenceService: QuickOrderStatePersistenceService)
Parameters :
Name Type Optional
activeCartService ActiveCartService No
component CmsComponentData<CmsQuickOrderComponent> No
globalMessageService GlobalMessageService No
quickOrderService QuickOrderFacade No
quickOrderStatePersistenceService QuickOrderStatePersistenceService No

Methods

addToCart
addToCart(orderEntries: OrderEntry[])
Parameters :
Name Type Optional
orderEntries OrderEntry[] No
Returns : void
canAddProduct
canAddProduct()
Returns : Observable<boolean>
clear
clear()
Returns : void
clearAddToCartInformation
clearAddToCartInformation()
Returns : void
clearDeletion
clearDeletion(entry: OrderEntry)
Parameters :
Name Type Optional
entry OrderEntry No
Returns : void
clearErrors
clearErrors()
Returns : void
clearNonPurchasableError
clearNonPurchasableError()
Returns : void
Protected clearStatuses
clearStatuses()
Returns : void
clearSuccesses
clearSuccesses()
Returns : void
clearWarnings
clearWarnings()
Returns : void
Protected extractErrors
extractErrors(errors: QuickOrderAddEntryEvent[])
Parameters :
Name Type Optional
errors QuickOrderAddEntryEvent[] No
Returns : void
Protected extractSuccesses
extractSuccesses(errors: QuickOrderAddEntryEvent[], entries: OrderEntry[])
Parameters :
Name Type Optional
errors QuickOrderAddEntryEvent[] No
entries OrderEntry[] No
Returns : void
Protected extractWarnings
extractWarnings(errors: QuickOrderAddEntryEvent[])
Parameters :
Name Type Optional
errors QuickOrderAddEntryEvent[] No
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
Protected setErrors
setErrors(errors: QuickOrderAddEntryEvent[])
Parameters :
Name Type Optional
errors QuickOrderAddEntryEvent[] No
Returns : void
Protected setSuccesses
setSuccesses(entries: OrderEntry[])
Parameters :
Name Type Optional
entries OrderEntry[] No
Returns : void
Protected setWarnings
setWarnings(warnings: QuickOrderAddEntryEvent[])
Parameters :
Name Type Optional
warnings QuickOrderAddEntryEvent[] No
Returns : void
Protected showAddedToCartSuccessMessage
showAddedToCartSuccessMessage()
Returns : void
undoDeletion
undoDeletion(entry: OrderEntry)
Parameters :
Name Type Optional
entry OrderEntry No
Returns : void

Properties

Protected cartErrors$
Default value : new BehaviorSubject<QuickOrderAddEntryEvent[]>([])
cartId$
Type : Observable<string>
Protected cartSuccesses$
Default value : new BehaviorSubject<OrderEntry[]>([])
Protected cartWarnings$
Default value : new BehaviorSubject<QuickOrderAddEntryEvent[]>([])
entries$
Type : Observable<OrderEntry[]>
globalMessageType
Default value : GlobalMessageType
isCartStable$
Type : Observable<boolean>
Default value : combineLatest([ this.activeCartService.getActiveCartId(), this.activeCartService.isStable(), ]).pipe(map(([activeCartId, isStable]) => (!activeCartId ? true : isStable)))
listLimitReached$
Type : Observable<boolean>
Protected nonPurchasableProductError$
Default value : new BehaviorSubject<Product | null>( null )
quickOrderForm
Type : QuickOrderFormComponent
Decorators :
@ViewChild('quickOrderForm')
quickOrderListLimit$
Type : Observable<number | undefined>
Default value : this.component.data$.pipe( map((data) => data.quickOrderListLimit), tap((limit) => { if (!!limit) { this.quickOrderService.setListLimit(limit); } }) )
Protected showAddToCartInformation$
Default value : new BehaviorSubject<boolean>(false)

Accessors

errors$
geterrors$()
warnings$
getwarnings$()
successes$
getsuccesses$()
nonPurchasableError$
getnonPurchasableError$()
addToCartInformation$
getaddToCartInformation$()
softDeletedEntries$
getsoftDeletedEntries$()
import {
  ChangeDetectionStrategy,
  Component,
  OnDestroy,
  OnInit,
  ViewChild,
} from '@angular/core';
import {
  CmsQuickOrderComponent,
  QuickOrderStatePersistenceService,
} from '@spartacus/cart/quick-order/core';
import {
  QuickOrderAddEntryEvent,
  QuickOrderFacade,
} from '@spartacus/cart/quick-order/root';
import {
  ActiveCartService,
  GlobalMessageService,
  GlobalMessageType,
  OrderEntry,
  Product,
} from '@spartacus/core';
import { CmsComponentData } from '@spartacus/storefront';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { first, map, tap } from 'rxjs/operators';
import { QuickOrderFormComponent } from './form/quick-order-form.component';

@Component({
  selector: 'cx-quick-order',
  templateUrl: './quick-order.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class QuickOrderComponent implements OnInit, OnDestroy {
  cartId$: Observable<string>;
  entries$: Observable<OrderEntry[]>;
  quickOrderListLimit$: Observable<number | undefined> =
    this.component.data$.pipe(
      map((data) => data.quickOrderListLimit),
      tap((limit) => {
        if (!!limit) {
          this.quickOrderService.setListLimit(limit);
        }
      })
    );
  isCartStable$: Observable<boolean> = combineLatest([
    this.activeCartService.getActiveCartId(),
    this.activeCartService.isStable(),
  ]).pipe(map(([activeCartId, isStable]) => (!activeCartId ? true : isStable)));
  globalMessageType = GlobalMessageType;
  listLimitReached$: Observable<boolean>;

  @ViewChild('quickOrderForm')
  quickOrderForm: QuickOrderFormComponent;

  protected cartErrors$ = new BehaviorSubject<QuickOrderAddEntryEvent[]>([]);
  protected cartWarnings$ = new BehaviorSubject<QuickOrderAddEntryEvent[]>([]);
  protected cartSuccesses$ = new BehaviorSubject<OrderEntry[]>([]);
  protected showAddToCartInformation$ = new BehaviorSubject<boolean>(false);
  protected nonPurchasableProductError$ = new BehaviorSubject<Product | null>(
    null
  );

  constructor(
    protected activeCartService: ActiveCartService,
    protected component: CmsComponentData<CmsQuickOrderComponent>,
    protected globalMessageService: GlobalMessageService,
    protected quickOrderService: QuickOrderFacade,
    protected quickOrderStatePersistenceService: QuickOrderStatePersistenceService
  ) {}

  ngOnInit(): void {
    this.cartId$ = this.activeCartService.getActiveCartId();
    this.entries$ = this.quickOrderService.getEntries();
    this.quickOrderStatePersistenceService.initSync();
  }

  ngOnDestroy(): void {
    this.quickOrderService.clearDeletedEntries();
  }

  get errors$(): Observable<QuickOrderAddEntryEvent[]> {
    return this.cartErrors$.asObservable();
  }

  get warnings$(): Observable<QuickOrderAddEntryEvent[]> {
    return this.cartWarnings$.asObservable();
  }

  get successes$(): Observable<OrderEntry[]> {
    return this.cartSuccesses$.asObservable();
  }

  get nonPurchasableError$(): Observable<Product | null> {
    return this.quickOrderService.getNonPurchasableProductError();
  }

  get addToCartInformation$(): Observable<boolean> {
    return this.showAddToCartInformation$.asObservable();
  }

  get softDeletedEntries$(): Observable<Record<string, OrderEntry>> {
    return this.quickOrderService.getSoftDeletedEntries();
  }

  clear(): void {
    this.quickOrderService.clearList();
    this.globalMessageService.add(
      {
        key: 'quickOrderTable.listCleared',
      },
      GlobalMessageType.MSG_TYPE_INFO
    );
  }

  addToCart(orderEntries: OrderEntry[]): void {
    if (!orderEntries.length) {
      this.showAddToCartInformation$.next(true);
      return;
    }

    this.clearStatuses();

    this.quickOrderService
      .addToCart()
      .pipe(first())
      .subscribe(([entries, errors]) => {
        errors.forEach((err) => {
          if (!err.entry) {
            err.entry = orderEntries.find(
              (e) => e.product?.code === err.productCode
            );
          }
        });

        this.extractErrors(errors);
        this.extractWarnings(errors);

        if (!errors.length) {
          this.showAddedToCartSuccessMessage();
        } else {
          this.extractSuccesses(errors, entries);
        }
      });
  }

  clearErrors(): void {
    this.cartErrors$.next([]);
  }

  clearWarnings(): void {
    this.cartWarnings$.next([]);
  }

  clearSuccesses(): void {
    this.cartSuccesses$.next([]);
  }

  clearAddToCartInformation(): void {
    this.showAddToCartInformation$.next(false);
  }

  undoDeletion(entry: OrderEntry): void {
    if (entry.product?.code) {
      this.quickOrderService.restoreSoftDeletedEntry(entry.product.code);
    }
  }

  clearDeletion(entry: OrderEntry): void {
    if (entry.product?.code) {
      this.quickOrderService.hardDeleteEntry(entry.product.code);
    }
  }

  clearNonPurchasableError(): void {
    this.quickOrderService.clearNonPurchasableProductError();
  }

  canAddProduct(): Observable<boolean> {
    return this.quickOrderService.canAdd();
  }

  protected extractErrors(errors: QuickOrderAddEntryEvent[]): void {
    const noAddedEntries = errors.filter((error) => error.quantityAdded === 0);

    this.setErrors(noAddedEntries);
  }

  protected extractWarnings(errors: QuickOrderAddEntryEvent[]): void {
    const warnings = errors.filter((error) => error.quantityAdded !== 0);

    this.setWarnings(warnings);
  }

  protected extractSuccesses(
    errors: QuickOrderAddEntryEvent[],
    entries: OrderEntry[]
  ): void {
    const successAddedEntries: OrderEntry[] = [];

    entries.forEach((entry) => {
      const element = errors.find(
        (error) => error.productCode === entry.product?.code
      );
      if (!element) {
        successAddedEntries.push(entry);
      }
    });

    this.setSuccesses(successAddedEntries);
  }

  protected clearStatuses(): void {
    this.clearErrors();
    this.clearWarnings();
    this.clearSuccesses();
  }

  protected showAddedToCartSuccessMessage(): void {
    this.globalMessageService.add(
      {
        key: 'quickOrderTable.addedtoCart',
      },
      GlobalMessageType.MSG_TYPE_CONFIRMATION
    );
  }

  protected setErrors(errors: QuickOrderAddEntryEvent[]): void {
    this.cartErrors$.next(errors);
  }

  protected setWarnings(warnings: QuickOrderAddEntryEvent[]): void {
    this.cartWarnings$.next(warnings);
  }

  protected setSuccesses(entries: OrderEntry[]): void {
    this.cartSuccesses$.next(entries);
  }
}
<ng-container *ngIf="entries$ | async as entries">
  <ng-container *ngIf="!(canAddProduct() | async)">
    <ng-container *ngIf="quickOrderForm?.form?.get('product')?.dirty">
      <cx-message
        [text]="
          'quickOrderList.errors.listIsFull'
            | cxTranslate: { count: entries.length }
        "
        [isVisibleCloseButton]="false"
        [type]="globalMessageType.MSG_TYPE_ERROR"
        class="quick-order-list-limit-message"
      >
      </cx-message>
    </ng-container>
  </ng-container>
</ng-container>

<ng-container *ngIf="addToCartInformation$ | async">
  <cx-message
    (closeMessage)="clearAddToCartInformation()"
    [text]="
      'quickOrderList.informations.addProductBeforeAddingToCart' | cxTranslate
    "
    [type]="globalMessageType.MSG_TYPE_ERROR"
    class="quick-order-add-to-cart-information-message"
  >
  </cx-message>
</ng-container>

<ng-container *ngIf="nonPurchasableError$ | async as nonPurchasableError">
  <cx-message
    (closeMessage)="clearNonPurchasableError()"
    [text]="
      'quickOrderList.errors.nonPurchasableError'
        | cxTranslate: { name: nonPurchasableError.name }
    "
    [type]="globalMessageType.MSG_TYPE_ERROR"
    class="quick-order-non-purchasable-product-error-message"
  >
  </cx-message>
</ng-container>

<ng-container *ngIf="softDeletedEntries$ | async as deletedEntries">
  <cx-message
    *ngFor="let deletedEntry of deletedEntries | keyvalue"
    (buttonAction)="undoDeletion(deletedEntry.value)"
    (closeMessage)="clearDeletion(deletedEntry.value)"
    [actionButtonText]="'quickOrderList.undo' | cxTranslate"
    [text]="
      'quickOrderList.productWasDeleted'
        | cxTranslate: { name: deletedEntry.value.product?.name }
    "
    [type]="globalMessageType.MSG_TYPE_CONFIRMATION"
    class="quick-order-deletions-message"
  >
  </cx-message>
</ng-container>

<ng-container *ngIf="errors$ | async as errors">
  <cx-message
    *ngIf="errors.length"
    (closeMessage)="clearErrors()"
    [accordionText]="'quickOrderList.errors.reviewErrors' | cxTranslate"
    [text]="'quickOrderList.errorProceedingToCart' | cxTranslate"
    [type]="globalMessageType.MSG_TYPE_ERROR"
    class="quick-order-errors-message"
  >
    <ul class="quick-order-errors">
      <li *ngFor="let error of errors" class="quick-order-error-item">
        <span>
          {{
            'quickOrderList.errors.productIsOutOfStock'
              | cxTranslate
                : {
                    name: error.entry.product.name,
                    code: error.entry.product.code
                  }
          }}
        </span>
      </li>
    </ul>
  </cx-message>
</ng-container>

<ng-container *ngIf="warnings$ | async as warnings">
  <cx-message
    *ngIf="warnings.length"
    (closeMessage)="clearWarnings()"
    [accordionText]="'quickOrderList.warnings.reviewWarnings' | cxTranslate"
    [text]="'quickOrderList.warningProceedingToCart' | cxTranslate"
    [type]="globalMessageType.MSG_TYPE_WARNING"
    class="quick-order-warnings-message"
  >
    <ul class="quick-order-warnings">
      <li *ngFor="let warning of warnings" class="quick-order-warning-item">
        <span>
          {{
            'quickOrderList.warnings.productWasReduced'
              | cxTranslate
                : {
                    name: warning.entry.product.name,
                    code: warning.entry.product.code,
                    quantityAdded: warning.quantityAdded
                  }
          }}
        </span>
      </li>
    </ul>
  </cx-message>
</ng-container>

<ng-container *ngIf="successes$ | async as successes">
  <cx-message
    *ngIf="successes.length"
    (closeMessage)="clearSuccesses()"
    [text]="'quickOrderList.successfullyAddedToCart' | cxTranslate"
    [type]="globalMessageType.MSG_TYPE_CONFIRMATION"
    class="quick-order-successes-message"
  >
    <ul class="quick-order-successes">
      <li *ngFor="let entry of successes" class="quick-order-success-item">
        <span>{{
          'quickOrderList.successes.productAddedToCart'
            | cxTranslate
              : {
                  name: entry.product.name,
                  code: entry.product.code
                }
        }}</span>
      </li>
    </ul>
  </cx-message>
</ng-container>

<ng-container *ngIf="quickOrderListLimit$ | async as quickOrderListLimit">
  <ng-container *ngIf="entries$ | async as entries">
    <div class="quick-order-header">
      <h3>{{ 'quickOrderList.header' | cxTranslate }}</h3>
      <p>
        {{
          'quickOrderList.subHeader'
            | cxTranslate: { limit: quickOrderListLimit }
        }}
      </p>
    </div>

    <div class="quick-order-form-body">
      <cx-quick-order-form #quickOrderForm> </cx-quick-order-form>
    </div>

    <div class="quick-order-table-body">
      <cx-quick-order-table
        [entries]="entries"
        [loading]="!(isCartStable$ | async)"
      ></cx-quick-order-table>
    </div>

    <div class="quick-order-footer row">
      <div class="col-xs-12 col-md-5 col-lg-4">
        <button
          *ngIf="entries.length"
          (click)="clear()"
          [attr.aria-label]="'quickOrderList.emptyList' | cxTranslate"
          [disabled]="!(isCartStable$ | async)"
          class="btn btn-block btn-action clear-button"
          type="button"
        >
          {{ 'quickOrderList.emptyList' | cxTranslate }}
        </button>
      </div>

      <div class="col-xs-12 col-md-5 col-lg-4">
        <cx-progress-button
          (clikEvent)="addToCart(entries)"
          [ariaLabel]="'quickOrderList.addToCart' | cxTranslate"
          [class]="'btn-block add-button'"
          [loading]="!(isCartStable$ | async)"
        >
          {{ 'quickOrderList.addToCart' | cxTranslate }}
        </cx-progress-button>
      </div>
    </div>
  </ng-container>
</ng-container>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""