File

feature-libs/checkout/components/components/shipping-address/shipping-address.component.ts

Implements

OnInit OnDestroy

Metadata

changeDetection ChangeDetectionStrategy.OnPush
selector cx-shipping-address
templateUrl ./shipping-address.component.html

Index

Properties
Methods
Accessors

Constructor

constructor(userAddressService: UserAddressService, checkoutDeliveryService: CheckoutDeliveryFacade, activatedRoute: ActivatedRoute, translation: TranslationService, activeCartService: ActiveCartService, checkoutStepService: CheckoutStepService, paymentTypeService?: PaymentTypeFacade, userCostCenterService?: UserCostCenterService, checkoutCostCenterService?: CheckoutCostCenterFacade)
Parameters :
Name Type Optional
userAddressService UserAddressService No
checkoutDeliveryService CheckoutDeliveryFacade No
activatedRoute ActivatedRoute No
translation TranslationService No
activeCartService ActiveCartService No
checkoutStepService CheckoutStepService No
paymentTypeService PaymentTypeFacade Yes
userCostCenterService UserCostCenterService Yes
checkoutCostCenterService CheckoutCostCenterFacade Yes

Methods

addAddress
addAddress(address: Address)
Parameters :
Name Type Optional
address Address No
Returns : void
back
back()
Returns : void
getCardContent
getCardContent(address: Address, selected: any, textDefaultShippingAddress: string, textShipToThisAddress: string, textSelected: string)
Parameters :
Name Type Optional
address Address No
selected any No
textDefaultShippingAddress string No
textShipToThisAddress string No
textSelected string No
Returns : Card
getSupportedAddresses
getSupportedAddresses()
Returns : Observable<Address[]>
hideNewAddressForm
hideNewAddressForm(goPrevious: boolean)
Parameters :
Name Type Optional Default value
goPrevious boolean No false
Returns : void
next
next()
Returns : void
ngOnDestroy
ngOnDestroy()
Returns : void
ngOnInit
ngOnInit()
Returns : void
selectAddress
selectAddress(address: Address)
Parameters :
Name Type Optional
address Address No
Returns : void
selectDefaultAddress
selectDefaultAddress(addresses: Address[], selected: Address | undefined)
Parameters :
Name Type Optional
addresses Address[] No
selected Address | undefined No
Returns : void
showNewAddressForm
showNewAddressForm()
Returns : void

Properties

addressFormOpened
Default value : false
doneAutoSelect
Default value : false
forceLoader
Default value : false
isAccountPayment
Default value : false
selectedAddress
Type : Address
Protected subscriptions
Default value : new Subscription()

Accessors

isGuestCheckout
getisGuestCheckout()
backBtnText
getbackBtnText()
isLoading$
getisLoading$()
selectedAddress$
getselectedAddress$()
cards$
getcards$()
import {
  ChangeDetectionStrategy,
  Component,
  OnDestroy,
  OnInit,
} from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import {
  CheckoutCostCenterFacade,
  CheckoutDeliveryFacade,
  PaymentTypeFacade,
} from '@spartacus/checkout/root';
import {
  ActiveCartService,
  Address,
  TranslationService,
  UserAddressService,
  UserCostCenterService,
} from '@spartacus/core';
import { Card } from '@spartacus/storefront';
import { combineLatest, Observable, Subscription } from 'rxjs';
import { distinctUntilChanged, map, switchMap, tap } from 'rxjs/operators';
import { CheckoutStepService } from '../../services/checkout-step.service';

export interface CardWithAddress {
  card: Card;
  address: Address;
}

@Component({
  selector: 'cx-shipping-address',
  templateUrl: './shipping-address.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ShippingAddressComponent implements OnInit, OnDestroy {
  addressFormOpened = false;
  forceLoader = false; // this helps with smoother steps transition
  selectedAddress: Address;
  doneAutoSelect = false;
  isAccountPayment = false;

  protected subscriptions = new Subscription();

  constructor(
    protected userAddressService: UserAddressService,
    protected checkoutDeliveryService: CheckoutDeliveryFacade,
    protected activatedRoute: ActivatedRoute,
    protected translation: TranslationService,
    protected activeCartService: ActiveCartService,
    protected checkoutStepService: CheckoutStepService,
    protected paymentTypeService?: PaymentTypeFacade,
    protected userCostCenterService?: UserCostCenterService,
    protected checkoutCostCenterService?: CheckoutCostCenterFacade
  ) {}

  get isGuestCheckout(): boolean {
    return this.activeCartService.isGuestCart();
  }

  get backBtnText(): string {
    return this.checkoutStepService.getBackBntText(this.activatedRoute);
  }

  get isLoading$(): Observable<boolean> {
    return this.userAddressService.getAddressesLoading();
  }

  get selectedAddress$(): Observable<Address> {
    return this.checkoutDeliveryService.getDeliveryAddress().pipe(
      tap((address) => {
        if (
          address &&
          (this.selectedAddress === undefined ||
            this.selectedAddress.id !== address.id)
        ) {
          this.selectedAddress = address;
          if (this.forceLoader) {
            this.next();
          }
        }
      })
    );
  }

  get cards$(): Observable<CardWithAddress[]> {
    return combineLatest([
      this.getSupportedAddresses(),
      this.selectedAddress$,
      this.translation.translate('checkoutAddress.defaultShippingAddress'),
      this.translation.translate('checkoutAddress.shipToThisAddress'),
      this.translation.translate('addressCard.selected'),
    ]).pipe(
      tap(([addresses, selected]) =>
        this.selectDefaultAddress(addresses, selected)
      ),
      map(([addresses, selected, textDefault, textShipTo, textSelected]) =>
        (<any>addresses).map((address: Address) => ({
          address,
          card: this.getCardContent(
            address,
            selected,
            textDefault,
            textShipTo,
            textSelected
          ),
        }))
      )
    );
  }

  getSupportedAddresses(): Observable<Address[]> {
    if (
      this.isAccountPayment &&
      this.checkoutCostCenterService &&
      this.userCostCenterService
    ) {
      return this.checkoutCostCenterService.getCostCenter().pipe(
        distinctUntilChanged(),
        switchMap((selected) => {
          this.doneAutoSelect = false;
          return (
            this.userCostCenterService?.getCostCenterAddresses(
              selected as string
            ) ?? []
          );
        })
      );
    }
    return this.userAddressService.getAddresses();
  }

  selectDefaultAddress(addresses: Address[], selected: Address | undefined) {
    if (
      !this.doneAutoSelect &&
      addresses &&
      addresses.length &&
      (!selected || Object.keys(selected).length === 0)
    ) {
      if (this.isAccountPayment) {
        if (addresses.length === 1) {
          this.selectAddress(addresses[0]);
        }
      } else {
        selected = addresses.find((address) => address.defaultAddress);
        if (selected) {
          this.selectAddress(selected);
        }
      }
      this.doneAutoSelect = true;
    }
  }

  ngOnInit(): void {
    if (
      this.paymentTypeService &&
      this.userCostCenterService &&
      this.checkoutCostCenterService
    ) {
      this.subscriptions.add(
        this.paymentTypeService
          .isAccountPayment()
          .pipe(distinctUntilChanged())
          .subscribe((isAccount) => (this.isAccountPayment = isAccount))
      );
    }

    if (!this.isGuestCheckout && !this.isAccountPayment) {
      this.userAddressService.loadAddresses();
    }
  }

  getCardContent(
    address: Address,
    selected: any,
    textDefaultShippingAddress: string,
    textShipToThisAddress: string,
    textSelected: string
  ): Card {
    let region = '';
    if (address.region && address.region.isocode) {
      region = address.region.isocode + ', ';
    }

    return {
      title: address.defaultAddress ? textDefaultShippingAddress : '',
      textBold: address.firstName + ' ' + address.lastName,
      text: [
        address.line1,
        address.line2,
        address.town + ', ' + region + address.country?.isocode,
        address.postalCode,
        address.phone,
      ],
      actions: [{ name: textShipToThisAddress, event: 'send' }],
      header: selected && selected.id === address.id ? textSelected : '',
    } as Card;
  }

  selectAddress(address: Address): void {
    this.checkoutDeliveryService.setDeliveryAddress(address);
  }

  addAddress(address: Address): void {
    this.forceLoader = true;
    if (Boolean(address)) {
      this.checkoutDeliveryService.createAndSetAddress(address);
    } else {
      this.forceLoader = false;
      this.next();
    }
  }

  showNewAddressForm(): void {
    this.addressFormOpened = true;
  }

  hideNewAddressForm(goPrevious: boolean = false): void {
    this.addressFormOpened = false;
    if (goPrevious) {
      this.back();
    }
  }

  next(): void {
    this.checkoutStepService.next(this.activatedRoute);
  }

  back(): void {
    this.checkoutStepService.back(this.activatedRoute);
  }

  ngOnDestroy() {
    this.subscriptions.unsubscribe();
  }
}
<ng-container *ngIf="cards$ | async as cards">
  <h2 class="cx-checkout-title d-none d-lg-block d-xl-block">
    {{ 'checkoutAddress.shippingAddress' | cxTranslate }}
  </h2>
  <ng-container *ngIf="!forceLoader && !(isLoading$ | async); else loading">
    <ng-container
      *ngIf="
        isAccountPayment || (cards?.length && !addressFormOpened);
        else newAddressForm
      "
    >
      <p class="cx-checkout-text">
        {{ 'checkoutAddress.selectYourShippingAddress' | cxTranslate }}
      </p>
      <div class="cx-checkout-btns row" *ngIf="!isAccountPayment">
        <div class="col-sm-12 col-md-12 col-lg-6">
          <button
            class="btn btn-block btn-action"
            (click)="showNewAddressForm()"
          >
            {{ 'checkoutAddress.addNewAddress' | cxTranslate }}
          </button>
        </div>
      </div>

      <div class="cx-checkout-body row">
        <div
          class="cx-shipping-address-card col-md-12 col-lg-6"
          *ngFor="let card of cards; let i = index"
        >
          <div
            class="cx-shipping-address-card-inner"
            (click)="selectAddress(card.address)"
          >
            <cx-card
              [border]="true"
              [fitToContainer]="true"
              [content]="card.card"
              (sendCard)="selectAddress(card.address)"
            ></cx-card>
          </div>
        </div>
      </div>

      <div class="cx-checkout-btns row">
        <div class="col-md-12 col-lg-6">
          <button class="cx-btn btn btn-block btn-action" (click)="back()">
            {{ backBtnText | cxTranslate }}
          </button>
        </div>
        <div class="col-md-12 col-lg-6">
          <button
            class="cx-btn btn btn-block btn-primary"
            [disabled]="!selectedAddress?.id"
            (click)="next()"
          >
            {{ 'common.continue' | cxTranslate }}
          </button>
        </div>
      </div>
    </ng-container>

    <ng-template #newAddressForm>
      <cx-address-form
        *ngIf="cards.length; else initialAddressForm"
        [showTitleCode]="true"
        (backToAddress)="hideNewAddressForm(false)"
        (submitAddress)="addAddress($event)"
      ></cx-address-form>
      <ng-template #initialAddressForm>
        <cx-address-form
          [showTitleCode]="true"
          [setAsDefaultField]="!isGuestCheckout"
          [addressData]="selectedAddress"
          cancelBtnLabel="{{ backBtnText | cxTranslate }}"
          (backToAddress)="hideNewAddressForm(true)"
          (submitAddress)="addAddress($event)"
        ></cx-address-form>
      </ng-template>
    </ng-template>
  </ng-container>

  <ng-template #loading>
    <div class="cx-spinner">
      <cx-spinner></cx-spinner>
    </div>
  </ng-template>
</ng-container>
Legend
Html element
Component
Html element with directive

result-matching ""

    No results matching ""