strapi-plugin-payone-provider 1.5.8 → 1.6.1

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.
Files changed (53) hide show
  1. package/admin/src/components/Initializer/index.jsx +16 -0
  2. package/admin/src/components/PluginIcon/index.jsx +6 -0
  3. package/admin/src/index.js +3 -3
  4. package/admin/src/pages/App/components/AppHeader.jsx +55 -0
  5. package/admin/src/pages/App/components/AppTabs.jsx +158 -0
  6. package/admin/src/pages/App/components/ApplePayBtn.jsx +304 -0
  7. package/admin/src/pages/App/components/ApplePayButton.js +139 -93
  8. package/admin/src/pages/App/components/ApplePayButton.jsx +908 -0
  9. package/admin/src/pages/App/components/ApplePayConfig.jsx +298 -0
  10. package/admin/src/pages/App/components/ApplePayConfigPanel.jsx +81 -0
  11. package/admin/src/pages/App/components/ConfigurationPanel.jsx +280 -0
  12. package/admin/src/pages/App/components/DocsPanel.jsx +1057 -0
  13. package/admin/src/pages/App/components/GooglePayConfig.jsx +217 -0
  14. package/admin/src/pages/App/components/GooglePayConfigPanel.jsx +82 -0
  15. package/admin/src/pages/App/components/GooglePaybutton.jsx +300 -0
  16. package/admin/src/pages/App/components/HistoryPanel.jsx +285 -0
  17. package/admin/src/pages/App/components/PaymentActionsPanel.jsx +238 -0
  18. package/admin/src/pages/App/components/StatusBadge.jsx +24 -0
  19. package/admin/src/pages/App/components/TransactionHistoryItem.jsx +377 -0
  20. package/admin/src/pages/App/components/icons/BankIcon.jsx +10 -0
  21. package/admin/src/pages/App/components/icons/ChevronDownIcon.jsx +9 -0
  22. package/admin/src/pages/App/components/icons/ChevronUpIcon.jsx +9 -0
  23. package/admin/src/pages/App/components/icons/CreditCardIcon.jsx +9 -0
  24. package/admin/src/pages/App/components/icons/ErrorIcon.jsx +10 -0
  25. package/admin/src/pages/App/components/icons/InfoIcon.jsx +9 -0
  26. package/admin/src/pages/App/components/icons/PaymentIcon.jsx +10 -0
  27. package/admin/src/pages/App/components/icons/PendingIcon.jsx +9 -0
  28. package/admin/src/pages/App/components/icons/PersonIcon.jsx +9 -0
  29. package/admin/src/pages/App/components/icons/SuccessIcon.jsx +9 -0
  30. package/admin/src/pages/App/components/icons/WalletIcon.jsx +9 -0
  31. package/admin/src/pages/App/components/icons/index.jsx +11 -0
  32. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.jsx +205 -0
  33. package/admin/src/pages/App/components/paymentActions/CaptureForm.jsx +65 -0
  34. package/admin/src/pages/App/components/paymentActions/CardDetailsInput.jsx +191 -0
  35. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.jsx +236 -0
  36. package/admin/src/pages/App/components/paymentActions/PaymentResult.jsx +148 -0
  37. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +132 -0
  38. package/admin/src/pages/App/components/paymentActions/RefundForm.jsx +90 -0
  39. package/admin/src/pages/App/index.jsx +127 -0
  40. package/admin/src/pages/constants/paymentConstants.js +1 -2
  41. package/admin/src/pages/hooks/usePaymentActions.js +96 -0
  42. package/package.json +2 -2
  43. package/server/bootstrap.js +65 -0
  44. package/server/controllers/payone.js +4 -48
  45. package/server/routes/index.js +1 -1
  46. package/server/services/applePayService.js +51 -407
  47. package/server/services/paymentService.js +0 -68
  48. package/server/services/payone.js +0 -3
  49. package/server/services/settingsService.js +0 -21
  50. package/server/services/testConnectionService.js +0 -14
  51. package/server/services/transactionService.js +14 -0
  52. package/server/utils/paymentMethodParams.js +60 -27
  53. package/server/utils/requestBuilder.js +0 -22
@@ -0,0 +1,298 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, Select, Option, Checkbox, Stack } from "@strapi/design-system";
3
+ import {
4
+ APPLE_PAY_SUPPORTED_COUNTRIES,
5
+ APPLE_PAY_SUPPORTED_NETWORKS,
6
+ APPLE_PAY_MERCHANT_CAPABILITIES,
7
+ getSupportedCurrenciesForCountry,
8
+ getSupportedNetworksForCountry,
9
+ APPLE_PAY_BUTTON_STYLES,
10
+ APPLE_PAY_BUTTON_TYPES,
11
+ DEFAULT_APPLE_PAY_CONFIG
12
+ } from "../../utils/applePayConstants";
13
+
14
+ const ApplePayConfig = ({
15
+ config,
16
+ onConfigChange,
17
+ settings
18
+ }) => {
19
+ const {
20
+ countryCode = DEFAULT_APPLE_PAY_CONFIG.countryCode,
21
+ currencyCode = DEFAULT_APPLE_PAY_CONFIG.currencyCode,
22
+ merchantCapabilities = DEFAULT_APPLE_PAY_CONFIG.merchantCapabilities,
23
+ supportedNetworks = DEFAULT_APPLE_PAY_CONFIG.supportedNetworks,
24
+ buttonStyle = DEFAULT_APPLE_PAY_CONFIG.buttonStyle,
25
+ buttonType = DEFAULT_APPLE_PAY_CONFIG.buttonType,
26
+ } = config || {};
27
+
28
+ const supportedCurrencies = getSupportedCurrenciesForCountry(countryCode);
29
+ const supportedNetworksForCountry = getSupportedNetworksForCountry(countryCode);
30
+
31
+ const handleCountryChange = (value) => {
32
+ const newConfig = {
33
+ ...config,
34
+ countryCode: value
35
+ };
36
+
37
+ const newSupportedCurrencies = getSupportedCurrenciesForCountry(value);
38
+ if (!newSupportedCurrencies.find(c => c.code === currencyCode)) {
39
+ newConfig.currencyCode = newSupportedCurrencies[0]?.code || "USD";
40
+ }
41
+
42
+ newConfig.supportedNetworks = getSupportedNetworksForCountry(value);
43
+
44
+ onConfigChange(newConfig);
45
+ };
46
+
47
+ const handleCurrencyChange = (value) => {
48
+ onConfigChange({
49
+ ...config,
50
+ currencyCode: value
51
+ });
52
+ };
53
+
54
+ const handleNetworkToggle = (networkCode) => {
55
+ const currentNetworks = supportedNetworks || [];
56
+ const newNetworks = currentNetworks.includes(networkCode)
57
+ ? currentNetworks.filter(n => n !== networkCode)
58
+ : [...currentNetworks, networkCode];
59
+
60
+ onConfigChange({
61
+ ...config,
62
+ supportedNetworks: newNetworks
63
+ });
64
+ };
65
+
66
+ const handleCapabilityToggle = (capabilityCode) => {
67
+ const currentCapabilities = merchantCapabilities || [];
68
+ const newCapabilities = currentCapabilities.includes(capabilityCode)
69
+ ? currentCapabilities.filter(c => c !== capabilityCode)
70
+ : [...currentCapabilities, capabilityCode];
71
+
72
+ onConfigChange({
73
+ ...config,
74
+ merchantCapabilities: newCapabilities
75
+ });
76
+ };
77
+
78
+ return (
79
+ <Box>
80
+ <Stack spacing={6}>
81
+ <Box>
82
+ <Typography variant="delta" as="h3" fontWeight="bold" style={{ marginBottom: "6px" }}>
83
+ Apple Pay Configuration
84
+ </Typography>
85
+ <Typography variant="pi" textColor="neutral600">
86
+ Configure Apple Pay settings for your payment gateway
87
+ </Typography>
88
+ </Box>
89
+
90
+ {/* Country and Currency */}
91
+ <Flex gap={4} wrap="wrap">
92
+ <Box style={{ flex: 1, minWidth: "300px" }}>
93
+ <Select
94
+ label="Country Code"
95
+ name="countryCode"
96
+ value={countryCode}
97
+ onChange={handleCountryChange}
98
+ hint="Select the country where your business operates"
99
+ required
100
+ >
101
+ {APPLE_PAY_SUPPORTED_COUNTRIES.map(country => (
102
+ <Option key={country.code} value={country.code}>
103
+ {country.name} ({country.code})
104
+ </Option>
105
+ ))}
106
+ </Select>
107
+ </Box>
108
+
109
+ <Box style={{ flex: 1, minWidth: "300px" }}>
110
+ <Select
111
+ label="Currency Code"
112
+ name="currencyCode"
113
+ value={currencyCode}
114
+ onChange={handleCurrencyChange}
115
+ hint={`Supported currencies for ${countryCode}`}
116
+ required
117
+ >
118
+ {supportedCurrencies.map(currency => (
119
+ <Option key={currency.code} value={currency.code}>
120
+ {currency.name} ({currency.code}) {currency.symbol}
121
+ </Option>
122
+ ))}
123
+ </Select>
124
+ {supportedCurrencies.length === 0 && (
125
+ <Typography variant="pi" textColor="danger600" style={{ marginTop: "4px" }}>
126
+ No supported currencies for this country. Please select a different country.
127
+ </Typography>
128
+ )}
129
+ </Box>
130
+ </Flex>
131
+
132
+ {/* Button Style and Type */}
133
+ <Flex gap={4} wrap="wrap">
134
+ <Box style={{ flex: 1, minWidth: "300px" }}>
135
+ <Select
136
+ label="Button Style"
137
+ name="buttonStyle"
138
+ value={buttonStyle}
139
+ onChange={(value) => onConfigChange({ ...config, buttonStyle: value })}
140
+ hint="Visual style of the Apple Pay button"
141
+ >
142
+ {APPLE_PAY_BUTTON_STYLES.map(style => (
143
+ <Option key={style.code} value={style.code}>
144
+ {style.name}
145
+ </Option>
146
+ ))}
147
+ </Select>
148
+ </Box>
149
+
150
+ <Box style={{ flex: 1, minWidth: "300px" }}>
151
+ <Select
152
+ label="Button Type"
153
+ name="buttonType"
154
+ value={buttonType}
155
+ onChange={(value) => onConfigChange({ ...config, buttonType: value })}
156
+ hint="Type of action the button represents"
157
+ >
158
+ {APPLE_PAY_BUTTON_TYPES.map(type => (
159
+ <Option key={type.code} value={type.code}>
160
+ {type.name}
161
+ </Option>
162
+ ))}
163
+ </Select>
164
+ </Box>
165
+ </Flex>
166
+
167
+ {/* Supported Networks */}
168
+ <Box>
169
+ <Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
170
+ Supported Networks
171
+ </Typography>
172
+ <Typography variant="pi" textColor="neutral600" style={{ marginLeft: "2px" }}>
173
+ Select payment networks supported in {countryCode}
174
+ </Typography>
175
+ <Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
176
+ {APPLE_PAY_SUPPORTED_NETWORKS.map(network => {
177
+ const isSupported = supportedNetworksForCountry.includes(network.code);
178
+ const isSelected = supportedNetworks?.includes(network.code);
179
+
180
+ return (
181
+ <Box key={network.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
182
+ <Checkbox
183
+ name={`network-${network.code}`}
184
+ checked={isSelected}
185
+ onChange={() => handleNetworkToggle(network.code)}
186
+ disabled={!isSupported}
187
+ hint={!isSupported ? `Not supported in ${countryCode}` : undefined}
188
+ >
189
+ {network.name} ({network.code})
190
+ {!isSupported && (
191
+ <Typography variant="sigma" textColor="neutral500" style={{ marginLeft: "8px" }}>
192
+ (Not available)
193
+ </Typography>
194
+ )}
195
+ </Checkbox>
196
+ </Box>
197
+ );
198
+ })}
199
+ </Flex>
200
+ {supportedNetworks?.length === 0 && (
201
+ <Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
202
+ At least one network must be selected
203
+ </Typography>
204
+ )}
205
+ </Box>
206
+
207
+ {/* Merchant Capabilities */}
208
+ <Box>
209
+ <Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
210
+ Merchant Capabilities
211
+ </Typography>
212
+ <Typography variant="pi" textColor="neutral600" style={{ marginLeft: "2px" }}>
213
+ Select payment capabilities. "3D Secure" is required for most payment methods.
214
+ </Typography>
215
+ <Flex wrap="wrap" gap={4} style={{ marginTop: "12px" }}>
216
+ {APPLE_PAY_MERCHANT_CAPABILITIES.map(capability => {
217
+ const isSelected = merchantCapabilities?.includes(capability.code);
218
+
219
+ return (
220
+ <Box key={capability.code} style={{ flex: "0 0 calc(50% - 8px)", minWidth: "250px" }}>
221
+ <Checkbox
222
+ name={`capability-${capability.code}`}
223
+ checked={isSelected}
224
+ onChange={() => handleCapabilityToggle(capability.code)}
225
+ >
226
+ {capability.name} - {capability.description}
227
+ </Checkbox>
228
+ </Box>
229
+ );
230
+ })}
231
+ </Flex>
232
+ {merchantCapabilities?.length === 0 && (
233
+ <Typography variant="pi" textColor="danger600" style={{ marginTop: "8px" }}>
234
+ At least one capability must be selected. "supports3DS" is recommended.
235
+ </Typography>
236
+ )}
237
+ </Box>
238
+
239
+
240
+ {/* Merchant Identifier Info */}
241
+ <Box>
242
+ <Typography variant="pi" fontWeight="semiBold" style={{ marginLeft: "2px" }}>
243
+ Merchant Identifier
244
+ </Typography>
245
+ <Typography variant="pi" textColor="neutral600">
246
+ {settings?.mid || settings?.portalid
247
+ ? `Using: ${settings.mid || settings.portalid}`
248
+ : "Merchant identifier will be obtained from Payone after domain verification. See documentation for setup instructions."
249
+ }
250
+ </Typography>
251
+ </Box>
252
+
253
+ {/* Domain Verification File Alert */}
254
+ <Box marginTop={4}>
255
+ <Box padding={3} background="warning100" borderRadius="4px" borderColor="warning200" borderWidth="1px" borderStyle="solid">
256
+ <Typography variant="pi" fontWeight="bold" textColor="warning700" marginBottom={2}>
257
+ ⚠️ Domain Verification File Required {' '}
258
+ </Typography>
259
+ <Typography variant="pi" textColor="neutral700" marginBottom={2}>
260
+ <strong>Download the Apple Pay domain verification file</strong> from your Payone merchant portal:
261
+ </Typography>
262
+ <Box padding={2} background="neutral0" borderRadius="4px" marginTop={2} marginBottom={2}>
263
+ <Typography variant="pi" style={{ fontSize: "12px" }}>
264
+ <strong>Download URL:</strong> Download the domain verification file from Payone documentation:{" "}
265
+ <a
266
+ href="https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev"
267
+ target="_blank"
268
+ rel="noopener noreferrer"
269
+ style={{ color: "#0066ff", textDecoration: "underline" }}
270
+ >
271
+ https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev
272
+ </a>
273
+ </Typography>
274
+ </Box>
275
+ <Typography variant="pi" textColor="neutral700" marginBottom={2}>
276
+ <strong>Place the file at:</strong>
277
+ </Typography>
278
+ <Box padding={2} background="neutral0" borderRadius="4px" marginTop={2} marginBottom={2}>
279
+ <Typography variant="pi" style={{ fontFamily: "monospace", fontSize: "12px" }}>
280
+ <strong>Strapi:</strong> <code>public/.well-known/apple-developer-merchantid-domain-association</code><br />
281
+ <strong>Frontend:</strong> <code>public/.well-known/apple-developer-merchantid-domain-association</code>
282
+ </Typography>
283
+ </Box>
284
+ <Typography variant="pi" textColor="neutral700" marginTop={2}>
285
+ The file must be accessible at: <code>https://yourdomain.com/.well-known/apple-developer-merchantid-domain-association</code>
286
+ </Typography>
287
+ <br />
288
+ <Typography variant="pi" fontWeight="bold" textColor="danger600" marginTop={2}>
289
+ Without this file, Apple Pay will NOT work on your domain!
290
+ </Typography>
291
+ </Box>
292
+ </Box>
293
+ </Stack>
294
+ </Box>
295
+ );
296
+ };
297
+
298
+ export default ApplePayConfig;
@@ -0,0 +1,81 @@
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 ApplePayConfig from "./ApplePayConfig";
12
+
13
+ const ApplePayConfigPanel = ({
14
+ settings,
15
+ onInputChange,
16
+ isSaving,
17
+ onSave
18
+ }) => {
19
+ const [applePayConfig, setApplePayConfig] = useState(settings?.applePayConfig || {});
20
+
21
+ useEffect(() => {
22
+ setApplePayConfig(settings?.applePayConfig || {});
23
+ }, [settings?.applePayConfig]);
24
+
25
+ return (
26
+ <Box
27
+ className="payment-container"
28
+ paddingTop={8}
29
+ paddingBottom={8}
30
+ paddingLeft={8}
31
+ paddingRight={8}
32
+ >
33
+ <Flex direction="column" alignItems="stretch" gap={8}>
34
+ <Box>
35
+ <Typography variant="beta" as="h2" fontWeight="bold" className="payment-title" style={{ fontSize: '20px', marginBottom: '4px' }}>
36
+ Apple Pay Configuration
37
+ </Typography>
38
+ <Typography variant="pi" textColor="neutral600" marginTop={2} className="payment-subtitle" style={{ fontSize: '14px' }}>
39
+ Configure Apple Pay settings for your payment gateway
40
+ </Typography>
41
+ </Box>
42
+
43
+ <Box>
44
+ <Card className="payment-card">
45
+ <CardBody padding={6}>
46
+ <ApplePayConfig
47
+ config={applePayConfig}
48
+ onConfigChange={(newConfig) => {
49
+ setApplePayConfig(newConfig);
50
+ onInputChange("applePayConfig", newConfig);
51
+ }}
52
+ settings={settings}
53
+ />
54
+ </CardBody>
55
+ </Card>
56
+ </Box>
57
+
58
+ <Box paddingTop={4}>
59
+ <Flex direction="row" gap={4} alignItems="center">
60
+ <Button
61
+ loading={isSaving}
62
+ onClick={onSave}
63
+ startIcon={<Check />}
64
+ size="L"
65
+ variant="default"
66
+ className="payment-button payment-button-success"
67
+ >
68
+ Save Apple Pay Configuration
69
+ </Button>
70
+ <Typography variant="sigma" textColor="neutral600">
71
+ Note: Apple Pay configuration is used for Apple Pay payment requests. Make sure to configure the correct merchant identifier, supported networks, and capabilities for your region.
72
+ </Typography>
73
+ </Flex>
74
+ </Box>
75
+ </Flex>
76
+ </Box>
77
+ );
78
+ };
79
+
80
+ export default ApplePayConfigPanel;
81
+
@@ -0,0 +1,280 @@
1
+ import React, { useEffect } from "react";
2
+ import {
3
+ Box,
4
+ Button,
5
+ Card,
6
+ CardBody,
7
+ Flex,
8
+ Stack,
9
+ Typography,
10
+ TextInput,
11
+ Select,
12
+ Option,
13
+ Alert
14
+ } from "@strapi/design-system";
15
+ import { Play } from "@strapi/icons";
16
+
17
+ const ConfigurationPanel = ({
18
+ settings,
19
+ isSaving,
20
+ isTesting,
21
+ testResult,
22
+ onSave,
23
+ onTestConnection,
24
+ onInputChange
25
+ }) => {
26
+ const mode = (settings?.mode || "test").toLowerCase();
27
+
28
+ useEffect(() => {
29
+ if (settings?.mode) {
30
+ const currentMode = (settings.mode || "test").toLowerCase();
31
+ console.log("[ConfigurationPanel] Mode updated:", currentMode);
32
+ }
33
+ }, [settings?.mode]);
34
+
35
+
36
+ return (
37
+ <Box
38
+ className="payment-container"
39
+ paddingTop={8}
40
+ paddingBottom={8}
41
+ paddingLeft={8}
42
+ paddingRight={8}
43
+ >
44
+ <Flex direction="column" alignItems="stretch" gap={8}>
45
+ <Box>
46
+ <Typography variant="beta" as="h2" fontWeight="bold" className="payment-title" style={{ fontSize: '20px', marginBottom: '4px' }}>
47
+ Payone API Configuration
48
+ </Typography>
49
+ <Typography variant="pi" textColor="neutral600" marginTop={2} className="payment-subtitle" style={{ fontSize: '14px' }}>
50
+ Configure your Payone payment gateway settings
51
+ </Typography>
52
+ </Box>
53
+
54
+ <Box>
55
+ <Card className="payment-card">
56
+ <CardBody padding={6}>
57
+ <Stack spacing={6}>
58
+ <Flex gap={4} wrap="wrap">
59
+ <TextInput
60
+ label="Account ID (aid)"
61
+ name="aid"
62
+ value={settings.aid || ""}
63
+ onChange={(e) => onInputChange("aid", e.target.value)}
64
+ required
65
+ hint="Your Payone account ID"
66
+ className="payment-input"
67
+ style={{ flex: 1, minWidth: "300px" }}
68
+ />
69
+
70
+ <TextInput
71
+ label="Portal ID"
72
+ name="portalid"
73
+ value={settings.portalid || ""}
74
+ onChange={(e) => onInputChange("portalid", e.target.value)}
75
+ required
76
+ hint="Your Payone portal ID"
77
+ className="payment-input"
78
+ style={{ flex: 1, minWidth: "300px" }}
79
+ />
80
+ </Flex>
81
+
82
+ <Flex gap={4} wrap="wrap">
83
+ <TextInput
84
+ label="Merchant ID (mid)"
85
+ name="mid"
86
+ value={settings.mid || ""}
87
+ onChange={(e) => onInputChange("mid", e.target.value)}
88
+ required
89
+ hint="Your Payone merchant ID"
90
+ className="payment-input"
91
+ style={{ flex: 1, minWidth: "300px" }}
92
+ />
93
+
94
+ <TextInput
95
+ label="Portal Key"
96
+ name="key"
97
+ type="password"
98
+ value={settings.key || ""}
99
+ onChange={(e) => onInputChange("key", e.target.value)}
100
+ required
101
+ hint="Your Payone portal key (will be encrypted)"
102
+ className="payment-input"
103
+ style={{ flex: 1, minWidth: "300px" }}
104
+ />
105
+ </Flex>
106
+
107
+ <Flex gap={4} wrap="wrap">
108
+ <Select
109
+ label="Mode"
110
+ name="mode"
111
+ value={settings.mode || "test"}
112
+ onChange={(value) => onInputChange("mode", value)}
113
+ hint="Select the API mode"
114
+ className="payment-input"
115
+ style={{ flex: 1, minWidth: "300px" }}
116
+ >
117
+ <Option value="test">Test</Option>
118
+ <Option value="live">Live</Option>
119
+ </Select>
120
+
121
+ <TextInput
122
+ label="API Version"
123
+ name="api_version"
124
+ value={settings.api_version || "3.10"}
125
+ onChange={(e) =>
126
+ onInputChange("api_version", e.target.value)
127
+ }
128
+ hint="Payone API version"
129
+ className="payment-input"
130
+ style={{ flex: 1, minWidth: "300px" }}
131
+ />
132
+ </Flex>
133
+
134
+ <Flex direction="column" wrap="wrap" gap={1} alignItems="flex-start">
135
+ <Select
136
+ label="Enable 3D Secure"
137
+ name="enable3DSecure"
138
+ value={settings.enable3DSecure ? "yes" : "no"}
139
+ onChange={(value) =>
140
+ onInputChange("enable3DSecure", value === "yes")
141
+ }
142
+ hint="Enable 3D Secure authentication for credit card payments"
143
+ className="payment-input"
144
+ >
145
+ <Option value="yes">Enabled</Option>
146
+ <Option value="no">Disabled</Option>
147
+ </Select>
148
+ <Typography variant="pi" textColor="neutral600" marginTop={1}>
149
+ When enabled, credit card payments will require 3D Secure authentication (SCA compliance)
150
+ </Typography>
151
+ </Flex>
152
+ </Stack>
153
+ </CardBody>
154
+ </Card>
155
+ </Box>
156
+
157
+ <Box paddingTop={6}>
158
+ <Card className="payment-card">
159
+ <CardBody padding={6}>
160
+ <Stack spacing={6}>
161
+ <Box>
162
+ <Typography
163
+ variant="delta"
164
+ as="h3"
165
+ fontWeight="bold"
166
+ marginBottom={2}
167
+ >
168
+ Test Connection
169
+ </Typography>
170
+ <Typography variant="pi" textColor="neutral600">
171
+ Verify your Payone configuration by testing the API
172
+ connection
173
+ </Typography>
174
+ </Box>
175
+
176
+ <Button
177
+ variant="default"
178
+ onClick={onTestConnection}
179
+ loading={isTesting}
180
+ startIcon={<Play />}
181
+ className="payment-button payment-button-success"
182
+ disabled={mode === 'live'}
183
+ >
184
+ {isTesting ? "Testing Connection..." : "Test Connection"}
185
+ </Button>
186
+ {mode === 'live' && (
187
+ <Typography variant="pi" textColor="neutral600" style={{ marginTop: "8px" }}>
188
+ Test Connection is disabled in live mode for security reasons.
189
+ </Typography>
190
+ )}
191
+
192
+ {testResult && (
193
+ <Alert
194
+ variant={Boolean(testResult.success) ? "success" : "danger"}
195
+ title={
196
+ Boolean(testResult.success)
197
+ ? "Connection Successful"
198
+ : "Connection Failed"
199
+ }
200
+ className="payment-alert"
201
+ >
202
+ <Typography
203
+ variant="pi"
204
+ fontWeight="medium"
205
+ marginBottom={2}
206
+ >
207
+ {testResult.message}
208
+ </Typography>
209
+ {testResult.details && (
210
+ <Box paddingTop={3}>
211
+ {Boolean(testResult.success) ? (
212
+ <Card className="payment-card">
213
+ <CardBody padding={4}>
214
+ <Typography variant="pi">
215
+ <strong>Mode:</strong> {testResult.details.mode}{" "}
216
+ |<strong> AID:</strong> {testResult.details.aid}{" "}
217
+ |<strong> Portal ID:</strong>{" "}
218
+ {testResult.details.portalid} |
219
+ <strong> Merchant ID:</strong>{" "}
220
+ {testResult.details.mid || ""}
221
+ </Typography>
222
+ </CardBody>
223
+ </Card>
224
+ ) : (
225
+ <Card className="payment-card" style={{ background: "#fff5f5" }}>
226
+ <CardBody padding={4}>
227
+ <Stack spacing={2}>
228
+ {testResult.errorcode && (
229
+ <Typography
230
+ variant="pi"
231
+ textColor="neutral600"
232
+ >
233
+ <strong>Error Code:</strong>{" "}
234
+ {testResult.errorcode}
235
+ </Typography>
236
+ )}
237
+ {testResult.details.errorCode && (
238
+ <Typography
239
+ variant="pi"
240
+ textColor="neutral600"
241
+ >
242
+ <strong>Error Code:</strong>{" "}
243
+ {testResult.details.errorCode}
244
+ </Typography>
245
+ )}
246
+ {testResult.details &&
247
+ testResult.details.rawResponse && (
248
+ <Typography
249
+ variant="pi"
250
+ textColor="neutral600"
251
+ >
252
+ <strong>Debug Info:</strong>{" "}
253
+ {testResult.details.rawResponse}
254
+ </Typography>
255
+ )}
256
+ </Stack>
257
+ </CardBody>
258
+ </Card>
259
+ )}
260
+ </Box>
261
+ )}
262
+ </Alert>
263
+ )}
264
+ </Stack>
265
+ </CardBody>
266
+ </Card>
267
+ </Box>
268
+
269
+ <Box paddingTop={4}>
270
+ <Typography variant="sigma" textColor="neutral600">
271
+ Note: These settings are used for all Payone API requests. Make sure
272
+ to use the correct credentials for your selected mode.
273
+ </Typography>
274
+ </Box>
275
+ </Flex>
276
+ </Box>
277
+ );
278
+ };
279
+
280
+ export default ConfigurationPanel;