strapi-plugin-payone-provider 1.4.2 → 1.5.0
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/APPLE_PAY_INTEGRATION.md +472 -0
- package/CSP_SETUP.md +184 -0
- package/HTTPS_REQUIREMENT.md +136 -0
- package/admin/src/pages/App/components/AppTabs.js +2 -0
- package/admin/src/pages/App/components/ApplePayButton.js +704 -0
- package/admin/src/pages/App/components/ApplePayConfig.js +305 -0
- package/admin/src/pages/App/components/PaymentActionsPanel.js +6 -0
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +29 -2
- package/admin/src/pages/App/components/paymentActions/CaptureForm.js +1 -0
- package/admin/src/pages/App/components/paymentActions/CardDetailsInput.js +18 -16
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +44 -2
- package/admin/src/pages/App/components/paymentActions/RefundForm.js +1 -0
- package/admin/src/pages/hooks/usePaymentActions.js +13 -2
- package/admin/src/pages/utils/applePayConstants.js +222 -0
- package/admin/src/pages/utils/paymentUtils.js +22 -74
- package/package.json +1 -1
- package/server/bootstrap.js +5 -1
- package/server/config/index.js +5 -1
- package/server/controllers/payone.js +10 -0
- package/server/routes/index.js +17 -0
- package/server/services/applePayService.js +261 -0
- package/server/services/payone.js +10 -0
- package/server/utils/paymentMethodParams.js +19 -2
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Flex, Typography, Select, Option, Checkbox, TextInput } from "@strapi/design-system";
|
|
3
|
+
import {
|
|
4
|
+
APPLE_PAY_SUPPORTED_COUNTRIES,
|
|
5
|
+
APPLE_PAY_SUPPORTED_CURRENCIES,
|
|
6
|
+
APPLE_PAY_SUPPORTED_NETWORKS,
|
|
7
|
+
APPLE_PAY_MERCHANT_CAPABILITIES,
|
|
8
|
+
getSupportedCurrenciesForCountry,
|
|
9
|
+
getSupportedNetworksForCountry,
|
|
10
|
+
APPLE_PAY_BUTTON_STYLES,
|
|
11
|
+
APPLE_PAY_BUTTON_TYPES,
|
|
12
|
+
DEFAULT_APPLE_PAY_CONFIG
|
|
13
|
+
} from "../../utils/applePayConstants";
|
|
14
|
+
|
|
15
|
+
const ApplePayConfig = ({
|
|
16
|
+
config,
|
|
17
|
+
onConfigChange,
|
|
18
|
+
settings
|
|
19
|
+
}) => {
|
|
20
|
+
const {
|
|
21
|
+
countryCode = DEFAULT_APPLE_PAY_CONFIG.countryCode,
|
|
22
|
+
currencyCode = DEFAULT_APPLE_PAY_CONFIG.currencyCode,
|
|
23
|
+
merchantCapabilities = DEFAULT_APPLE_PAY_CONFIG.merchantCapabilities,
|
|
24
|
+
supportedNetworks = DEFAULT_APPLE_PAY_CONFIG.supportedNetworks,
|
|
25
|
+
buttonStyle = DEFAULT_APPLE_PAY_CONFIG.buttonStyle,
|
|
26
|
+
buttonType = DEFAULT_APPLE_PAY_CONFIG.buttonType,
|
|
27
|
+
requestPayerName = DEFAULT_APPLE_PAY_CONFIG.requestPayerName,
|
|
28
|
+
requestBillingAddress = DEFAULT_APPLE_PAY_CONFIG.requestBillingAddress,
|
|
29
|
+
requestPayerEmail = DEFAULT_APPLE_PAY_CONFIG.requestPayerEmail,
|
|
30
|
+
requestPayerPhone = DEFAULT_APPLE_PAY_CONFIG.requestPayerPhone,
|
|
31
|
+
requestShipping = DEFAULT_APPLE_PAY_CONFIG.requestShipping,
|
|
32
|
+
shippingType = DEFAULT_APPLE_PAY_CONFIG.shippingType
|
|
33
|
+
} = config || {};
|
|
34
|
+
|
|
35
|
+
// Get supported currencies and networks based on selected country
|
|
36
|
+
const supportedCurrencies = getSupportedCurrenciesForCountry(countryCode);
|
|
37
|
+
const supportedNetworksForCountry = getSupportedNetworksForCountry(countryCode);
|
|
38
|
+
|
|
39
|
+
const handleCountryChange = (value) => {
|
|
40
|
+
const newConfig = {
|
|
41
|
+
...config,
|
|
42
|
+
countryCode: value
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// Auto-update currency if current currency is not supported in new country
|
|
46
|
+
const newSupportedCurrencies = getSupportedCurrenciesForCountry(value);
|
|
47
|
+
if (!newSupportedCurrencies.find(c => c.code === currencyCode)) {
|
|
48
|
+
newConfig.currencyCode = newSupportedCurrencies[0]?.code || "USD";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Auto-update networks based on country
|
|
52
|
+
newConfig.supportedNetworks = getSupportedNetworksForCountry(value);
|
|
53
|
+
|
|
54
|
+
onConfigChange(newConfig);
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const handleCurrencyChange = (value) => {
|
|
58
|
+
onConfigChange({
|
|
59
|
+
...config,
|
|
60
|
+
currencyCode: value
|
|
61
|
+
});
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const handleNetworkToggle = (networkCode) => {
|
|
65
|
+
const currentNetworks = supportedNetworks || [];
|
|
66
|
+
const newNetworks = currentNetworks.includes(networkCode)
|
|
67
|
+
? currentNetworks.filter(n => n !== networkCode)
|
|
68
|
+
: [...currentNetworks, networkCode];
|
|
69
|
+
|
|
70
|
+
onConfigChange({
|
|
71
|
+
...config,
|
|
72
|
+
supportedNetworks: newNetworks
|
|
73
|
+
});
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
const handleCapabilityToggle = (capabilityCode) => {
|
|
77
|
+
const currentCapabilities = merchantCapabilities || [];
|
|
78
|
+
const newCapabilities = currentCapabilities.includes(capabilityCode)
|
|
79
|
+
? currentCapabilities.filter(c => c !== capabilityCode)
|
|
80
|
+
: [...currentCapabilities, capabilityCode];
|
|
81
|
+
|
|
82
|
+
onConfigChange({
|
|
83
|
+
...config,
|
|
84
|
+
merchantCapabilities: newCapabilities
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<Box padding={4}>
|
|
90
|
+
<Flex direction="column" gap={4}>
|
|
91
|
+
<Typography variant="omega" fontWeight="semiBold">
|
|
92
|
+
Apple Pay Configuration
|
|
93
|
+
</Typography>
|
|
94
|
+
|
|
95
|
+
{/* Country Code */}
|
|
96
|
+
<Box>
|
|
97
|
+
<Select
|
|
98
|
+
label="Country Code *"
|
|
99
|
+
name="countryCode"
|
|
100
|
+
value={countryCode}
|
|
101
|
+
onChange={handleCountryChange}
|
|
102
|
+
hint="Select the country where your business operates"
|
|
103
|
+
required
|
|
104
|
+
>
|
|
105
|
+
{APPLE_PAY_SUPPORTED_COUNTRIES.map(country => (
|
|
106
|
+
<Option key={country.code} value={country.code}>
|
|
107
|
+
{country.name} ({country.code})
|
|
108
|
+
</Option>
|
|
109
|
+
))}
|
|
110
|
+
</Select>
|
|
111
|
+
</Box>
|
|
112
|
+
|
|
113
|
+
{/* Currency Code */}
|
|
114
|
+
<Box>
|
|
115
|
+
<Select
|
|
116
|
+
label="Currency Code *"
|
|
117
|
+
name="currencyCode"
|
|
118
|
+
value={currencyCode}
|
|
119
|
+
onChange={handleCurrencyChange}
|
|
120
|
+
hint={`Supported currencies for ${countryCode}. Some currencies may be restricted.`}
|
|
121
|
+
required
|
|
122
|
+
>
|
|
123
|
+
{supportedCurrencies.map(currency => (
|
|
124
|
+
<Option key={currency.code} value={currency.code}>
|
|
125
|
+
{currency.name} ({currency.code}) {currency.symbol}
|
|
126
|
+
</Option>
|
|
127
|
+
))}
|
|
128
|
+
</Select>
|
|
129
|
+
{supportedCurrencies.length === 0 && (
|
|
130
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "4px" }}>
|
|
131
|
+
No supported currencies for this country. Please select a different country.
|
|
132
|
+
</Typography>
|
|
133
|
+
)}
|
|
134
|
+
</Box>
|
|
135
|
+
|
|
136
|
+
{/* Supported Networks */}
|
|
137
|
+
<Box>
|
|
138
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginBottom: "8px" }}>
|
|
139
|
+
Supported Networks *
|
|
140
|
+
</Typography>
|
|
141
|
+
<Typography variant="sigma" textColor="neutral600" style={{ marginBottom: "12px" }}>
|
|
142
|
+
Select payment networks supported in {countryCode}
|
|
143
|
+
</Typography>
|
|
144
|
+
<Flex direction="column" gap={2}>
|
|
145
|
+
{APPLE_PAY_SUPPORTED_NETWORKS.map(network => {
|
|
146
|
+
const isSupported = supportedNetworksForCountry.includes(network.code);
|
|
147
|
+
const isSelected = supportedNetworks?.includes(network.code);
|
|
148
|
+
|
|
149
|
+
return (
|
|
150
|
+
<Checkbox
|
|
151
|
+
key={network.code}
|
|
152
|
+
name={`network-${network.code}`}
|
|
153
|
+
checked={isSelected}
|
|
154
|
+
onChange={() => handleNetworkToggle(network.code)}
|
|
155
|
+
disabled={!isSupported}
|
|
156
|
+
hint={!isSupported ? `Not supported in ${countryCode}` : undefined}
|
|
157
|
+
>
|
|
158
|
+
{network.name} ({network.code})
|
|
159
|
+
{!isSupported && (
|
|
160
|
+
<Typography variant="sigma" textColor="neutral500" style={{ marginLeft: "8px" }}>
|
|
161
|
+
(Not available in {countryCode})
|
|
162
|
+
</Typography>
|
|
163
|
+
)}
|
|
164
|
+
</Checkbox>
|
|
165
|
+
);
|
|
166
|
+
})}
|
|
167
|
+
</Flex>
|
|
168
|
+
{supportedNetworks?.length === 0 && (
|
|
169
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
|
|
170
|
+
At least one network must be selected
|
|
171
|
+
</Typography>
|
|
172
|
+
)}
|
|
173
|
+
</Box>
|
|
174
|
+
|
|
175
|
+
{/* Merchant Capabilities */}
|
|
176
|
+
<Box>
|
|
177
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginBottom: "8px" }}>
|
|
178
|
+
Merchant Capabilities *
|
|
179
|
+
</Typography>
|
|
180
|
+
<Typography variant="sigma" textColor="neutral600" style={{ marginBottom: "12px" }}>
|
|
181
|
+
Select payment capabilities. "3D Secure" is required for most payment methods.
|
|
182
|
+
</Typography>
|
|
183
|
+
<Flex direction="column" gap={2}>
|
|
184
|
+
{APPLE_PAY_MERCHANT_CAPABILITIES.map(capability => {
|
|
185
|
+
const isSelected = merchantCapabilities?.includes(capability.code);
|
|
186
|
+
|
|
187
|
+
return (
|
|
188
|
+
<Checkbox
|
|
189
|
+
key={capability.code}
|
|
190
|
+
name={`capability-${capability.code}`}
|
|
191
|
+
checked={isSelected}
|
|
192
|
+
onChange={() => handleCapabilityToggle(capability.code)}
|
|
193
|
+
>
|
|
194
|
+
{capability.name} - {capability.description}
|
|
195
|
+
</Checkbox>
|
|
196
|
+
);
|
|
197
|
+
})}
|
|
198
|
+
</Flex>
|
|
199
|
+
{merchantCapabilities?.length === 0 && (
|
|
200
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
|
|
201
|
+
At least one capability must be selected. "supports3DS" is recommended.
|
|
202
|
+
</Typography>
|
|
203
|
+
)}
|
|
204
|
+
</Box>
|
|
205
|
+
|
|
206
|
+
{/* Button Style */}
|
|
207
|
+
<Box>
|
|
208
|
+
<Select
|
|
209
|
+
label="Button Style"
|
|
210
|
+
name="buttonStyle"
|
|
211
|
+
value={buttonStyle}
|
|
212
|
+
onChange={(value) => onConfigChange({ ...config, buttonStyle: value })}
|
|
213
|
+
hint="Visual style of the Apple Pay button"
|
|
214
|
+
>
|
|
215
|
+
{APPLE_PAY_BUTTON_STYLES.map(style => (
|
|
216
|
+
<Option key={style.code} value={style.code}>
|
|
217
|
+
{style.name}
|
|
218
|
+
</Option>
|
|
219
|
+
))}
|
|
220
|
+
</Select>
|
|
221
|
+
</Box>
|
|
222
|
+
|
|
223
|
+
{/* Button Type */}
|
|
224
|
+
<Box>
|
|
225
|
+
<Select
|
|
226
|
+
label="Button Type"
|
|
227
|
+
name="buttonType"
|
|
228
|
+
value={buttonType}
|
|
229
|
+
onChange={(value) => onConfigChange({ ...config, buttonType: value })}
|
|
230
|
+
hint="Type of action the button represents"
|
|
231
|
+
>
|
|
232
|
+
{APPLE_PAY_BUTTON_TYPES.map(type => (
|
|
233
|
+
<Option key={type.code} value={type.code}>
|
|
234
|
+
{type.name}
|
|
235
|
+
</Option>
|
|
236
|
+
))}
|
|
237
|
+
</Select>
|
|
238
|
+
</Box>
|
|
239
|
+
|
|
240
|
+
{/* Payment Options */}
|
|
241
|
+
<Box>
|
|
242
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginBottom: "8px" }}>
|
|
243
|
+
Payment Options
|
|
244
|
+
</Typography>
|
|
245
|
+
<Flex direction="column" gap={2}>
|
|
246
|
+
<Checkbox
|
|
247
|
+
name="requestPayerName"
|
|
248
|
+
checked={requestPayerName}
|
|
249
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerName: checked })}
|
|
250
|
+
>
|
|
251
|
+
Request Payer Name
|
|
252
|
+
</Checkbox>
|
|
253
|
+
<Checkbox
|
|
254
|
+
name="requestBillingAddress"
|
|
255
|
+
checked={requestBillingAddress}
|
|
256
|
+
onChange={(checked) => onConfigChange({ ...config, requestBillingAddress: checked })}
|
|
257
|
+
>
|
|
258
|
+
Request Billing Address
|
|
259
|
+
</Checkbox>
|
|
260
|
+
<Checkbox
|
|
261
|
+
name="requestPayerEmail"
|
|
262
|
+
checked={requestPayerEmail}
|
|
263
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerEmail: checked })}
|
|
264
|
+
>
|
|
265
|
+
Request Payer Email
|
|
266
|
+
</Checkbox>
|
|
267
|
+
<Checkbox
|
|
268
|
+
name="requestPayerPhone"
|
|
269
|
+
checked={requestPayerPhone}
|
|
270
|
+
onChange={(checked) => onConfigChange({ ...config, requestPayerPhone: checked })}
|
|
271
|
+
>
|
|
272
|
+
Request Payer Phone
|
|
273
|
+
</Checkbox>
|
|
274
|
+
<Checkbox
|
|
275
|
+
name="requestShipping"
|
|
276
|
+
checked={requestShipping}
|
|
277
|
+
onChange={(checked) => onConfigChange({ ...config, requestShipping: checked })}
|
|
278
|
+
>
|
|
279
|
+
Request Shipping Address
|
|
280
|
+
</Checkbox>
|
|
281
|
+
</Flex>
|
|
282
|
+
</Box>
|
|
283
|
+
|
|
284
|
+
{/* Merchant Identifier Info */}
|
|
285
|
+
<Box padding={3} background="neutral100" borderRadius="4px">
|
|
286
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginBottom: "4px" }}>
|
|
287
|
+
Merchant Identifier
|
|
288
|
+
</Typography>
|
|
289
|
+
<Typography variant="sigma" textColor="neutral600">
|
|
290
|
+
{settings?.mid || settings?.portalid
|
|
291
|
+
? `Using: ${settings.mid || settings.portalid}`
|
|
292
|
+
: "Merchant identifier will be obtained from Payone after domain verification. See documentation for setup instructions."
|
|
293
|
+
}
|
|
294
|
+
</Typography>
|
|
295
|
+
</Box>
|
|
296
|
+
</Flex>
|
|
297
|
+
</Box>
|
|
298
|
+
);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
export default ApplePayConfig;
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
|
|
@@ -36,6 +36,8 @@ const PaymentActionsPanel = ({
|
|
|
36
36
|
settings,
|
|
37
37
|
googlePayToken,
|
|
38
38
|
setGooglePayToken,
|
|
39
|
+
applePayToken,
|
|
40
|
+
setApplePayToken,
|
|
39
41
|
cardtype,
|
|
40
42
|
setCardtype,
|
|
41
43
|
cardpan,
|
|
@@ -84,6 +86,8 @@ const PaymentActionsPanel = ({
|
|
|
84
86
|
settings={settings}
|
|
85
87
|
googlePayToken={googlePayToken}
|
|
86
88
|
setGooglePayToken={setGooglePayToken}
|
|
89
|
+
applePayToken={applePayToken}
|
|
90
|
+
setApplePayToken={setApplePayToken}
|
|
87
91
|
cardtype={cardtype}
|
|
88
92
|
setCardtype={setCardtype}
|
|
89
93
|
cardpan={cardpan}
|
|
@@ -109,6 +113,8 @@ const PaymentActionsPanel = ({
|
|
|
109
113
|
settings={settings}
|
|
110
114
|
googlePayToken={googlePayToken}
|
|
111
115
|
setGooglePayToken={setGooglePayToken}
|
|
116
|
+
applePayToken={applePayToken}
|
|
117
|
+
setApplePayToken={setApplePayToken}
|
|
112
118
|
cardtype={cardtype}
|
|
113
119
|
setCardtype={setCardtype}
|
|
114
120
|
cardpan={cardpan}
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
|
|
3
3
|
import { Play } from "@strapi/icons";
|
|
4
4
|
import GooglePayButton from "../GooglePaybutton";
|
|
5
|
+
import ApplePayButton from "../ApplePayButton";
|
|
5
6
|
import CardDetailsInput from "./CardDetailsInput";
|
|
6
7
|
|
|
7
8
|
const AuthorizationForm = ({
|
|
@@ -15,6 +16,8 @@ const AuthorizationForm = ({
|
|
|
15
16
|
settings,
|
|
16
17
|
googlePayToken,
|
|
17
18
|
setGooglePayToken,
|
|
19
|
+
applePayToken,
|
|
20
|
+
setApplePayToken,
|
|
18
21
|
cardtype,
|
|
19
22
|
setCardtype,
|
|
20
23
|
cardpan,
|
|
@@ -37,6 +40,22 @@ const AuthorizationForm = ({
|
|
|
37
40
|
onError(error);
|
|
38
41
|
}
|
|
39
42
|
};
|
|
43
|
+
|
|
44
|
+
const handleApplePayToken = (token, paymentData) => {
|
|
45
|
+
if (!token) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setApplePayToken(token);
|
|
49
|
+
onAuthorization(token);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleApplePayError = (error) => {
|
|
53
|
+
if (onError) {
|
|
54
|
+
onError(error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
|
|
40
59
|
return (
|
|
41
60
|
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
42
61
|
<Flex direction="row" gap={2}>
|
|
@@ -73,8 +92,7 @@ const AuthorizationForm = ({
|
|
|
73
92
|
/>
|
|
74
93
|
</Flex>
|
|
75
94
|
|
|
76
|
-
{
|
|
77
|
-
{paymentMethod === "cc" && settings?.enable3DSecure !== false && (
|
|
95
|
+
{paymentMethod === "cc" && settings?.enable3DSecure && (
|
|
78
96
|
<Box marginTop={4}>
|
|
79
97
|
<CardDetailsInput
|
|
80
98
|
cardtype={cardtype}
|
|
@@ -97,12 +115,21 @@ const AuthorizationForm = ({
|
|
|
97
115
|
onError={handleGooglePayError}
|
|
98
116
|
settings={settings}
|
|
99
117
|
/>
|
|
118
|
+
) : paymentMethod === "apl" ? (
|
|
119
|
+
<ApplePayButton
|
|
120
|
+
amount={paymentAmount}
|
|
121
|
+
currency="EUR"
|
|
122
|
+
onTokenReceived={handleApplePayToken}
|
|
123
|
+
onError={handleApplePayError}
|
|
124
|
+
settings={settings}
|
|
125
|
+
/>
|
|
100
126
|
) : (
|
|
101
127
|
<Button
|
|
102
128
|
variant="default"
|
|
103
129
|
onClick={onAuthorization}
|
|
104
130
|
loading={isProcessingPayment}
|
|
105
131
|
startIcon={<Play />}
|
|
132
|
+
style={{ maxWidth: '200px' }}
|
|
106
133
|
className="payment-button payment-button-primary"
|
|
107
134
|
disabled={
|
|
108
135
|
!paymentAmount.trim() ||
|
|
@@ -94,22 +94,24 @@ const CardDetailsInput = ({
|
|
|
94
94
|
return (
|
|
95
95
|
<Box>
|
|
96
96
|
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
97
|
-
<
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
{card.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
97
|
+
<Flex direction="row" gap={2} alignItems="flex-start">
|
|
98
|
+
<Select
|
|
99
|
+
label="3D Secure Test Cards"
|
|
100
|
+
name="testCard"
|
|
101
|
+
value={selectedTestCard}
|
|
102
|
+
placeholder="Select a 3DS test card to auto-fill"
|
|
103
|
+
hint="These cards will trigger 3DS authentication redirect. Password: 12345"
|
|
104
|
+
onChange={handleTestCardSelect}
|
|
105
|
+
className="payment-input"
|
|
106
|
+
>
|
|
107
|
+
<Option value="">-- Select a test card --</Option>
|
|
108
|
+
{TEST_3DS_CARDS.map((card, index) => (
|
|
109
|
+
<Option key={index} value={`${card.cardtype}-${card.cardpan}`}>
|
|
110
|
+
{card.name} - {card.description}
|
|
111
|
+
</Option>
|
|
112
|
+
))}
|
|
113
|
+
</Select>
|
|
114
|
+
</Flex>
|
|
113
115
|
|
|
114
116
|
<Flex gap={4} wrap="wrap" alignItems="flex-start">
|
|
115
117
|
<Select
|
|
@@ -2,6 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
|
|
3
3
|
import { Play } from "@strapi/icons";
|
|
4
4
|
import GooglePayButton from "../GooglePaybutton";
|
|
5
|
+
import ApplePayButton from "../ApplePayButton";
|
|
5
6
|
import CardDetailsInput from "./CardDetailsInput";
|
|
6
7
|
|
|
7
8
|
const PreauthorizationForm = ({
|
|
@@ -15,6 +16,8 @@ const PreauthorizationForm = ({
|
|
|
15
16
|
settings,
|
|
16
17
|
googlePayToken,
|
|
17
18
|
setGooglePayToken,
|
|
19
|
+
applePayToken,
|
|
20
|
+
setApplePayToken,
|
|
18
21
|
cardtype,
|
|
19
22
|
setCardtype,
|
|
20
23
|
cardpan,
|
|
@@ -37,6 +40,20 @@ const PreauthorizationForm = ({
|
|
|
37
40
|
onError(error);
|
|
38
41
|
}
|
|
39
42
|
};
|
|
43
|
+
|
|
44
|
+
const handleApplePayToken = (token, paymentData) => {
|
|
45
|
+
if (!token) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
setApplePayToken(token);
|
|
49
|
+
onPreauthorization(token);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleApplePayError = (error) => {
|
|
53
|
+
if (onError) {
|
|
54
|
+
onError(error);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
40
57
|
return (
|
|
41
58
|
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
42
59
|
<Flex direction="row" gap={2}>
|
|
@@ -73,8 +90,7 @@ const PreauthorizationForm = ({
|
|
|
73
90
|
/>
|
|
74
91
|
</Flex>
|
|
75
92
|
|
|
76
|
-
{
|
|
77
|
-
{paymentMethod === "cc" && settings?.enable3DSecure !== false && (
|
|
93
|
+
{paymentMethod === "cc" && settings?.enable3DSecure && (
|
|
78
94
|
<Box marginTop={4}>
|
|
79
95
|
<CardDetailsInput
|
|
80
96
|
cardtype={cardtype}
|
|
@@ -97,12 +113,38 @@ const PreauthorizationForm = ({
|
|
|
97
113
|
onError={handleGooglePayError}
|
|
98
114
|
settings={settings}
|
|
99
115
|
/>
|
|
116
|
+
) : paymentMethod === "apl" ? (
|
|
117
|
+
<Box>
|
|
118
|
+
<ApplePayButton
|
|
119
|
+
amount={paymentAmount}
|
|
120
|
+
currency="EUR"
|
|
121
|
+
onTokenReceived={handleApplePayToken}
|
|
122
|
+
onError={handleApplePayError}
|
|
123
|
+
settings={settings}
|
|
124
|
+
/>
|
|
125
|
+
<Box marginTop={3} style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "8px" }}>
|
|
126
|
+
<Typography variant="pi" textColor="neutral600" style={{ marginBottom: "8px" }}>
|
|
127
|
+
Apple Pay is not available on localhost. You can test the payment flow without Apple Pay token:
|
|
128
|
+
</Typography>
|
|
129
|
+
<Button
|
|
130
|
+
variant="secondary"
|
|
131
|
+
onClick={() => onPreauthorization(null)}
|
|
132
|
+
loading={isProcessingPayment}
|
|
133
|
+
startIcon={<Play />}
|
|
134
|
+
style={{ maxWidth: '200px' }}
|
|
135
|
+
disabled={!paymentAmount.trim() || !preauthReference.trim()}
|
|
136
|
+
>
|
|
137
|
+
Process Preauthorization
|
|
138
|
+
</Button>
|
|
139
|
+
</Box>
|
|
140
|
+
</Box>
|
|
100
141
|
) : (
|
|
101
142
|
<Button
|
|
102
143
|
variant="default"
|
|
103
144
|
onClick={onPreauthorization}
|
|
104
145
|
loading={isProcessingPayment}
|
|
105
146
|
startIcon={<Play />}
|
|
147
|
+
style={{ maxWidth: '200px' }}
|
|
106
148
|
className="payment-button payment-button-primary"
|
|
107
149
|
disabled={
|
|
108
150
|
!paymentAmount.trim() ||
|
|
@@ -50,6 +50,7 @@ const usePaymentActions = () => {
|
|
|
50
50
|
const [paymentMethod, setPaymentMethod] = useState("cc");
|
|
51
51
|
const [captureMode, setCaptureMode] = useState("full");
|
|
52
52
|
const [googlePayToken, setGooglePayToken] = useState(null);
|
|
53
|
+
const [applePayToken, setApplePayToken] = useState(null);
|
|
53
54
|
|
|
54
55
|
// Card details for 3DS testing
|
|
55
56
|
const [cardtype, setCardtype] = useState("");
|
|
@@ -129,10 +130,13 @@ const usePaymentActions = () => {
|
|
|
129
130
|
baseParams.backurl = `${baseUrl}${basePath}${pluginPath}/back`;
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
const tokenToUse = tokenParam || googlePayToken;
|
|
133
|
+
const tokenToUse = tokenParam || googlePayToken || applePayToken;
|
|
133
134
|
if (paymentMethod === "gpp" && tokenToUse) {
|
|
134
135
|
baseParams.googlePayToken = tokenToUse;
|
|
135
136
|
baseParams.settings = settings;
|
|
137
|
+
} else if (paymentMethod === "apl" && tokenToUse) {
|
|
138
|
+
baseParams.applePayToken = tokenToUse;
|
|
139
|
+
baseParams.settings = settings;
|
|
136
140
|
}
|
|
137
141
|
|
|
138
142
|
const params = getPreauthorizationParams(paymentMethod, baseParams);
|
|
@@ -271,10 +275,13 @@ const usePaymentActions = () => {
|
|
|
271
275
|
baseParams.backurl = `${baseUrl}${basePath}${pluginPath}/back`;
|
|
272
276
|
}
|
|
273
277
|
|
|
274
|
-
const tokenToUse = tokenParam || googlePayToken;
|
|
278
|
+
const tokenToUse = tokenParam || googlePayToken || applePayToken;
|
|
275
279
|
if (paymentMethod === "gpp" && tokenToUse) {
|
|
276
280
|
baseParams.googlePayToken = tokenToUse;
|
|
277
281
|
baseParams.settings = settings;
|
|
282
|
+
} else if (paymentMethod === "apl" && tokenToUse) {
|
|
283
|
+
baseParams.applePayToken = tokenToUse;
|
|
284
|
+
baseParams.settings = settings;
|
|
278
285
|
}
|
|
279
286
|
|
|
280
287
|
const params = getAuthorizationParams(paymentMethod, baseParams);
|
|
@@ -454,6 +461,10 @@ const usePaymentActions = () => {
|
|
|
454
461
|
googlePayToken,
|
|
455
462
|
setGooglePayToken,
|
|
456
463
|
|
|
464
|
+
// Apple Pay
|
|
465
|
+
applePayToken,
|
|
466
|
+
setApplePayToken,
|
|
467
|
+
|
|
457
468
|
// Card details for 3DS
|
|
458
469
|
cardtype,
|
|
459
470
|
setCardtype,
|