paymongo-cli 1.4.4 → 1.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/copilot-instructions.md +95 -95
- package/CHANGELOG.md +85 -1
- package/LICENSE +20 -20
- package/dist/.tsbuildinfo +1 -1
- package/dist/commands/config.js +30 -15
- package/dist/commands/dev/logs.js +3 -3
- package/dist/commands/dev/status.js +2 -2
- package/dist/commands/dev/stop.js +3 -3
- package/dist/commands/dev.js +9 -8
- package/dist/commands/env.js +6 -6
- package/dist/commands/generate/templates/checkout-page/index.js +520 -520
- package/dist/commands/generate/templates/payment-intent/javascript.js +68 -68
- package/dist/commands/generate/templates/payment-intent/typescript.js +92 -92
- package/dist/commands/generate/templates/webhook-handler/javascript.js +192 -147
- package/dist/commands/generate/templates/webhook-handler/typescript.js +147 -117
- package/dist/commands/generate.js +43 -37
- package/dist/commands/init.js +25 -8
- package/dist/commands/login.js +56 -19
- package/dist/commands/payments.js +9 -8
- package/dist/commands/team/index.js +11 -9
- package/dist/commands/trigger.js +58 -18
- package/dist/commands/webhooks.js +8 -7
- package/dist/index.js +9 -2
- package/dist/services/analytics/service.js +24 -19
- package/dist/services/api/client.js +16 -16
- package/dist/services/config/manager.js +6 -8
- package/dist/services/dev/process-manager.js +30 -32
- package/dist/services/dev/server.js +45 -39
- package/dist/services/team/service.js +4 -1
- package/dist/types/schemas.js +38 -9
- package/dist/utils/bulk.js +36 -4
- package/dist/utils/constants.js +11 -1
- package/dist/utils/errors.js +6 -0
- package/dist/utils/validator.js +10 -9
- package/dist/utils/webhook-store.js +18 -15
- package/eslint.config.ts +70 -70
- package/package.json +2 -2
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -281
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -281
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -5053
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/dist/commands/config.d.ts +0 -21
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/config.js.map +0 -1
- package/dist/commands/dev.d.ts +0 -16
- package/dist/commands/dev.d.ts.map +0 -1
- package/dist/commands/dev.js.map +0 -1
- package/dist/commands/env.d.ts +0 -4
- package/dist/commands/env.d.ts.map +0 -1
- package/dist/commands/env.js.map +0 -1
- package/dist/commands/init.d.ts +0 -15
- package/dist/commands/init.d.ts.map +0 -1
- package/dist/commands/init.js.map +0 -1
- package/dist/commands/login.d.ts +0 -20
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/login.js.map +0 -1
- package/dist/commands/payments.d.ts +0 -41
- package/dist/commands/payments.d.ts.map +0 -1
- package/dist/commands/payments.js.map +0 -1
- package/dist/commands/team/index.d.ts +0 -4
- package/dist/commands/team/index.d.ts.map +0 -1
- package/dist/commands/team/index.js.map +0 -1
- package/dist/commands/trigger.d.ts +0 -4
- package/dist/commands/trigger.d.ts.map +0 -1
- package/dist/commands/trigger.js.map +0 -1
- package/dist/commands/webhooks.d.ts +0 -23
- package/dist/commands/webhooks.d.ts.map +0 -1
- package/dist/commands/webhooks.js.map +0 -1
- package/dist/index.d.ts +0 -3
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/services/analytics/service.d.ts +0 -35
- package/dist/services/analytics/service.d.ts.map +0 -1
- package/dist/services/analytics/service.js.map +0 -1
- package/dist/services/api/client.d.ts +0 -26
- package/dist/services/api/client.d.ts.map +0 -1
- package/dist/services/api/client.js.map +0 -1
- package/dist/services/api/rate-limiter.d.ts +0 -64
- package/dist/services/api/rate-limiter.d.ts.map +0 -1
- package/dist/services/api/rate-limiter.js.map +0 -1
- package/dist/services/api/undici-client.d.ts +0 -39
- package/dist/services/api/undici-client.d.ts.map +0 -1
- package/dist/services/api/undici-client.js +0 -288
- package/dist/services/api/undici-client.js.map +0 -1
- package/dist/services/config/manager.d.ts +0 -16
- package/dist/services/config/manager.d.ts.map +0 -1
- package/dist/services/config/manager.js.map +0 -1
- package/dist/services/dev/process-manager.d.ts +0 -50
- package/dist/services/dev/process-manager.d.ts.map +0 -1
- package/dist/services/dev/process-manager.js.map +0 -1
- package/dist/services/github/auth.d.ts +0 -15
- package/dist/services/github/auth.d.ts.map +0 -1
- package/dist/services/github/auth.js +0 -79
- package/dist/services/github/auth.js.map +0 -1
- package/dist/services/github/client.d.ts +0 -95
- package/dist/services/github/client.d.ts.map +0 -1
- package/dist/services/github/client.js +0 -130
- package/dist/services/github/client.js.map +0 -1
- package/dist/services/github/sync.d.ts +0 -26
- package/dist/services/github/sync.d.ts.map +0 -1
- package/dist/services/github/sync.js +0 -203
- package/dist/services/github/sync.js.map +0 -1
- package/dist/services/payments/simulator.d.ts +0 -28
- package/dist/services/payments/simulator.d.ts.map +0 -1
- package/dist/services/payments/simulator.js.map +0 -1
- package/dist/services/team/service.d.ts +0 -44
- package/dist/services/team/service.d.ts.map +0 -1
- package/dist/services/team/service.js.map +0 -1
- package/dist/services/web/server.d.ts +0 -31
- package/dist/services/web/server.d.ts.map +0 -1
- package/dist/services/web/server.js +0 -206
- package/dist/services/web/server.js.map +0 -1
- package/dist/types/paymongo.d.ts +0 -204
- package/dist/types/paymongo.d.ts.map +0 -1
- package/dist/types/paymongo.js.map +0 -1
- package/dist/types/schemas.d.ts +0 -80
- package/dist/types/schemas.d.ts.map +0 -1
- package/dist/types/schemas.js.map +0 -1
- package/dist/utils/bulk.d.ts +0 -62
- package/dist/utils/bulk.d.ts.map +0 -1
- package/dist/utils/bulk.js.map +0 -1
- package/dist/utils/cache.d.ts +0 -22
- package/dist/utils/cache.d.ts.map +0 -1
- package/dist/utils/cache.js.map +0 -1
- package/dist/utils/constants.d.ts +0 -32
- package/dist/utils/constants.d.ts.map +0 -1
- package/dist/utils/constants.js.map +0 -1
- package/dist/utils/errors.d.ts +0 -34
- package/dist/utils/errors.d.ts.map +0 -1
- package/dist/utils/errors.js.map +0 -1
- package/dist/utils/logger.d.ts +0 -20
- package/dist/utils/logger.d.ts.map +0 -1
- package/dist/utils/logger.js.map +0 -1
- package/dist/utils/spinner.d.ts +0 -17
- package/dist/utils/spinner.d.ts.map +0 -1
- package/dist/utils/spinner.js.map +0 -1
- package/dist/utils/validator.d.ts +0 -10
- package/dist/utils/validator.d.ts.map +0 -1
- package/dist/utils/validator.js.map +0 -1
- package/dist/utils/webhook-store.d.ts +0 -22
- package/dist/utils/webhook-store.d.ts.map +0 -1
- package/dist/utils/webhook-store.js.map +0 -1
|
@@ -1,530 +1,530 @@
|
|
|
1
1
|
export function getHtmlTemplate() {
|
|
2
|
-
return `<!DOCTYPE html>
|
|
3
|
-
<html lang="en">
|
|
4
|
-
<head>
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>PayMongo Checkout</title>
|
|
8
|
-
<script src="https://js.paymongo.com/v1/paymongo.js"></script>
|
|
9
|
-
<style>
|
|
10
|
-
body {
|
|
11
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
12
|
-
max-width: 400px;
|
|
13
|
-
margin: 50px auto;
|
|
14
|
-
padding: 20px;
|
|
15
|
-
}
|
|
16
|
-
.checkout-form {
|
|
17
|
-
background: #f9f9f9;
|
|
18
|
-
padding: 20px;
|
|
19
|
-
border-radius: 8px;
|
|
20
|
-
}
|
|
21
|
-
.form-group {
|
|
22
|
-
margin-bottom: 15px;
|
|
23
|
-
}
|
|
24
|
-
label {
|
|
25
|
-
display: block;
|
|
26
|
-
margin-bottom: 5px;
|
|
27
|
-
font-weight: 500;
|
|
28
|
-
}
|
|
29
|
-
input, select {
|
|
30
|
-
width: 100%;
|
|
31
|
-
padding: 10px;
|
|
32
|
-
border: 1px solid #ddd;
|
|
33
|
-
border-radius: 4px;
|
|
34
|
-
font-size: 16px;
|
|
35
|
-
}
|
|
36
|
-
button {
|
|
37
|
-
width: 100%;
|
|
38
|
-
padding: 12px;
|
|
39
|
-
background: #007bff;
|
|
40
|
-
color: white;
|
|
41
|
-
border: none;
|
|
42
|
-
border-radius: 4px;
|
|
43
|
-
font-size: 16px;
|
|
44
|
-
cursor: pointer;
|
|
45
|
-
}
|
|
46
|
-
button:hover {
|
|
47
|
-
background: #0056b3;
|
|
48
|
-
}
|
|
49
|
-
button:disabled {
|
|
50
|
-
background: #ccc;
|
|
51
|
-
cursor: not-allowed;
|
|
52
|
-
}
|
|
53
|
-
</style>
|
|
54
|
-
</head>
|
|
55
|
-
<body>
|
|
56
|
-
<div class="checkout-form">
|
|
57
|
-
<h2>Complete Your Payment</h2>
|
|
58
|
-
<form id="payment-form">
|
|
59
|
-
<div class="form-group">
|
|
60
|
-
<label for="email">Email</label>
|
|
61
|
-
<input type="email" id="email" required>
|
|
62
|
-
</div>
|
|
63
|
-
|
|
64
|
-
<div class="form-group">
|
|
65
|
-
<label for="card-number">Card Number</label>
|
|
66
|
-
<input type="text" id="card-number" placeholder="1234 5678 9012 3456" required>
|
|
67
|
-
</div>
|
|
68
|
-
|
|
69
|
-
<div class="form-group">
|
|
70
|
-
<label for="expiry">Expiry Date</label>
|
|
71
|
-
<input type="text" id="expiry" placeholder="MM/YY" required>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
<div class="form-group">
|
|
75
|
-
<label for="cvc">CVC</label>
|
|
76
|
-
<input type="text" id="cvc" placeholder="123" required>
|
|
77
|
-
</div>
|
|
78
|
-
|
|
79
|
-
<button type="submit" id="pay-button">Pay ₱100.00</button>
|
|
80
|
-
</form>
|
|
81
|
-
</div>
|
|
82
|
-
|
|
83
|
-
<script>
|
|
84
|
-
// Replace with your actual client key from the payment intent
|
|
85
|
-
const clientKey = 'YOUR_CLIENT_KEY_HERE';
|
|
86
|
-
|
|
87
|
-
const paymongo = new Paymongo(clientKey);
|
|
88
|
-
|
|
89
|
-
document.getElementById('payment-form').addEventListener('submit', async (e) => {
|
|
90
|
-
e.preventDefault();
|
|
91
|
-
|
|
92
|
-
const payButton = document.getElementById('pay-button');
|
|
93
|
-
payButton.disabled = true;
|
|
94
|
-
payButton.textContent = 'Processing...';
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
// Create payment method
|
|
98
|
-
const paymentMethod = await paymongo.createPaymentMethod({
|
|
99
|
-
type: 'card',
|
|
100
|
-
details: {
|
|
101
|
-
card_number: document.getElementById('card-number').value.replace(/\\s/g, ''),
|
|
102
|
-
exp_month: document.getElementById('expiry').value.split('/')[0],
|
|
103
|
-
exp_year: '20' + document.getElementById('expiry').value.split('/')[1],
|
|
104
|
-
cvc: document.getElementById('cvc').value,
|
|
105
|
-
},
|
|
106
|
-
billing: {
|
|
107
|
-
email: document.getElementById('email').value,
|
|
108
|
-
},
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
// Attach payment method to payment intent
|
|
112
|
-
const result = await paymongo.attachPaymentIntent('YOUR_PAYMENT_INTENT_ID', {
|
|
113
|
-
payment_method: paymentMethod.id,
|
|
114
|
-
return_url: window.location.origin + '/success',
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
if (result.next_action) {
|
|
118
|
-
// Handle 3D Secure or other next actions
|
|
119
|
-
window.location.href = result.next_action.redirect.url;
|
|
120
|
-
} else {
|
|
121
|
-
// Payment succeeded
|
|
122
|
-
window.location.href = '/success';
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
} catch (error) {
|
|
126
|
-
console.error('Payment failed:', error);
|
|
127
|
-
alert('Payment failed. Please try again.');
|
|
128
|
-
payButton.disabled = false;
|
|
129
|
-
payButton.textContent = 'Pay ₱100.00';
|
|
130
|
-
}
|
|
131
|
-
});
|
|
132
|
-
</script>
|
|
133
|
-
</body>
|
|
2
|
+
return `<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>PayMongo Checkout</title>
|
|
8
|
+
<script src="https://js.paymongo.com/v1/paymongo.js"></script>
|
|
9
|
+
<style>
|
|
10
|
+
body {
|
|
11
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
12
|
+
max-width: 400px;
|
|
13
|
+
margin: 50px auto;
|
|
14
|
+
padding: 20px;
|
|
15
|
+
}
|
|
16
|
+
.checkout-form {
|
|
17
|
+
background: #f9f9f9;
|
|
18
|
+
padding: 20px;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
}
|
|
21
|
+
.form-group {
|
|
22
|
+
margin-bottom: 15px;
|
|
23
|
+
}
|
|
24
|
+
label {
|
|
25
|
+
display: block;
|
|
26
|
+
margin-bottom: 5px;
|
|
27
|
+
font-weight: 500;
|
|
28
|
+
}
|
|
29
|
+
input, select {
|
|
30
|
+
width: 100%;
|
|
31
|
+
padding: 10px;
|
|
32
|
+
border: 1px solid #ddd;
|
|
33
|
+
border-radius: 4px;
|
|
34
|
+
font-size: 16px;
|
|
35
|
+
}
|
|
36
|
+
button {
|
|
37
|
+
width: 100%;
|
|
38
|
+
padding: 12px;
|
|
39
|
+
background: #007bff;
|
|
40
|
+
color: white;
|
|
41
|
+
border: none;
|
|
42
|
+
border-radius: 4px;
|
|
43
|
+
font-size: 16px;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
}
|
|
46
|
+
button:hover {
|
|
47
|
+
background: #0056b3;
|
|
48
|
+
}
|
|
49
|
+
button:disabled {
|
|
50
|
+
background: #ccc;
|
|
51
|
+
cursor: not-allowed;
|
|
52
|
+
}
|
|
53
|
+
</style>
|
|
54
|
+
</head>
|
|
55
|
+
<body>
|
|
56
|
+
<div class="checkout-form">
|
|
57
|
+
<h2>Complete Your Payment</h2>
|
|
58
|
+
<form id="payment-form">
|
|
59
|
+
<div class="form-group">
|
|
60
|
+
<label for="email">Email</label>
|
|
61
|
+
<input type="email" id="email" required>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div class="form-group">
|
|
65
|
+
<label for="card-number">Card Number</label>
|
|
66
|
+
<input type="text" id="card-number" placeholder="1234 5678 9012 3456" required>
|
|
67
|
+
</div>
|
|
68
|
+
|
|
69
|
+
<div class="form-group">
|
|
70
|
+
<label for="expiry">Expiry Date</label>
|
|
71
|
+
<input type="text" id="expiry" placeholder="MM/YY" required>
|
|
72
|
+
</div>
|
|
73
|
+
|
|
74
|
+
<div class="form-group">
|
|
75
|
+
<label for="cvc">CVC</label>
|
|
76
|
+
<input type="text" id="cvc" placeholder="123" required>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<button type="submit" id="pay-button">Pay ₱100.00</button>
|
|
80
|
+
</form>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
<script>
|
|
84
|
+
// Replace with your actual client key from the payment intent
|
|
85
|
+
const clientKey = 'YOUR_CLIENT_KEY_HERE';
|
|
86
|
+
|
|
87
|
+
const paymongo = new Paymongo(clientKey);
|
|
88
|
+
|
|
89
|
+
document.getElementById('payment-form').addEventListener('submit', async (e) => {
|
|
90
|
+
e.preventDefault();
|
|
91
|
+
|
|
92
|
+
const payButton = document.getElementById('pay-button');
|
|
93
|
+
payButton.disabled = true;
|
|
94
|
+
payButton.textContent = 'Processing...';
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
// Create payment method
|
|
98
|
+
const paymentMethod = await paymongo.createPaymentMethod({
|
|
99
|
+
type: 'card',
|
|
100
|
+
details: {
|
|
101
|
+
card_number: document.getElementById('card-number').value.replace(/\\s/g, ''),
|
|
102
|
+
exp_month: document.getElementById('expiry').value.split('/')[0],
|
|
103
|
+
exp_year: '20' + document.getElementById('expiry').value.split('/')[1],
|
|
104
|
+
cvc: document.getElementById('cvc').value,
|
|
105
|
+
},
|
|
106
|
+
billing: {
|
|
107
|
+
email: document.getElementById('email').value,
|
|
108
|
+
},
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
// Attach payment method to payment intent
|
|
112
|
+
const result = await paymongo.attachPaymentIntent('YOUR_PAYMENT_INTENT_ID', {
|
|
113
|
+
payment_method: paymentMethod.id,
|
|
114
|
+
return_url: window.location.origin + '/success',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (result.next_action) {
|
|
118
|
+
// Handle 3D Secure or other next actions
|
|
119
|
+
window.location.href = result.next_action.redirect.url;
|
|
120
|
+
} else {
|
|
121
|
+
// Payment succeeded
|
|
122
|
+
window.location.href = '/success';
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error('Payment failed:', error);
|
|
127
|
+
alert('Payment failed. Please try again.');
|
|
128
|
+
payButton.disabled = false;
|
|
129
|
+
payButton.textContent = 'Pay ₱100.00';
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
</script>
|
|
133
|
+
</body>
|
|
134
134
|
</html>`;
|
|
135
135
|
}
|
|
136
136
|
export function getReactTemplate() {
|
|
137
|
-
return `import React, { useState } from 'react';
|
|
138
|
-
|
|
139
|
-
interface CheckoutFormProps {
|
|
140
|
-
clientKey: string;
|
|
141
|
-
paymentIntentId: string;
|
|
142
|
-
amount: number;
|
|
143
|
-
onSuccess: (result: any) => void;
|
|
144
|
-
onError: (error: any) => void;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
const CheckoutForm: React.FC<CheckoutFormProps> = ({
|
|
148
|
-
clientKey,
|
|
149
|
-
paymentIntentId,
|
|
150
|
-
amount,
|
|
151
|
-
onSuccess,
|
|
152
|
-
onError
|
|
153
|
-
}) => {
|
|
154
|
-
const [loading, setLoading] = useState(false);
|
|
155
|
-
const [formData, setFormData] = useState({
|
|
156
|
-
email: '',
|
|
157
|
-
cardNumber: '',
|
|
158
|
-
expiry: '',
|
|
159
|
-
cvc: ''
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
163
|
-
const { name, value } = e.target;
|
|
164
|
-
setFormData(prev => ({
|
|
165
|
-
...prev,
|
|
166
|
-
[name]: value
|
|
167
|
-
}));
|
|
168
|
-
};
|
|
169
|
-
|
|
170
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
171
|
-
e.preventDefault();
|
|
172
|
-
setLoading(true);
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
// Load PayMongo script dynamically if not already loaded
|
|
176
|
-
if (!window.Paymongo) {
|
|
177
|
-
await new Promise((resolve, reject) => {
|
|
178
|
-
const script = document.createElement('script');
|
|
179
|
-
script.src = 'https://js.paymongo.com/v1/paymongo.js';
|
|
180
|
-
script.onload = resolve;
|
|
181
|
-
script.onerror = reject;
|
|
182
|
-
document.head.appendChild(script);
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
const paymongo = new (window as any).Paymongo(clientKey);
|
|
187
|
-
|
|
188
|
-
// Create payment method
|
|
189
|
-
const paymentMethod = await paymongo.createPaymentMethod({
|
|
190
|
-
type: 'card',
|
|
191
|
-
details: {
|
|
192
|
-
card_number: formData.cardNumber.replace(/\\s/g, ''),
|
|
193
|
-
exp_month: parseInt(formData.expiry.split('/')[0]),
|
|
194
|
-
exp_year: 2000 + parseInt(formData.expiry.split('/')[1]),
|
|
195
|
-
cvc: formData.cvc,
|
|
196
|
-
},
|
|
197
|
-
billing: {
|
|
198
|
-
email: formData.email,
|
|
199
|
-
},
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
// Attach payment method to payment intent
|
|
203
|
-
const result = await paymongo.attachPaymentIntent(paymentIntentId, {
|
|
204
|
-
payment_method: paymentMethod.id,
|
|
205
|
-
return_url: window.location.origin + '/success',
|
|
206
|
-
});
|
|
207
|
-
|
|
208
|
-
onSuccess(result);
|
|
209
|
-
|
|
210
|
-
} catch (error) {
|
|
211
|
-
onError(error);
|
|
212
|
-
} finally {
|
|
213
|
-
setLoading(false);
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
|
|
217
|
-
return (
|
|
218
|
-
<div style={{ maxWidth: '400px', margin: '50px auto', padding: '20px' }}>
|
|
219
|
-
<div style={{
|
|
220
|
-
background: '#f9f9f9',
|
|
221
|
-
padding: '20px',
|
|
222
|
-
borderRadius: '8px'
|
|
223
|
-
}}>
|
|
224
|
-
<h2>Complete Your Payment</h2>
|
|
225
|
-
<form onSubmit={handleSubmit}>
|
|
226
|
-
<div style={{ marginBottom: '15px' }}>
|
|
227
|
-
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
228
|
-
Email
|
|
229
|
-
</label>
|
|
230
|
-
<input
|
|
231
|
-
type="email"
|
|
232
|
-
name="email"
|
|
233
|
-
value={formData.email}
|
|
234
|
-
onChange={handleInputChange}
|
|
235
|
-
required
|
|
236
|
-
style={{
|
|
237
|
-
width: '100%',
|
|
238
|
-
padding: '10px',
|
|
239
|
-
border: '1px solid #ddd',
|
|
240
|
-
borderRadius: '4px',
|
|
241
|
-
fontSize: '16px'
|
|
242
|
-
}}
|
|
243
|
-
/>
|
|
244
|
-
</div>
|
|
245
|
-
|
|
246
|
-
<div style={{ marginBottom: '15px' }}>
|
|
247
|
-
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
248
|
-
Card Number
|
|
249
|
-
</label>
|
|
250
|
-
<input
|
|
251
|
-
type="text"
|
|
252
|
-
name="cardNumber"
|
|
253
|
-
value={formData.cardNumber}
|
|
254
|
-
onChange={handleInputChange}
|
|
255
|
-
placeholder="1234 5678 9012 3456"
|
|
256
|
-
required
|
|
257
|
-
style={{
|
|
258
|
-
width: '100%',
|
|
259
|
-
padding: '10px',
|
|
260
|
-
border: '1px solid #ddd',
|
|
261
|
-
borderRadius: '4px',
|
|
262
|
-
fontSize: '16px'
|
|
263
|
-
}}
|
|
264
|
-
/>
|
|
265
|
-
</div>
|
|
266
|
-
|
|
267
|
-
<div style={{ marginBottom: '15px' }}>
|
|
268
|
-
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
269
|
-
Expiry Date
|
|
270
|
-
</label>
|
|
271
|
-
<input
|
|
272
|
-
type="text"
|
|
273
|
-
name="expiry"
|
|
274
|
-
value={formData.expiry}
|
|
275
|
-
onChange={handleInputChange}
|
|
276
|
-
placeholder="MM/YY"
|
|
277
|
-
required
|
|
278
|
-
style={{
|
|
279
|
-
width: '100%',
|
|
280
|
-
padding: '10px',
|
|
281
|
-
border: '1px solid #ddd',
|
|
282
|
-
borderRadius: '4px',
|
|
283
|
-
fontSize: '16px'
|
|
284
|
-
}}
|
|
285
|
-
/>
|
|
286
|
-
</div>
|
|
287
|
-
|
|
288
|
-
<div style={{ marginBottom: '15px' }}>
|
|
289
|
-
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
290
|
-
CVC
|
|
291
|
-
</label>
|
|
292
|
-
<input
|
|
293
|
-
type="text"
|
|
294
|
-
name="cvc"
|
|
295
|
-
value={formData.cvc}
|
|
296
|
-
onChange={handleInputChange}
|
|
297
|
-
placeholder="123"
|
|
298
|
-
required
|
|
299
|
-
style={{
|
|
300
|
-
width: '100%',
|
|
301
|
-
padding: '10px',
|
|
302
|
-
border: '1px solid #ddd',
|
|
303
|
-
borderRadius: '4px',
|
|
304
|
-
fontSize: '16px'
|
|
305
|
-
}}
|
|
306
|
-
/>
|
|
307
|
-
</div>
|
|
308
|
-
|
|
309
|
-
<button
|
|
310
|
-
type="submit"
|
|
311
|
-
disabled={loading}
|
|
312
|
-
style={{
|
|
313
|
-
width: '100%',
|
|
314
|
-
padding: '12px',
|
|
315
|
-
background: loading ? '#ccc' : '#007bff',
|
|
316
|
-
color: 'white',
|
|
317
|
-
border: 'none',
|
|
318
|
-
borderRadius: '4px',
|
|
319
|
-
fontSize: '16px',
|
|
320
|
-
cursor: loading ? 'not-allowed' : 'pointer'
|
|
321
|
-
}}
|
|
322
|
-
>
|
|
323
|
-
{loading ? 'Processing...' : \`Pay ₱\${(amount / 100).toFixed(2)}\`}
|
|
324
|
-
</button>
|
|
325
|
-
</form>
|
|
326
|
-
</div>
|
|
327
|
-
</div>
|
|
328
|
-
);
|
|
329
|
-
};
|
|
330
|
-
|
|
137
|
+
return `import React, { useState } from 'react';
|
|
138
|
+
|
|
139
|
+
interface CheckoutFormProps {
|
|
140
|
+
clientKey: string;
|
|
141
|
+
paymentIntentId: string;
|
|
142
|
+
amount: number;
|
|
143
|
+
onSuccess: (result: any) => void;
|
|
144
|
+
onError: (error: any) => void;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const CheckoutForm: React.FC<CheckoutFormProps> = ({
|
|
148
|
+
clientKey,
|
|
149
|
+
paymentIntentId,
|
|
150
|
+
amount,
|
|
151
|
+
onSuccess,
|
|
152
|
+
onError
|
|
153
|
+
}) => {
|
|
154
|
+
const [loading, setLoading] = useState(false);
|
|
155
|
+
const [formData, setFormData] = useState({
|
|
156
|
+
email: '',
|
|
157
|
+
cardNumber: '',
|
|
158
|
+
expiry: '',
|
|
159
|
+
cvc: ''
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
163
|
+
const { name, value } = e.target;
|
|
164
|
+
setFormData(prev => ({
|
|
165
|
+
...prev,
|
|
166
|
+
[name]: value
|
|
167
|
+
}));
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
const handleSubmit = async (e: React.FormEvent) => {
|
|
171
|
+
e.preventDefault();
|
|
172
|
+
setLoading(true);
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
// Load PayMongo script dynamically if not already loaded
|
|
176
|
+
if (!window.Paymongo) {
|
|
177
|
+
await new Promise((resolve, reject) => {
|
|
178
|
+
const script = document.createElement('script');
|
|
179
|
+
script.src = 'https://js.paymongo.com/v1/paymongo.js';
|
|
180
|
+
script.onload = resolve;
|
|
181
|
+
script.onerror = reject;
|
|
182
|
+
document.head.appendChild(script);
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const paymongo = new (window as any).Paymongo(clientKey);
|
|
187
|
+
|
|
188
|
+
// Create payment method
|
|
189
|
+
const paymentMethod = await paymongo.createPaymentMethod({
|
|
190
|
+
type: 'card',
|
|
191
|
+
details: {
|
|
192
|
+
card_number: formData.cardNumber.replace(/\\s/g, ''),
|
|
193
|
+
exp_month: parseInt(formData.expiry.split('/')[0]),
|
|
194
|
+
exp_year: 2000 + parseInt(formData.expiry.split('/')[1]),
|
|
195
|
+
cvc: formData.cvc,
|
|
196
|
+
},
|
|
197
|
+
billing: {
|
|
198
|
+
email: formData.email,
|
|
199
|
+
},
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// Attach payment method to payment intent
|
|
203
|
+
const result = await paymongo.attachPaymentIntent(paymentIntentId, {
|
|
204
|
+
payment_method: paymentMethod.id,
|
|
205
|
+
return_url: window.location.origin + '/success',
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
onSuccess(result);
|
|
209
|
+
|
|
210
|
+
} catch (error) {
|
|
211
|
+
onError(error);
|
|
212
|
+
} finally {
|
|
213
|
+
setLoading(false);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
return (
|
|
218
|
+
<div style={{ maxWidth: '400px', margin: '50px auto', padding: '20px' }}>
|
|
219
|
+
<div style={{
|
|
220
|
+
background: '#f9f9f9',
|
|
221
|
+
padding: '20px',
|
|
222
|
+
borderRadius: '8px'
|
|
223
|
+
}}>
|
|
224
|
+
<h2>Complete Your Payment</h2>
|
|
225
|
+
<form onSubmit={handleSubmit}>
|
|
226
|
+
<div style={{ marginBottom: '15px' }}>
|
|
227
|
+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
228
|
+
Email
|
|
229
|
+
</label>
|
|
230
|
+
<input
|
|
231
|
+
type="email"
|
|
232
|
+
name="email"
|
|
233
|
+
value={formData.email}
|
|
234
|
+
onChange={handleInputChange}
|
|
235
|
+
required
|
|
236
|
+
style={{
|
|
237
|
+
width: '100%',
|
|
238
|
+
padding: '10px',
|
|
239
|
+
border: '1px solid #ddd',
|
|
240
|
+
borderRadius: '4px',
|
|
241
|
+
fontSize: '16px'
|
|
242
|
+
}}
|
|
243
|
+
/>
|
|
244
|
+
</div>
|
|
245
|
+
|
|
246
|
+
<div style={{ marginBottom: '15px' }}>
|
|
247
|
+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
248
|
+
Card Number
|
|
249
|
+
</label>
|
|
250
|
+
<input
|
|
251
|
+
type="text"
|
|
252
|
+
name="cardNumber"
|
|
253
|
+
value={formData.cardNumber}
|
|
254
|
+
onChange={handleInputChange}
|
|
255
|
+
placeholder="1234 5678 9012 3456"
|
|
256
|
+
required
|
|
257
|
+
style={{
|
|
258
|
+
width: '100%',
|
|
259
|
+
padding: '10px',
|
|
260
|
+
border: '1px solid #ddd',
|
|
261
|
+
borderRadius: '4px',
|
|
262
|
+
fontSize: '16px'
|
|
263
|
+
}}
|
|
264
|
+
/>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
<div style={{ marginBottom: '15px' }}>
|
|
268
|
+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
269
|
+
Expiry Date
|
|
270
|
+
</label>
|
|
271
|
+
<input
|
|
272
|
+
type="text"
|
|
273
|
+
name="expiry"
|
|
274
|
+
value={formData.expiry}
|
|
275
|
+
onChange={handleInputChange}
|
|
276
|
+
placeholder="MM/YY"
|
|
277
|
+
required
|
|
278
|
+
style={{
|
|
279
|
+
width: '100%',
|
|
280
|
+
padding: '10px',
|
|
281
|
+
border: '1px solid #ddd',
|
|
282
|
+
borderRadius: '4px',
|
|
283
|
+
fontSize: '16px'
|
|
284
|
+
}}
|
|
285
|
+
/>
|
|
286
|
+
</div>
|
|
287
|
+
|
|
288
|
+
<div style={{ marginBottom: '15px' }}>
|
|
289
|
+
<label style={{ display: 'block', marginBottom: '5px', fontWeight: '500' }}>
|
|
290
|
+
CVC
|
|
291
|
+
</label>
|
|
292
|
+
<input
|
|
293
|
+
type="text"
|
|
294
|
+
name="cvc"
|
|
295
|
+
value={formData.cvc}
|
|
296
|
+
onChange={handleInputChange}
|
|
297
|
+
placeholder="123"
|
|
298
|
+
required
|
|
299
|
+
style={{
|
|
300
|
+
width: '100%',
|
|
301
|
+
padding: '10px',
|
|
302
|
+
border: '1px solid #ddd',
|
|
303
|
+
borderRadius: '4px',
|
|
304
|
+
fontSize: '16px'
|
|
305
|
+
}}
|
|
306
|
+
/>
|
|
307
|
+
</div>
|
|
308
|
+
|
|
309
|
+
<button
|
|
310
|
+
type="submit"
|
|
311
|
+
disabled={loading}
|
|
312
|
+
style={{
|
|
313
|
+
width: '100%',
|
|
314
|
+
padding: '12px',
|
|
315
|
+
background: loading ? '#ccc' : '#007bff',
|
|
316
|
+
color: 'white',
|
|
317
|
+
border: 'none',
|
|
318
|
+
borderRadius: '4px',
|
|
319
|
+
fontSize: '16px',
|
|
320
|
+
cursor: loading ? 'not-allowed' : 'pointer'
|
|
321
|
+
}}
|
|
322
|
+
>
|
|
323
|
+
{loading ? 'Processing...' : \`Pay ₱\${(amount / 100).toFixed(2)}\`}
|
|
324
|
+
</button>
|
|
325
|
+
</form>
|
|
326
|
+
</div>
|
|
327
|
+
</div>
|
|
328
|
+
);
|
|
329
|
+
};
|
|
330
|
+
|
|
331
331
|
export default CheckoutForm;`;
|
|
332
332
|
}
|
|
333
333
|
export function getVueTemplate() {
|
|
334
|
-
return `<template>
|
|
335
|
-
<div class="checkout-container">
|
|
336
|
-
<div class="checkout-form">
|
|
337
|
-
<h2>Complete Your Payment</h2>
|
|
338
|
-
<form @submit.prevent="handleSubmit">
|
|
339
|
-
<div class="form-group">
|
|
340
|
-
<label for="email">Email</label>
|
|
341
|
-
<input
|
|
342
|
-
v-model="formData.email"
|
|
343
|
-
type="email"
|
|
344
|
-
id="email"
|
|
345
|
-
required
|
|
346
|
-
>
|
|
347
|
-
</div>
|
|
348
|
-
|
|
349
|
-
<div class="form-group">
|
|
350
|
-
<label for="cardNumber">Card Number</label>
|
|
351
|
-
<input
|
|
352
|
-
v-model="formData.cardNumber"
|
|
353
|
-
type="text"
|
|
354
|
-
id="cardNumber"
|
|
355
|
-
placeholder="1234 5678 9012 3456"
|
|
356
|
-
required
|
|
357
|
-
>
|
|
358
|
-
</div>
|
|
359
|
-
|
|
360
|
-
<div class="form-group">
|
|
361
|
-
<label for="expiry">Expiry Date</label>
|
|
362
|
-
<input
|
|
363
|
-
v-model="formData.expiry"
|
|
364
|
-
type="text"
|
|
365
|
-
id="expiry"
|
|
366
|
-
placeholder="MM/YY"
|
|
367
|
-
required
|
|
368
|
-
>
|
|
369
|
-
</div>
|
|
370
|
-
|
|
371
|
-
<div class="form-group">
|
|
372
|
-
<label for="cvc">CVC</label>
|
|
373
|
-
<input
|
|
374
|
-
v-model="formData.cvc"
|
|
375
|
-
type="text"
|
|
376
|
-
id="cvc"
|
|
377
|
-
placeholder="123"
|
|
378
|
-
required
|
|
379
|
-
>
|
|
380
|
-
</div>
|
|
381
|
-
|
|
382
|
-
<button
|
|
383
|
-
type="submit"
|
|
384
|
-
:disabled="loading"
|
|
385
|
-
class="pay-button"
|
|
386
|
-
>
|
|
387
|
-
{{ loading ? 'Processing...' : \`Pay ₱\${(amount / 100).toFixed(2)}\` }}
|
|
388
|
-
</button>
|
|
389
|
-
</form>
|
|
390
|
-
</div>
|
|
391
|
-
</div>
|
|
392
|
-
</template>
|
|
393
|
-
|
|
394
|
-
<script>
|
|
395
|
-
export default {
|
|
396
|
-
name: 'CheckoutForm',
|
|
397
|
-
props: {
|
|
398
|
-
clientKey: {
|
|
399
|
-
type: String,
|
|
400
|
-
required: true
|
|
401
|
-
},
|
|
402
|
-
paymentIntentId: {
|
|
403
|
-
type: String,
|
|
404
|
-
required: true
|
|
405
|
-
},
|
|
406
|
-
amount: {
|
|
407
|
-
type: Number,
|
|
408
|
-
required: true
|
|
409
|
-
}
|
|
410
|
-
},
|
|
411
|
-
data() {
|
|
412
|
-
return {
|
|
413
|
-
loading: false,
|
|
414
|
-
formData: {
|
|
415
|
-
email: '',
|
|
416
|
-
cardNumber: '',
|
|
417
|
-
expiry: '',
|
|
418
|
-
cvc: ''
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
},
|
|
422
|
-
methods: {
|
|
423
|
-
async handleSubmit() {
|
|
424
|
-
this.loading = true;
|
|
425
|
-
|
|
426
|
-
try {
|
|
427
|
-
// Load PayMongo script if not loaded
|
|
428
|
-
if (!window.Paymongo) {
|
|
429
|
-
await this.loadPayMongoScript();
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
const paymongo = new window.Paymongo(this.clientKey);
|
|
433
|
-
|
|
434
|
-
// Create payment method
|
|
435
|
-
const paymentMethod = await paymongo.createPaymentMethod({
|
|
436
|
-
type: 'card',
|
|
437
|
-
details: {
|
|
438
|
-
card_number: this.formData.cardNumber.replace(/\\s/g, ''),
|
|
439
|
-
exp_month: parseInt(this.formData.expiry.split('/')[0]),
|
|
440
|
-
exp_year: 2000 + parseInt(this.formData.expiry.split('/')[1]),
|
|
441
|
-
cvc: this.formData.cvc,
|
|
442
|
-
},
|
|
443
|
-
billing: {
|
|
444
|
-
email: this.formData.email,
|
|
445
|
-
},
|
|
446
|
-
});
|
|
447
|
-
|
|
448
|
-
// Attach payment method to payment intent
|
|
449
|
-
const result = await paymongo.attachPaymentIntent(this.paymentIntentId, {
|
|
450
|
-
payment_method: paymentMethod.id,
|
|
451
|
-
return_url: window.location.origin + '/success',
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
this.$emit('success', result);
|
|
455
|
-
|
|
456
|
-
} catch (error) {
|
|
457
|
-
console.error('Payment failed:', error);
|
|
458
|
-
this.$emit('error', error);
|
|
459
|
-
} finally {
|
|
460
|
-
this.loading = false;
|
|
461
|
-
}
|
|
462
|
-
},
|
|
463
|
-
|
|
464
|
-
loadPayMongoScript() {
|
|
465
|
-
return new Promise((resolve, reject) => {
|
|
466
|
-
const script = document.createElement('script');
|
|
467
|
-
script.src = 'https://js.paymongo.com/v1/paymongo.js';
|
|
468
|
-
script.onload = resolve;
|
|
469
|
-
script.onerror = reject;
|
|
470
|
-
document.head.appendChild(script);
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
};
|
|
475
|
-
</script>
|
|
476
|
-
|
|
477
|
-
<style scoped>
|
|
478
|
-
.checkout-container {
|
|
479
|
-
max-width: 400px;
|
|
480
|
-
margin: 50px auto;
|
|
481
|
-
padding: 20px;
|
|
482
|
-
}
|
|
483
|
-
|
|
484
|
-
.checkout-form {
|
|
485
|
-
background: #f9f9f9;
|
|
486
|
-
padding: 20px;
|
|
487
|
-
border-radius: 8px;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
.form-group {
|
|
491
|
-
margin-bottom: 15px;
|
|
492
|
-
}
|
|
493
|
-
|
|
494
|
-
label {
|
|
495
|
-
display: block;
|
|
496
|
-
margin-bottom: 5px;
|
|
497
|
-
font-weight: 500;
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
input {
|
|
501
|
-
width: 100%;
|
|
502
|
-
padding: 10px;
|
|
503
|
-
border: 1px solid #ddd;
|
|
504
|
-
border-radius: 4px;
|
|
505
|
-
font-size: 16px;
|
|
506
|
-
box-sizing: border-box;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
.pay-button {
|
|
510
|
-
width: 100%;
|
|
511
|
-
padding: 12px;
|
|
512
|
-
background: #007bff;
|
|
513
|
-
color: white;
|
|
514
|
-
border: none;
|
|
515
|
-
border-radius: 4px;
|
|
516
|
-
font-size: 16px;
|
|
517
|
-
cursor: pointer;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
.pay-button:hover:not(:disabled) {
|
|
521
|
-
background: #0056b3;
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
.pay-button:disabled {
|
|
525
|
-
background: #ccc;
|
|
526
|
-
cursor: not-allowed;
|
|
527
|
-
}
|
|
334
|
+
return `<template>
|
|
335
|
+
<div class="checkout-container">
|
|
336
|
+
<div class="checkout-form">
|
|
337
|
+
<h2>Complete Your Payment</h2>
|
|
338
|
+
<form @submit.prevent="handleSubmit">
|
|
339
|
+
<div class="form-group">
|
|
340
|
+
<label for="email">Email</label>
|
|
341
|
+
<input
|
|
342
|
+
v-model="formData.email"
|
|
343
|
+
type="email"
|
|
344
|
+
id="email"
|
|
345
|
+
required
|
|
346
|
+
>
|
|
347
|
+
</div>
|
|
348
|
+
|
|
349
|
+
<div class="form-group">
|
|
350
|
+
<label for="cardNumber">Card Number</label>
|
|
351
|
+
<input
|
|
352
|
+
v-model="formData.cardNumber"
|
|
353
|
+
type="text"
|
|
354
|
+
id="cardNumber"
|
|
355
|
+
placeholder="1234 5678 9012 3456"
|
|
356
|
+
required
|
|
357
|
+
>
|
|
358
|
+
</div>
|
|
359
|
+
|
|
360
|
+
<div class="form-group">
|
|
361
|
+
<label for="expiry">Expiry Date</label>
|
|
362
|
+
<input
|
|
363
|
+
v-model="formData.expiry"
|
|
364
|
+
type="text"
|
|
365
|
+
id="expiry"
|
|
366
|
+
placeholder="MM/YY"
|
|
367
|
+
required
|
|
368
|
+
>
|
|
369
|
+
</div>
|
|
370
|
+
|
|
371
|
+
<div class="form-group">
|
|
372
|
+
<label for="cvc">CVC</label>
|
|
373
|
+
<input
|
|
374
|
+
v-model="formData.cvc"
|
|
375
|
+
type="text"
|
|
376
|
+
id="cvc"
|
|
377
|
+
placeholder="123"
|
|
378
|
+
required
|
|
379
|
+
>
|
|
380
|
+
</div>
|
|
381
|
+
|
|
382
|
+
<button
|
|
383
|
+
type="submit"
|
|
384
|
+
:disabled="loading"
|
|
385
|
+
class="pay-button"
|
|
386
|
+
>
|
|
387
|
+
{{ loading ? 'Processing...' : \`Pay ₱\${(amount / 100).toFixed(2)}\` }}
|
|
388
|
+
</button>
|
|
389
|
+
</form>
|
|
390
|
+
</div>
|
|
391
|
+
</div>
|
|
392
|
+
</template>
|
|
393
|
+
|
|
394
|
+
<script>
|
|
395
|
+
export default {
|
|
396
|
+
name: 'CheckoutForm',
|
|
397
|
+
props: {
|
|
398
|
+
clientKey: {
|
|
399
|
+
type: String,
|
|
400
|
+
required: true
|
|
401
|
+
},
|
|
402
|
+
paymentIntentId: {
|
|
403
|
+
type: String,
|
|
404
|
+
required: true
|
|
405
|
+
},
|
|
406
|
+
amount: {
|
|
407
|
+
type: Number,
|
|
408
|
+
required: true
|
|
409
|
+
}
|
|
410
|
+
},
|
|
411
|
+
data() {
|
|
412
|
+
return {
|
|
413
|
+
loading: false,
|
|
414
|
+
formData: {
|
|
415
|
+
email: '',
|
|
416
|
+
cardNumber: '',
|
|
417
|
+
expiry: '',
|
|
418
|
+
cvc: ''
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
},
|
|
422
|
+
methods: {
|
|
423
|
+
async handleSubmit() {
|
|
424
|
+
this.loading = true;
|
|
425
|
+
|
|
426
|
+
try {
|
|
427
|
+
// Load PayMongo script if not loaded
|
|
428
|
+
if (!window.Paymongo) {
|
|
429
|
+
await this.loadPayMongoScript();
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const paymongo = new window.Paymongo(this.clientKey);
|
|
433
|
+
|
|
434
|
+
// Create payment method
|
|
435
|
+
const paymentMethod = await paymongo.createPaymentMethod({
|
|
436
|
+
type: 'card',
|
|
437
|
+
details: {
|
|
438
|
+
card_number: this.formData.cardNumber.replace(/\\s/g, ''),
|
|
439
|
+
exp_month: parseInt(this.formData.expiry.split('/')[0]),
|
|
440
|
+
exp_year: 2000 + parseInt(this.formData.expiry.split('/')[1]),
|
|
441
|
+
cvc: this.formData.cvc,
|
|
442
|
+
},
|
|
443
|
+
billing: {
|
|
444
|
+
email: this.formData.email,
|
|
445
|
+
},
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Attach payment method to payment intent
|
|
449
|
+
const result = await paymongo.attachPaymentIntent(this.paymentIntentId, {
|
|
450
|
+
payment_method: paymentMethod.id,
|
|
451
|
+
return_url: window.location.origin + '/success',
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
this.$emit('success', result);
|
|
455
|
+
|
|
456
|
+
} catch (error) {
|
|
457
|
+
console.error('Payment failed:', error);
|
|
458
|
+
this.$emit('error', error);
|
|
459
|
+
} finally {
|
|
460
|
+
this.loading = false;
|
|
461
|
+
}
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
loadPayMongoScript() {
|
|
465
|
+
return new Promise((resolve, reject) => {
|
|
466
|
+
const script = document.createElement('script');
|
|
467
|
+
script.src = 'https://js.paymongo.com/v1/paymongo.js';
|
|
468
|
+
script.onload = resolve;
|
|
469
|
+
script.onerror = reject;
|
|
470
|
+
document.head.appendChild(script);
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
};
|
|
475
|
+
</script>
|
|
476
|
+
|
|
477
|
+
<style scoped>
|
|
478
|
+
.checkout-container {
|
|
479
|
+
max-width: 400px;
|
|
480
|
+
margin: 50px auto;
|
|
481
|
+
padding: 20px;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.checkout-form {
|
|
485
|
+
background: #f9f9f9;
|
|
486
|
+
padding: 20px;
|
|
487
|
+
border-radius: 8px;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
.form-group {
|
|
491
|
+
margin-bottom: 15px;
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
label {
|
|
495
|
+
display: block;
|
|
496
|
+
margin-bottom: 5px;
|
|
497
|
+
font-weight: 500;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
input {
|
|
501
|
+
width: 100%;
|
|
502
|
+
padding: 10px;
|
|
503
|
+
border: 1px solid #ddd;
|
|
504
|
+
border-radius: 4px;
|
|
505
|
+
font-size: 16px;
|
|
506
|
+
box-sizing: border-box;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.pay-button {
|
|
510
|
+
width: 100%;
|
|
511
|
+
padding: 12px;
|
|
512
|
+
background: #007bff;
|
|
513
|
+
color: white;
|
|
514
|
+
border: none;
|
|
515
|
+
border-radius: 4px;
|
|
516
|
+
font-size: 16px;
|
|
517
|
+
cursor: pointer;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
.pay-button:hover:not(:disabled) {
|
|
521
|
+
background: #0056b3;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.pay-button:disabled {
|
|
525
|
+
background: #ccc;
|
|
526
|
+
cursor: not-allowed;
|
|
527
|
+
}
|
|
528
528
|
</style>`;
|
|
529
529
|
}
|
|
530
530
|
export function getCheckoutPageTemplate(language) {
|