strapi-plugin-payone-provider 1.4.2 → 1.5.2
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/README.md +179 -22
- package/admin/src/pages/App/components/AppHeader.js +22 -4
- package/admin/src/pages/App/components/AppTabs.js +25 -1
- package/admin/src/pages/App/components/ApplePayButton.js +737 -0
- package/admin/src/pages/App/components/ApplePayConfig.js +364 -0
- package/admin/src/pages/App/components/ApplePayConfigPanel.js +81 -0
- package/admin/src/pages/App/components/ConfigurationPanel.js +19 -3
- package/admin/src/pages/App/components/DocsPanel.js +1057 -0
- package/admin/src/pages/App/components/GooglePayConfig.js +217 -0
- package/admin/src/pages/App/components/GooglePayConfigPanel.js +82 -0
- package/admin/src/pages/App/components/GooglePaybutton.js +1 -1
- package/admin/src/pages/App/components/PaymentActionsPanel.js +24 -6
- package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +60 -4
- 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/PaymentMethodSelector.js +106 -2
- package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +64 -4
- package/admin/src/pages/App/components/paymentActions/RefundForm.js +1 -0
- package/admin/src/pages/App/index.js +70 -1
- package/admin/src/pages/hooks/usePaymentActions.js +13 -2
- package/admin/src/pages/hooks/useSettings.js +2 -0
- package/admin/src/pages/utils/applePayConstants.js +222 -0
- package/admin/src/pages/utils/googlePayConstants.js +79 -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,217 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { Box, Flex, Typography, Select, Option, Checkbox, Stack } from "@strapi/design-system";
|
|
3
|
+
import {
|
|
4
|
+
GOOGLE_PAY_SUPPORTED_COUNTRIES,
|
|
5
|
+
GOOGLE_PAY_SUPPORTED_CURRENCIES,
|
|
6
|
+
GOOGLE_PAY_SUPPORTED_NETWORKS,
|
|
7
|
+
GOOGLE_PAY_AUTH_METHODS,
|
|
8
|
+
DEFAULT_GOOGLE_PAY_CONFIG
|
|
9
|
+
} from "../../utils/googlePayConstants";
|
|
10
|
+
|
|
11
|
+
const GooglePayConfig = ({
|
|
12
|
+
config,
|
|
13
|
+
onConfigChange,
|
|
14
|
+
settings
|
|
15
|
+
}) => {
|
|
16
|
+
const {
|
|
17
|
+
countryCode = DEFAULT_GOOGLE_PAY_CONFIG.countryCode,
|
|
18
|
+
currencyCode = DEFAULT_GOOGLE_PAY_CONFIG.currencyCode,
|
|
19
|
+
allowedCardNetworks = DEFAULT_GOOGLE_PAY_CONFIG.allowedCardNetworks,
|
|
20
|
+
allowedAuthMethods = DEFAULT_GOOGLE_PAY_CONFIG.allowedAuthMethods,
|
|
21
|
+
merchantName = DEFAULT_GOOGLE_PAY_CONFIG.merchantName
|
|
22
|
+
} = config || {};
|
|
23
|
+
|
|
24
|
+
const handleCountryChange = (value) => {
|
|
25
|
+
onConfigChange({
|
|
26
|
+
...config,
|
|
27
|
+
countryCode: value
|
|
28
|
+
});
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
const handleCurrencyChange = (value) => {
|
|
32
|
+
onConfigChange({
|
|
33
|
+
...config,
|
|
34
|
+
currencyCode: value
|
|
35
|
+
});
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const handleNetworkToggle = (networkCode) => {
|
|
39
|
+
const currentNetworks = allowedCardNetworks || [];
|
|
40
|
+
const newNetworks = currentNetworks.includes(networkCode)
|
|
41
|
+
? currentNetworks.filter(n => n !== networkCode)
|
|
42
|
+
: [...currentNetworks, networkCode];
|
|
43
|
+
|
|
44
|
+
onConfigChange({
|
|
45
|
+
...config,
|
|
46
|
+
allowedCardNetworks: newNetworks
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
const handleAuthMethodToggle = (authMethodCode) => {
|
|
51
|
+
const currentMethods = allowedAuthMethods || [];
|
|
52
|
+
const newMethods = currentMethods.includes(authMethodCode)
|
|
53
|
+
? currentMethods.filter(m => m !== authMethodCode)
|
|
54
|
+
: [...currentMethods, authMethodCode];
|
|
55
|
+
|
|
56
|
+
onConfigChange({
|
|
57
|
+
...config,
|
|
58
|
+
allowedAuthMethods: newMethods
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return (
|
|
63
|
+
<Box>
|
|
64
|
+
<Stack spacing={6}>
|
|
65
|
+
<Box>
|
|
66
|
+
<Typography variant="delta" as="h3" fontWeight="bold" style={{ marginBottom: "6px" }}>
|
|
67
|
+
Google Pay Configuration
|
|
68
|
+
</Typography>
|
|
69
|
+
<Typography variant="pi" textColor="neutral600">
|
|
70
|
+
Configure Google Pay settings for your payment gateway
|
|
71
|
+
</Typography>
|
|
72
|
+
</Box>
|
|
73
|
+
|
|
74
|
+
{/* Country and Currency */}
|
|
75
|
+
<Flex gap={4} wrap="wrap">
|
|
76
|
+
<Box style={{ flex: 1, minWidth: "300px" }}>
|
|
77
|
+
<Select
|
|
78
|
+
label="Country Code"
|
|
79
|
+
name="countryCode"
|
|
80
|
+
value={countryCode}
|
|
81
|
+
onChange={handleCountryChange}
|
|
82
|
+
hint="Select the country where your business operates"
|
|
83
|
+
required
|
|
84
|
+
>
|
|
85
|
+
{GOOGLE_PAY_SUPPORTED_COUNTRIES.map(country => (
|
|
86
|
+
<Option key={country.code} value={country.code}>
|
|
87
|
+
{country.name} ({country.code})
|
|
88
|
+
</Option>
|
|
89
|
+
))}
|
|
90
|
+
</Select>
|
|
91
|
+
</Box>
|
|
92
|
+
|
|
93
|
+
<Box style={{ flex: 1, minWidth: "300px" }}>
|
|
94
|
+
<Select
|
|
95
|
+
label="Currency Code"
|
|
96
|
+
name="currencyCode"
|
|
97
|
+
value={currencyCode}
|
|
98
|
+
onChange={handleCurrencyChange}
|
|
99
|
+
hint="Select the currency for transactions"
|
|
100
|
+
required
|
|
101
|
+
>
|
|
102
|
+
{GOOGLE_PAY_SUPPORTED_CURRENCIES.map(currency => (
|
|
103
|
+
<Option key={currency.code} value={currency.code}>
|
|
104
|
+
{currency.name} ({currency.code}) {currency.symbol}
|
|
105
|
+
</Option>
|
|
106
|
+
))}
|
|
107
|
+
</Select>
|
|
108
|
+
</Box>
|
|
109
|
+
</Flex>
|
|
110
|
+
|
|
111
|
+
{/* Merchant Name */}
|
|
112
|
+
<Box>
|
|
113
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
|
|
114
|
+
Merchant Name
|
|
115
|
+
</Typography>
|
|
116
|
+
<Typography variant="pi" textColor="neutral600" style={{ marginLeft: "2px" }}>
|
|
117
|
+
The name of your business as it will appear in Google Pay
|
|
118
|
+
</Typography>
|
|
119
|
+
<input
|
|
120
|
+
type="text"
|
|
121
|
+
value={merchantName}
|
|
122
|
+
onChange={(e) => onConfigChange({ ...config, merchantName: e.target.value })}
|
|
123
|
+
style={{
|
|
124
|
+
width: "100%",
|
|
125
|
+
padding: "8px 12px",
|
|
126
|
+
marginTop: "8px",
|
|
127
|
+
border: "1px solid #dcdce4",
|
|
128
|
+
borderRadius: "4px",
|
|
129
|
+
fontSize: "14px"
|
|
130
|
+
}}
|
|
131
|
+
placeholder="Your Store Name"
|
|
132
|
+
/>
|
|
133
|
+
</Box>
|
|
134
|
+
|
|
135
|
+
{/* Allowed Card Networks */}
|
|
136
|
+
<Box>
|
|
137
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
|
|
138
|
+
Allowed Card Networks
|
|
139
|
+
</Typography>
|
|
140
|
+
<Typography variant="pi" textColor="neutral600" style={{ marginLeft: "2px" }}>
|
|
141
|
+
Select payment card networks to accept
|
|
142
|
+
</Typography>
|
|
143
|
+
<Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
|
|
144
|
+
{GOOGLE_PAY_SUPPORTED_NETWORKS.map(network => {
|
|
145
|
+
const isSelected = allowedCardNetworks?.includes(network.code);
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Box key={network.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
|
|
149
|
+
<Checkbox
|
|
150
|
+
name={`network-${network.code}`}
|
|
151
|
+
checked={isSelected}
|
|
152
|
+
onChange={() => handleNetworkToggle(network.code)}
|
|
153
|
+
>
|
|
154
|
+
{network.name} ({network.code})
|
|
155
|
+
</Checkbox>
|
|
156
|
+
</Box>
|
|
157
|
+
);
|
|
158
|
+
})}
|
|
159
|
+
</Flex>
|
|
160
|
+
{allowedCardNetworks?.length === 0 && (
|
|
161
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
|
|
162
|
+
At least one card network must be selected
|
|
163
|
+
</Typography>
|
|
164
|
+
)}
|
|
165
|
+
</Box>
|
|
166
|
+
|
|
167
|
+
{/* Allowed Authentication Methods */}
|
|
168
|
+
<Box>
|
|
169
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
|
|
170
|
+
Allowed Authentication Methods
|
|
171
|
+
</Typography>
|
|
172
|
+
<Typography variant="pi" textColor="neutral600" style={{ marginLeft: "2px" }}>
|
|
173
|
+
Select authentication methods for card payments
|
|
174
|
+
</Typography>
|
|
175
|
+
<Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
|
|
176
|
+
{GOOGLE_PAY_AUTH_METHODS.map(method => {
|
|
177
|
+
const isSelected = allowedAuthMethods?.includes(method.code);
|
|
178
|
+
|
|
179
|
+
return (
|
|
180
|
+
<Box key={method.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
|
|
181
|
+
<Checkbox
|
|
182
|
+
name={`auth-method-${method.code}`}
|
|
183
|
+
checked={isSelected}
|
|
184
|
+
onChange={() => handleAuthMethodToggle(method.code)}
|
|
185
|
+
>
|
|
186
|
+
{method.name} - {method.description}
|
|
187
|
+
</Checkbox>
|
|
188
|
+
</Box>
|
|
189
|
+
);
|
|
190
|
+
})}
|
|
191
|
+
</Flex>
|
|
192
|
+
{allowedAuthMethods?.length === 0 && (
|
|
193
|
+
<Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
|
|
194
|
+
At least one authentication method must be selected
|
|
195
|
+
</Typography>
|
|
196
|
+
)}
|
|
197
|
+
</Box>
|
|
198
|
+
|
|
199
|
+
{/* Gateway Merchant ID Info */}
|
|
200
|
+
<Box>
|
|
201
|
+
<Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
|
|
202
|
+
Gateway Merchant ID
|
|
203
|
+
</Typography>
|
|
204
|
+
<Typography variant="pi" textColor="neutral600">
|
|
205
|
+
{settings?.mid || settings?.portalid
|
|
206
|
+
? `Using: ${settings.mid || settings.portalid}`
|
|
207
|
+
: "Gateway merchant ID will be obtained from your Payone Merchant ID (MID) or Portal ID. Make sure these are configured in the main Configuration tab."
|
|
208
|
+
}
|
|
209
|
+
</Typography>
|
|
210
|
+
</Box>
|
|
211
|
+
</Stack>
|
|
212
|
+
</Box>
|
|
213
|
+
);
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
export default GooglePayConfig;
|
|
217
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import React, { useState, useEffect } from "react";
|
|
2
|
+
import {
|
|
3
|
+
Box,
|
|
4
|
+
Card,
|
|
5
|
+
CardBody,
|
|
6
|
+
Flex,
|
|
7
|
+
Typography,
|
|
8
|
+
Button
|
|
9
|
+
} from "@strapi/design-system";
|
|
10
|
+
import { Check } from "@strapi/icons";
|
|
11
|
+
import GooglePayConfig from "./GooglePayConfig";
|
|
12
|
+
|
|
13
|
+
const GooglePayConfigPanel = ({
|
|
14
|
+
settings,
|
|
15
|
+
onInputChange,
|
|
16
|
+
isSaving,
|
|
17
|
+
onSave,
|
|
18
|
+
onBack
|
|
19
|
+
}) => {
|
|
20
|
+
const [googlePayConfig, setGooglePayConfig] = useState(settings?.googlePayConfig || {});
|
|
21
|
+
|
|
22
|
+
useEffect(() => {
|
|
23
|
+
setGooglePayConfig(settings?.googlePayConfig || {});
|
|
24
|
+
}, [settings?.googlePayConfig]);
|
|
25
|
+
|
|
26
|
+
return (
|
|
27
|
+
<Box
|
|
28
|
+
className="payment-container"
|
|
29
|
+
paddingTop={8}
|
|
30
|
+
paddingBottom={8}
|
|
31
|
+
paddingLeft={8}
|
|
32
|
+
paddingRight={8}
|
|
33
|
+
>
|
|
34
|
+
<Flex direction="column" alignItems="stretch" gap={8}>
|
|
35
|
+
<Box>
|
|
36
|
+
<Typography variant="beta" as="h2" fontWeight="bold" className="payment-title" style={{ fontSize: '20px', marginBottom: '4px' }}>
|
|
37
|
+
Google Pay Configuration
|
|
38
|
+
</Typography>
|
|
39
|
+
<Typography variant="pi" textColor="neutral600" marginTop={2} className="payment-subtitle" style={{ fontSize: '14px' }}>
|
|
40
|
+
Configure Google Pay settings for your payment gateway
|
|
41
|
+
</Typography>
|
|
42
|
+
</Box>
|
|
43
|
+
|
|
44
|
+
<Box>
|
|
45
|
+
<Card className="payment-card">
|
|
46
|
+
<CardBody padding={6}>
|
|
47
|
+
<GooglePayConfig
|
|
48
|
+
config={googlePayConfig}
|
|
49
|
+
onConfigChange={(newConfig) => {
|
|
50
|
+
setGooglePayConfig(newConfig);
|
|
51
|
+
onInputChange("googlePayConfig", newConfig);
|
|
52
|
+
}}
|
|
53
|
+
settings={settings}
|
|
54
|
+
/>
|
|
55
|
+
</CardBody>
|
|
56
|
+
</Card>
|
|
57
|
+
</Box>
|
|
58
|
+
|
|
59
|
+
<Box paddingTop={4}>
|
|
60
|
+
<Flex direction="row" gap={4} alignItems="center">
|
|
61
|
+
<Button
|
|
62
|
+
loading={isSaving}
|
|
63
|
+
onClick={onSave}
|
|
64
|
+
startIcon={<Check />}
|
|
65
|
+
size="L"
|
|
66
|
+
variant="default"
|
|
67
|
+
className="payment-button payment-button-success"
|
|
68
|
+
>
|
|
69
|
+
Save Google Pay Configuration
|
|
70
|
+
</Button>
|
|
71
|
+
<Typography variant="sigma" textColor="neutral600">
|
|
72
|
+
Note: Google Pay configuration is used for Google Pay payment requests. Make sure to configure the correct card networks, authentication methods, and merchant information for your region.
|
|
73
|
+
</Typography>
|
|
74
|
+
</Flex>
|
|
75
|
+
</Box>
|
|
76
|
+
</Flex>
|
|
77
|
+
</Box>
|
|
78
|
+
);
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export default GooglePayConfigPanel;
|
|
82
|
+
|
|
@@ -291,7 +291,7 @@ const GooglePayButton = ({
|
|
|
291
291
|
</Typography>
|
|
292
292
|
</>
|
|
293
293
|
)}
|
|
294
|
-
<Box ref={buttonContainerRef} style={{ minHeight: "40px", width: "100%", display: "flex", justifyContent: "flex-start" }} />
|
|
294
|
+
<Box ref={buttonContainerRef} style={{ minHeight: "40px", width: "100%", maxWidth: "200px", display: "flex", justifyContent: "flex-start", }} />
|
|
295
295
|
</Flex>
|
|
296
296
|
</Box>
|
|
297
297
|
);
|
|
@@ -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,
|
|
@@ -43,8 +45,12 @@ const PaymentActionsPanel = ({
|
|
|
43
45
|
cardexpiredate,
|
|
44
46
|
setCardexpiredate,
|
|
45
47
|
cardcvc2,
|
|
46
|
-
setCardcvc2
|
|
48
|
+
setCardcvc2,
|
|
49
|
+
onNavigateToConfig
|
|
47
50
|
}) => {
|
|
51
|
+
const mode = (settings?.mode || 'test').toLowerCase();
|
|
52
|
+
const isLiveMode = mode === 'live';
|
|
53
|
+
|
|
48
54
|
return (
|
|
49
55
|
<Box
|
|
50
56
|
className="payment-container"
|
|
@@ -54,13 +60,18 @@ const PaymentActionsPanel = ({
|
|
|
54
60
|
paddingRight={8}
|
|
55
61
|
>
|
|
56
62
|
<Flex direction="column" alignItems="stretch" gap={6}>
|
|
57
|
-
<Box>
|
|
63
|
+
<Box style={{ display: 'flex', flexDirection: 'column', alignItems: 'flex-start', gap: '8px' }}>
|
|
58
64
|
<Typography variant="beta" as="h2" className="payment-title" style={{ fontSize: '20px', marginBottom: '4px' }}>
|
|
59
65
|
Payment Actions
|
|
60
66
|
</Typography>
|
|
61
67
|
<Typography variant="pi" textColor="neutral600" className="payment-subtitle" style={{ fontSize: '14px' }}>
|
|
62
68
|
Process payments, captures, and refunds with multiple payment methods
|
|
63
69
|
</Typography>
|
|
70
|
+
{isLiveMode && (
|
|
71
|
+
<Typography variant="pi" textColor="danger600" style={{ fontSize: '14px', marginTop: '8px', fontWeight: 'bold' }}>
|
|
72
|
+
⚠️ Payment Actions are disabled in live mode for security reasons. Please use test mode for testing.
|
|
73
|
+
</Typography>
|
|
74
|
+
)}
|
|
64
75
|
</Box>
|
|
65
76
|
|
|
66
77
|
<PaymentMethodSelector
|
|
@@ -68,11 +79,12 @@ const PaymentActionsPanel = ({
|
|
|
68
79
|
setPaymentMethod={setPaymentMethod}
|
|
69
80
|
captureMode={captureMode}
|
|
70
81
|
setCaptureMode={setCaptureMode}
|
|
82
|
+
onNavigateToConfig={onNavigateToConfig}
|
|
71
83
|
/>
|
|
72
84
|
|
|
73
85
|
<hr className="payment-divider" />
|
|
74
86
|
|
|
75
|
-
<Box className="payment-form-section">
|
|
87
|
+
<Box className="payment-form-section" style={{ opacity: isLiveMode ? 0.5 : 1, pointerEvents: isLiveMode ? 'none' : 'auto' }}>
|
|
76
88
|
<PreauthorizationForm
|
|
77
89
|
paymentAmount={paymentAmount}
|
|
78
90
|
setPaymentAmount={setPaymentAmount}
|
|
@@ -84,6 +96,8 @@ const PaymentActionsPanel = ({
|
|
|
84
96
|
settings={settings}
|
|
85
97
|
googlePayToken={googlePayToken}
|
|
86
98
|
setGooglePayToken={setGooglePayToken}
|
|
99
|
+
applePayToken={applePayToken}
|
|
100
|
+
setApplePayToken={setApplePayToken}
|
|
87
101
|
cardtype={cardtype}
|
|
88
102
|
setCardtype={setCardtype}
|
|
89
103
|
cardpan={cardpan}
|
|
@@ -92,12 +106,13 @@ const PaymentActionsPanel = ({
|
|
|
92
106
|
setCardexpiredate={setCardexpiredate}
|
|
93
107
|
cardcvc2={cardcvc2}
|
|
94
108
|
setCardcvc2={setCardcvc2}
|
|
109
|
+
isLiveMode={isLiveMode}
|
|
95
110
|
/>
|
|
96
111
|
</Box>
|
|
97
112
|
|
|
98
113
|
<hr className="payment-divider" />
|
|
99
114
|
|
|
100
|
-
<Box className="payment-form-section">
|
|
115
|
+
<Box className="payment-form-section" style={{ opacity: isLiveMode ? 0.5 : 1, pointerEvents: isLiveMode ? 'none' : 'auto' }}>
|
|
101
116
|
<AuthorizationForm
|
|
102
117
|
paymentAmount={paymentAmount}
|
|
103
118
|
setPaymentAmount={setPaymentAmount}
|
|
@@ -109,6 +124,8 @@ const PaymentActionsPanel = ({
|
|
|
109
124
|
settings={settings}
|
|
110
125
|
googlePayToken={googlePayToken}
|
|
111
126
|
setGooglePayToken={setGooglePayToken}
|
|
127
|
+
applePayToken={applePayToken}
|
|
128
|
+
setApplePayToken={setApplePayToken}
|
|
112
129
|
cardtype={cardtype}
|
|
113
130
|
setCardtype={setCardtype}
|
|
114
131
|
cardpan={cardpan}
|
|
@@ -117,12 +134,13 @@ const PaymentActionsPanel = ({
|
|
|
117
134
|
setCardexpiredate={setCardexpiredate}
|
|
118
135
|
cardcvc2={cardcvc2}
|
|
119
136
|
setCardcvc2={setCardcvc2}
|
|
137
|
+
isLiveMode={isLiveMode}
|
|
120
138
|
/>
|
|
121
139
|
</Box>
|
|
122
140
|
|
|
123
141
|
<hr className="payment-divider" />
|
|
124
142
|
|
|
125
|
-
<Box className="payment-form-section">
|
|
143
|
+
<Box className="payment-form-section" style={{ opacity: isLiveMode ? 0.5 : 1, pointerEvents: isLiveMode ? 'none' : 'auto' }}>
|
|
126
144
|
<CaptureForm
|
|
127
145
|
paymentAmount={paymentAmount}
|
|
128
146
|
setPaymentAmount={setPaymentAmount}
|
|
@@ -135,7 +153,7 @@ const PaymentActionsPanel = ({
|
|
|
135
153
|
|
|
136
154
|
<hr className="payment-divider" />
|
|
137
155
|
|
|
138
|
-
<Box className="payment-form-section">
|
|
156
|
+
<Box className="payment-form-section" style={{ opacity: isLiveMode ? 0.5 : 1, pointerEvents: isLiveMode ? 'none' : 'auto' }}>
|
|
139
157
|
<RefundForm
|
|
140
158
|
paymentAmount={paymentAmount}
|
|
141
159
|
setPaymentAmount={setPaymentAmount}
|
|
@@ -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,
|
|
@@ -22,7 +25,8 @@ const AuthorizationForm = ({
|
|
|
22
25
|
cardexpiredate,
|
|
23
26
|
setCardexpiredate,
|
|
24
27
|
cardcvc2,
|
|
25
|
-
setCardcvc2
|
|
28
|
+
setCardcvc2,
|
|
29
|
+
isLiveMode = false
|
|
26
30
|
}) => {
|
|
27
31
|
const handleGooglePayToken = (token, paymentData) => {
|
|
28
32
|
if (!token) {
|
|
@@ -37,6 +41,28 @@ const AuthorizationForm = ({
|
|
|
37
41
|
onError(error);
|
|
38
42
|
}
|
|
39
43
|
};
|
|
44
|
+
|
|
45
|
+
const handleApplePayToken = async (token, paymentData) => {
|
|
46
|
+
if (!token) {
|
|
47
|
+
return Promise.reject(new Error("Token is missing"));
|
|
48
|
+
}
|
|
49
|
+
setApplePayToken(token);
|
|
50
|
+
try {
|
|
51
|
+
await onAuthorization(token);
|
|
52
|
+
return Promise.resolve();
|
|
53
|
+
} catch (error) {
|
|
54
|
+
console.error("[Apple Pay] Error in authorization:", error);
|
|
55
|
+
return Promise.reject(error);
|
|
56
|
+
}
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const handleApplePayError = (error) => {
|
|
60
|
+
if (onError) {
|
|
61
|
+
onError(error);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
|
|
40
66
|
return (
|
|
41
67
|
<Flex direction="column" alignItems="stretch" gap={4}>
|
|
42
68
|
<Flex direction="row" gap={2}>
|
|
@@ -73,8 +99,7 @@ const AuthorizationForm = ({
|
|
|
73
99
|
/>
|
|
74
100
|
</Flex>
|
|
75
101
|
|
|
76
|
-
{
|
|
77
|
-
{paymentMethod === "cc" && settings?.enable3DSecure !== false && (
|
|
102
|
+
{paymentMethod === "cc" && settings?.enable3DSecure && (
|
|
78
103
|
<Box marginTop={4}>
|
|
79
104
|
<CardDetailsInput
|
|
80
105
|
cardtype={cardtype}
|
|
@@ -97,18 +122,49 @@ const AuthorizationForm = ({
|
|
|
97
122
|
onError={handleGooglePayError}
|
|
98
123
|
settings={settings}
|
|
99
124
|
/>
|
|
125
|
+
) : paymentMethod === "apl" ? (
|
|
126
|
+
<Box>
|
|
127
|
+
<ApplePayButton
|
|
128
|
+
amount={paymentAmount}
|
|
129
|
+
currency="EUR"
|
|
130
|
+
onTokenReceived={handleApplePayToken}
|
|
131
|
+
onError={handleApplePayError}
|
|
132
|
+
settings={settings}
|
|
133
|
+
/>
|
|
134
|
+
{applePayToken && (
|
|
135
|
+
<Box marginTop={3} style={{ width: "100%", display: "flex", flexDirection: "column", alignItems: "flex-start", gap: "8px" }}>
|
|
136
|
+
<Typography variant="pi" textColor="success600" style={{ marginBottom: "8px", fontWeight: "bold" }}>
|
|
137
|
+
✓ Apple Pay token received. You can now process the authorization:
|
|
138
|
+
</Typography>
|
|
139
|
+
<Button
|
|
140
|
+
variant="default"
|
|
141
|
+
onClick={() => onAuthorization(applePayToken)}
|
|
142
|
+
loading={isProcessingPayment}
|
|
143
|
+
startIcon={<Play />}
|
|
144
|
+
style={{ maxWidth: '200px' }}
|
|
145
|
+
disabled={!paymentAmount.trim() || !authReference.trim() || isLiveMode}
|
|
146
|
+
className="payment-button payment-button-primary"
|
|
147
|
+
>
|
|
148
|
+
Process Authorization
|
|
149
|
+
</Button>
|
|
150
|
+
</Box>
|
|
151
|
+
)}
|
|
152
|
+
</Box>
|
|
100
153
|
) : (
|
|
101
154
|
<Button
|
|
102
155
|
variant="default"
|
|
103
156
|
onClick={onAuthorization}
|
|
104
157
|
loading={isProcessingPayment}
|
|
105
158
|
startIcon={<Play />}
|
|
159
|
+
style={{ maxWidth: '200px' }}
|
|
106
160
|
className="payment-button payment-button-primary"
|
|
107
161
|
disabled={
|
|
108
162
|
!paymentAmount.trim() ||
|
|
109
163
|
(paymentMethod === "cc" &&
|
|
110
164
|
settings?.enable3DSecure !== false &&
|
|
111
|
-
(!cardtype || !cardpan || !cardexpiredate || !cardcvc2))
|
|
165
|
+
(!cardtype || !cardpan || !cardexpiredate || !cardcvc2)) ||
|
|
166
|
+
(paymentMethod === "apl" && !applePayToken) ||
|
|
167
|
+
isLiveMode
|
|
112
168
|
}
|
|
113
169
|
>
|
|
114
170
|
Process Authorization
|
|
@@ -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
|