Angular обработка PayPal, дочерний компонент и жизненный цикл - PullRequest
1 голос
/ 02 мая 2020

В настоящее время я работаю над интеграцией PayPal в своем собственном магазине (Angular Frontend, сделайте tnet core WebApi backend) и, по-видимому, у меня есть проблема с жизненным циклом между основным компонентом (CheckoutProcessComponent) и дочерним компонентом (PaymentPayPalComponent) и с использованием необходимого PayPal javascript.

По сути, полный рабочий процесс PayPal работает, пока я использую переменные stati c. И именно здесь начинается моя проблема.

CheckoutProcessComponent.ts

import { Component, OnInit } from '@angular/core';
import { CartService } from 'src/app/_services/shop/cart.service';
import { ISubscriptionCollection } from 'src/app/_models/misc/ISubscriptionCollection';
import { serialUnsubscriber } from 'src/app/shared/utility.module';
import { CheckoutService } from 'src/app/_services/checkout/checkout.service';
import { ICheckoutOrderData } from 'src/app/_models/shop/ICheckoutOrderData';
import { IOrderProcessSummary } from 'src/app/_models/shop/IOrderProcessSummary';

@Component({
  selector: 'app-checkout-process',
  templateUrl: './checkout-process.component.html',
  styleUrls: ['./checkout-process.component.css']
})
export class CheckoutProcessComponent implements OnInit {
  subscriptions: ISubscriptionCollection = {};

  checkoutOrderData = {} as ICheckoutOrderData;
  orderSummaryFromServer: IOrderProcessSummary;
  orderCreated: boolean = false;

  constructor(public checkoutService: CheckoutService, public cartService: CartService) { }

  ngOnInit() {    
    this.checkoutOrderData.Order = this.checkoutService.orderData;
    this.checkoutOrderData.Cart = this.cartService.shoppingCart;
    // Create Order
    this.subscriptions['createOrder'] = this.checkoutService.createOrder(this.checkoutOrderData)
      .subscribe((res: IOrderProcessSummary) => {
        this.checkoutService.checkoutSummary = res;
        this.orderSummaryFromServer = res;
        console.log('Order created: ' + res);
      }, error => {
        console.log('Error');
      });
  }

  ngOnDestroy(): void {
    serialUnsubscriber(...Object.values(this.subscriptions));
  }

  nextStep(step: number) {
    this.checkoutService.updateCheckoutStep(step);
  }
 ...
}

CheckoutProcessComponent. html

<app-payment-paypal [orderSummary]="orderSummaryFromServer" *ngIf="checkoutService.orderData.paymentMethod === 'PM_PAYPAL'"></app-payment-paypal>
<app-payment-stripe *ngIf="checkoutService.orderData.paymentMethod === 'PM_STRIPE'"></app-payment-stripe>
<app-payment-moneytransfer *ngIf="checkoutService.orderData.paymentMethod === 'PM_TRANSFER'"></app-payment-moneytransfer>

PaymentPayPalComponent.ts

import { Component, OnInit, AfterViewChecked, Input } from '@angular/core';
import { environment } from 'src/environments/environment';
import { IOrderProcessSummary } from 'src/app/_models/shop/IOrderProcessSummary';
import { CheckoutService } from 'src/app/_services/checkout/checkout.service';

declare let paypal: any;

@Component({
  selector: 'app-payment-paypal',
  templateUrl: './payment-paypal.component.html',
  styleUrls: ['./payment-paypal.component.css']
})
export class PaymentPaypalComponent implements OnInit, AfterViewChecked {
  @Input() orderSummary: IOrderProcessSummary;

  paypalClientId = environment.paymentPayPal.clientId;
  addScript: boolean = false;
  scriptTagElement: HTMLScriptElement;
  constructor(private checkoutService: CheckoutService) { }

  ngOnInit() {
  }

  ngOnDestroy(): void {
    if (this.scriptTagElement) {
      document.body.removeChild(this.scriptTagElement);
    }
  }

  ngAfterViewChecked(): void {
    if (!this.addScript) {
      this.addPayPalScript().then(() => {
        paypal.Buttons({
          createOrder: function() {
            return fetch('https://localhost:5021/api/payments/paypal-create-order', {
              method: 'post',
              headers: {
                'content-type': 'application/json'
              },
              body: JSON.stringify({
                orderId: 1234
              })
            }).then(function(res) {
              return res.json();
            }).then(function(data) {
              return data.id; // Use the same key name for order ID on the client and server
            });
          },
          onApprove: function(data, actions) {
            console.log('onApprove - transaction was approved, but not authorized', data, actions);
            actions.order.get().then(details => {
                    console.log('onApprove - you can get full order details inside onApprove: ', details);
            });

            return fetch('https://localhost:5021/api/payments/paypal-capture-order', {
              method: 'post',
              headers: {
                'content-type': 'application/json'
              },
              body: JSON.stringify({
                token:   data.orderID,
                payerID: data.payerID,
              })
            });
          },
          onClientAuthorization: (data) => {
            console.log('onClientAuthorization - you should probably inform your server about completed transaction at this point', data);
            // this.showSuccess = true;
          },
          onCancel: (data, actions) => {
            console.log('OnCancel', data, actions);
            // this.showCancel = true;
          },
          onError: err => {
            console.log('OnError', err);
            // this.showError = true;
          }
        }).render('#paypal-button-container');
      })
    }
  }

  addPayPalScript() {
    return new Promise((resolve, reject) => {
      this.scriptTagElement = document.createElement('script');
      this.scriptTagElement.src = 'https://www.paypal.com/sdk/js?currency=EUR&client-id=' + this.paypalClientId;
      this.scriptTagElement.onload = resolve;
      document.body.appendChild(this.scriptTagElement);
      this.addScript = true;
    })
  }

}

PaymentPayPalComponent. html

<div class="text-center" id="paypal-button-container"></div>

Процесс обработки выглядит следующим образом:

  1. CheckoutProcessComponent> создает заказ на сервере с данными корзины и сохраняет заказ в база данных (общая функция, не связанная с PayPal)
  2. Результатом из 1. является IOrderProcessSummary, который содержит идентификатор заказа и сумму заказа
  3. В зависимости от выбранного способа оплаты соответствующий Компонент Payment-Child будет отображаться. В этом случае PaymentPayPalComponent.
  4. Затем я использую функцию PayPal «CreatePayPalOrderOnServer», которая использует Api PayPal в моем бэкэнде для создания заказа на сервере PayPal. Но для этого мне нужен указанный c orderId, потому что мне нужно заполнить данные PayPal-Order указанными c данными заказа из моей системы (в этом примере у меня фиксированный идентификатор заказа 1234).

Для шага 4. Я пробовал это с параметром Input () и с внедрением CheckoutService в PaymentPayPalComponent, но я не могу работать с любым видом динамических c переменных внутри PayPal-Button-Function (JavaScript). В этом примере мне нужно изменить "orderId: 1234" со значением из InputSummary () или с тем же значением из CheckoutService, но оба они остаются неопределенными.

PayPal- Javascript загружены правильно, и кнопки PayPal отображаются и работают технически, как предполагалось.

Как мне перенести мои динамические c данные в PaymentPayPalComponent и в PayPal.Buttons-Function?

Спасибо за советы!

...