summaryrefslogtreecommitdiff
path: root/src/components/PayPalButtons.astro
blob: 0d9b606e454d5633454354f332a1128c65521685 (plain)
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
---
import env from '../lib/env';

const PAYPAL_CLIENT_ID = env.ENVIRONMENT === 'prod'
  ? env.PAYPAL_LIVE_CLIENT_ID
  : env.PAYPAL_SANDBOX_CLIENT_ID;
---

<paypal-buttons data-paypal-client-id={PAYPAL_CLIENT_ID}>
  <div id="paypal-button-container"></div>
</paypal-buttons>

<script>
  import { PayPalNamespace, loadScript } from '@paypal/paypal-js';

  const backendUrl = '/api';

  class PayPalButtons extends HTMLElement {
    constructor() {
      super();

      const paypalClientId = this.dataset['paypalClientId'];
      if (!paypalClientId || typeof(paypalClientId) !== 'string') {
        throw new Error('PayPal Client ID not provided to PayPalButtons component.');
      }

      const paypalOptions = {
        clientId: paypalClientId,
        locale: 'en_GB',
        commit: false,
        currency: 'GBP',
        intent: 'capture',
      };

      loadScript(paypalOptions).catch((err) => {
        throw new Error('Failed to load the PayPal JS SDK script. ', err);
      }).then(paypal => {
        const constructButtons = paypal?.Buttons;
        if (paypal && constructButtons) {
          this.makePaypalButtons(constructButtons).render('#paypal-button-container');
        }
      });
    }

    makePaypalButtons(constructButtons: Required<PayPalNamespace>['Buttons']) {
      return constructButtons({
        // This function is called to set up the transaction details without actually carrying it out
        async createOrder() {
          const body = JSON.stringify({
            productDescription: "my product description",
            shortDescription: "my product",
            totalPrice: 15.5,
          });
          const headers = {
            'Content-Type': 'application/json'
          };

          let response;
          try {
            response = await fetch(
              `${backendUrl}/order`, 
              { method: "POST", body, headers }
            );
          } catch (err) {
            throw new Error(`Failed to create order. ${err}`);
          }

          if (!response.ok) {
            throw new Error(`
              Failed to create order. Backend response was
              ${response.status} ${response.statusText}. ${await response.text()}
            `);
          }

          const { orderId, approvalLink } = await response.json();
          console.info(`
            Successfully created order with ID
            ${orderId}. Approval link: ${approvalLink}
          `);
          return orderId;
        },

        // This function is called after payment is confirmed
        async onApprove(data) {
          const body = JSON.stringify({
            id: data.orderID,
            isApproved: true
          });
          const headers = {
            'Content-Type': 'application/json',
          };

          let response;
          try {
            response = await fetch(
              `${backendUrl}/order`,
              { method: 'PATCH', body, headers }
            );
          } catch (err) {
            throw new Error(`Failed to capture order. ${err}`);
          }

          if (!response.ok) {
            throw new Error(`
              Failed to capture order. Backend response was ${response.status}
              ${response.statusText}. ${await response.text()}
            `);
          }

          const { orderId, requestStatus } = await response.json();
          console.info(`
            Successfully captured order with ID ${orderId},
            request status is ${requestStatus}.
          `);
        }
      });
    }
  }

  customElements.define('paypal-buttons', PayPalButtons);
</script>