All files / src/app/pages/checkout-payment checkout-payment-page.component.ts

70.27% Statements 26/37
8.33% Branches 1/12
62.5% Functions 10/16
68.57% Lines 24/35

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 1071x 1x 1x   1x   1x   1x           1x             1x             11x         11x 11x       33x 11x 11x 11x   11x     11x   12x             11x         11x   11x 3x 3x     3x                                                                              
import { ChangeDetectionStrategy, Component, DestroyRef, OnInit, inject } from '@angular/core';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { isEqual } from 'lodash-es';
import { Observable } from 'rxjs';
import { distinctUntilChanged, filter, first, map, shareReplay, switchMap, tap, withLatestFrom } from 'rxjs/operators';
 
import { CheckoutFacade } from 'ish-core/facades/checkout.facade';
import { BasketView } from 'ish-core/models/basket/basket.model';
import { CheckoutStepType } from 'ish-core/models/checkout/checkout-step.type';
import { HttpError } from 'ish-core/models/http-error/http-error.model';
import { PaymentInstrument } from 'ish-core/models/payment-instrument/payment-instrument.model';
import { PaymentMethod } from 'ish-core/models/payment-method/payment-method.model';
import { Payment } from 'ish-core/models/payment/payment.model';
import { PriceType } from 'ish-core/models/price/price.model';
import { PaypalConfigService } from 'ish-core/utils/paypal/paypal-config/paypal-config.service';
 
@Component({
  selector: 'ish-checkout-payment-page',
  templateUrl: './checkout-payment-page.component.html',
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class CheckoutPaymentPageComponent implements OnInit {
  basket$: Observable<BasketView>;
  basketError$: Observable<HttpError>;
  loading$: Observable<boolean>;
  paymentMethods$: Observable<PaymentMethod[]>;
  priceType$: Observable<PriceType>;
 
  private destroyRef = inject(DestroyRef);
 
  private basketPayment: Payment;
 
  constructor(
    private checkoutFacade: CheckoutFacade,
    private paypalConfigService: PaypalConfigService
  ) {}
 
  ngOnInit() {
    this.basket$ = this.checkoutFacade.basket$.pipe(tap(basket => (this.basketPayment = basket?.payment)));
    this.basketError$ = this.checkoutFacade.basketError$;
    this.loading$ = this.checkoutFacade.basketLoading$;
    this.priceType$ = this.checkoutFacade.priceType$;
 
    this.paymentMethods$ = this.checkoutFacade.eligiblePaymentMethods$().pipe(
      withLatestFrom(this.basket$),
      map(([pmList, basket]) =>
        pmList?.filter(
          pm =>
            !pm.capabilities?.includes('FastCheckout') ||
            (pm.capabilities?.includes('FastCheckout') &&
              basket?.payment?.capabilities?.includes('FastCheckout') &&
              basket.payment.paymentInstrument.id === pm.id)
        )
      ),
      distinctUntilChanged(isEqual),
      switchMap(pmList => this.paypalConfigService.filterByPaypalEligibility(pmList)),
      shareReplay(1)
    );
 
    // if there is only one eligible payment method without parameters, assign it automatically to the basket
    this.paymentMethods$
      .pipe(
        filter(methods => methods?.length === 1),
        map(methods => methods[0]),
        filter(pm => !pm.parameters),
        first(),
        withLatestFrom(this.basket$),
        filter(([, basket]) => !basket?.payment),
        takeUntilDestroyed(this.destroyRef)
      )
      .subscribe(([pm]) => this.updateBasketPaymentMethod(pm.id));
  }
 
  updateBasketPaymentMethod(paymentName: string) {
    this.checkoutFacade.setBasketPayment(paymentName);
  }
 
  createPaymentInstrument(body: { paymentInstrument: PaymentInstrument; saveForLater: boolean }) {
    if (!body?.paymentInstrument) {
      return;
    }
    this.checkoutFacade.createBasketPayment(body.paymentInstrument, body.saveForLater);
  }
 
  deletePaymentInstrument(instrument: PaymentInstrument) {
    this.checkoutFacade.deleteBasketPayment(instrument);
  }
 
  /**
   * Validates the basket and jumps to the next checkout step (Review)
   */
  nextStep() {
    if (this.isPaymentRedirectRequired()) {
      // do a hard redirect to payment redirect URL
      this.checkoutFacade.startRedirectBeforeCheckout();
    } else {
      this.checkoutFacade.continue(CheckoutStepType.Review);
    }
  }
 
  private isPaymentRedirectRequired() {
    if (this.basketPayment) {
      return this.basketPayment.capabilities?.includes('RedirectBeforeCheckout') && this.basketPayment.redirectRequired;
    }
  }
}