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
122
123
124
125
126
127
128
129
130
131
|
---
import env from '../lib/env';
interface Props {
successPageUrl: string;
}
const { successPageUrl } = Astro.props;
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} data-success-page-url={successPageUrl}>
<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) {
const successPageUrl = this.dataset['successPageUrl'] ?? '.';
this.makePaypalButtons(constructButtons, successPageUrl).render(
'#paypal-button-container'
);
}
});
}
makePaypalButtons(
constructButtons: Required<PayPalNamespace>['Buttons'],
successPageUrl: string
) {
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}.
`);
console.info('Redirecting to confirmation page...');
window.location.href = successPageUrl;
},
});
}
}
customElements.define('paypal-buttons', PayPalButtons);
</script>
|