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,205 @@
1
+ import React from "react";
2
+ import {
3
+ Box,
4
+ Flex,
5
+ Typography,
6
+ TextInput,
7
+ Button,
8
+ } from "@strapi/design-system";
9
+ import { Play } from "@strapi/icons";
10
+ import GooglePayButton from "../GooglePaybutton";
11
+ import ApplePayBtn from "../ApplePayBtn";
12
+ import CardDetailsInput from "./CardDetailsInput";
13
+
14
+ const AuthorizationForm = ({
15
+ paymentAmount,
16
+ setPaymentAmount,
17
+ authReference,
18
+ setAuthReference,
19
+ isProcessingPayment,
20
+ onAuthorization,
21
+ paymentMethod,
22
+ settings,
23
+ setGooglePayToken,
24
+ applePayToken,
25
+ setApplePayToken,
26
+ cardtype,
27
+ setCardtype,
28
+ cardpan,
29
+ setCardpan,
30
+ cardexpiredate,
31
+ setCardexpiredate,
32
+ cardcvc2,
33
+ setCardcvc2,
34
+ isLiveMode = false,
35
+ }) => {
36
+ const handleGooglePayToken = (token, paymentData) => {
37
+ if (!token) {
38
+ return;
39
+ }
40
+ setGooglePayToken(token);
41
+ onAuthorization(token);
42
+ };
43
+
44
+ const handleGooglePayError = (error) => {
45
+ if (onError) {
46
+ onError(error);
47
+ }
48
+ };
49
+
50
+ const handleApplePayToken = async (token, paymentData) => {
51
+ if (!token) {
52
+ return Promise.reject(new Error("Token is missing"));
53
+ }
54
+
55
+ setApplePayToken(token);
56
+
57
+ return Promise.resolve({
58
+ success: true,
59
+ message:
60
+ "Token received successfully. Please click 'Process Authorization' to complete the payment.",
61
+ });
62
+ };
63
+
64
+ const handleApplePayError = (error) => {
65
+ if (onError) {
66
+ onError(error);
67
+ }
68
+ };
69
+
70
+ return (
71
+ <Flex direction="column" alignItems="stretch" gap={4}>
72
+ <Flex direction="row" gap={2}>
73
+ <Typography
74
+ variant="omega"
75
+ fontWeight="semiBold"
76
+ textColor="neutral800"
77
+ className="payment-form-title"
78
+ >
79
+ Authorization
80
+ </Typography>
81
+ <Typography
82
+ variant="pi"
83
+ textColor="neutral600"
84
+ className="payment-form-description"
85
+ >
86
+ Authorize and capture an amount immediately.
87
+ </Typography>
88
+ </Flex>
89
+
90
+ <Flex gap={4} wrap="wrap">
91
+ <TextInput
92
+ label="Amount (in cents) *"
93
+ name="authAmount"
94
+ value={paymentAmount}
95
+ onChange={(e) => setPaymentAmount(e.target.value)}
96
+ placeholder="Enter amount (e.g., 1000 for €10.00)"
97
+ hint="Amount in cents (e.g., 1000 = €10.00)"
98
+ required
99
+ className="payment-input"
100
+ style={{ flex: 1, minWidth: "250px" }}
101
+ />
102
+
103
+ <TextInput
104
+ label="Reference *"
105
+ name="authReference"
106
+ value={authReference}
107
+ onChange={(e) => setAuthReference(e.target.value)}
108
+ placeholder="Auto-generated if empty"
109
+ hint="Reference will be auto-generated if left empty"
110
+ className="payment-input"
111
+ style={{ flex: 1, minWidth: "250px" }}
112
+ />
113
+ </Flex>
114
+
115
+ {paymentMethod === "cc" && settings?.enable3DSecure && (
116
+ <Box marginTop={4}>
117
+ <CardDetailsInput
118
+ cardtype={cardtype}
119
+ setCardtype={setCardtype}
120
+ cardpan={cardpan}
121
+ setCardpan={setCardpan}
122
+ cardexpiredate={cardexpiredate}
123
+ setCardexpiredate={setCardexpiredate}
124
+ cardcvc2={cardcvc2}
125
+ setCardcvc2={setCardcvc2}
126
+ />
127
+ </Box>
128
+ )}
129
+
130
+ {paymentMethod === "gpp" ? (
131
+ <GooglePayButton
132
+ amount={paymentAmount}
133
+ currency="EUR"
134
+ onTokenReceived={handleGooglePayToken}
135
+ onError={handleGooglePayError}
136
+ settings={settings}
137
+ />
138
+ ) : paymentMethod === "apl" ? (
139
+ <Box>
140
+ <ApplePayBtn
141
+ amount={paymentAmount}
142
+ onTokenReceived={handleApplePayToken}
143
+ onError={handleApplePayError}
144
+ settings={settings}
145
+ />
146
+ {applePayToken && (
147
+ <Box
148
+ marginTop={3}
149
+ style={{
150
+ width: "100%",
151
+ display: "flex",
152
+ flexDirection: "column",
153
+ alignItems: "flex-start",
154
+ gap: "8px",
155
+ }}
156
+ >
157
+ <Typography
158
+ variant="pi"
159
+ textColor="success600"
160
+ style={{ marginBottom: "8px", fontWeight: "bold" }}
161
+ >
162
+ ✓ Apple Pay token received. You can now process the
163
+ authorization:
164
+ </Typography>
165
+ <Button
166
+ variant="default"
167
+ onClick={() => onAuthorization(applePayToken)}
168
+ loading={isProcessingPayment}
169
+ startIcon={<Play />}
170
+ style={{ maxWidth: "200px" }}
171
+ disabled={
172
+ !paymentAmount.trim() || !authReference.trim() || isLiveMode
173
+ }
174
+ className="payment-button payment-button-primary"
175
+ >
176
+ Process Authorization
177
+ </Button>
178
+ </Box>
179
+ )}
180
+ </Box>
181
+ ) : (
182
+ <Button
183
+ variant="default"
184
+ onClick={onAuthorization}
185
+ loading={isProcessingPayment}
186
+ startIcon={<Play />}
187
+ style={{ maxWidth: "200px" }}
188
+ className="payment-button payment-button-primary"
189
+ disabled={
190
+ !paymentAmount.trim() ||
191
+ (paymentMethod === "cc" &&
192
+ settings?.enable3DSecure !== false &&
193
+ (!cardtype || !cardpan || !cardexpiredate || !cardcvc2)) ||
194
+ (paymentMethod === "apl" && !applePayToken) ||
195
+ isLiveMode
196
+ }
197
+ >
198
+ Process Authorization
199
+ </Button>
200
+ )}
201
+ </Flex>
202
+ );
203
+ };
204
+
205
+ export default AuthorizationForm;
@@ -0,0 +1,65 @@
1
+ import React from "react";
2
+ import { Box, Flex, Typography, TextInput, Button } from "@strapi/design-system";
3
+ import { Play } from "@strapi/icons";
4
+
5
+ const CaptureForm = ({
6
+ paymentAmount,
7
+ setPaymentAmount,
8
+ captureTxid,
9
+ setCaptureTxid,
10
+ isProcessingPayment,
11
+ onCapture
12
+ }) => {
13
+ return (
14
+ <Flex direction="column" alignItems="stretch" gap={4}>
15
+ <Flex direction="row" gap={2}>
16
+ <Typography variant="omega" fontWeight="semiBold" textColor="neutral800" className="payment-form-title">
17
+ Capture
18
+ </Typography>
19
+ <Typography variant="pi" textColor="neutral600" className="payment-form-description">
20
+ Capture a previously authorized amount. Note: Reference parameter is
21
+ not supported by Payone capture.
22
+ </Typography>
23
+ </Flex>
24
+
25
+ <Flex gap={4} wrap="wrap">
26
+ <TextInput
27
+ label="Transaction ID"
28
+ name="captureTxid"
29
+ value={captureTxid}
30
+ onChange={(e) => setCaptureTxid(e.target.value)}
31
+ placeholder="Enter TxId from preauthorization"
32
+ hint="Transaction ID from a previous preauthorization"
33
+ className="payment-input"
34
+ style={{ flex: 1, minWidth: "250px" }}
35
+ />
36
+
37
+ <TextInput
38
+ label="Amount (in cents)"
39
+ name="captureAmount"
40
+ value={paymentAmount}
41
+ onChange={(e) => setPaymentAmount(e.target.value)}
42
+ placeholder="1000"
43
+ hint="Amount in cents to capture"
44
+ className="payment-input"
45
+ style={{ flex: 1, minWidth: "250px" }}
46
+ />
47
+ </Flex>
48
+
49
+ <Button
50
+ variant="default"
51
+ onClick={onCapture}
52
+ loading={isProcessingPayment}
53
+ startIcon={<Play />}
54
+ style={{ maxWidth: '200px' }}
55
+ className="payment-button payment-button-primary"
56
+ disabled={!captureTxid.trim() || !paymentAmount.trim()}
57
+ >
58
+ Process Capture
59
+ </Button>
60
+ </Flex>
61
+ );
62
+ };
63
+
64
+ export default CaptureForm;
65
+
@@ -0,0 +1,191 @@
1
+ import React, { useEffect, useRef } from "react";
2
+ import {
3
+ Box,
4
+ Flex,
5
+ Typography,
6
+ TextInput,
7
+ Select,
8
+ Option,
9
+ Link
10
+ } from "@strapi/design-system";
11
+
12
+ // 3DS Test Cards that require redirect (challenge workflow)
13
+ const TEST_3DS_CARDS = [
14
+ {
15
+ name: "VISA - 3DS 2.0 (Challenge)",
16
+ cardtype: "V",
17
+ cardpan: "4716971940353559",
18
+ cardexpiredate: "2512",
19
+ cardcvc2: "123",
20
+ description: "3DS 2.0 with challenge - Password: 12345"
21
+ },
22
+ {
23
+ name: "Mastercard - 3DS 2.0 (Challenge)",
24
+ cardtype: "M",
25
+ cardpan: "5404127720739582",
26
+ cardexpiredate: "2512",
27
+ cardcvc2: "123",
28
+ description: "3DS 2.0 with challenge - Password: 12345"
29
+ },
30
+ // {
31
+ // name: "AMEX - 3DS 2.0 (Challenge)",
32
+ // cardtype: "A",
33
+ // cardpan: "375144726036141",
34
+ // cardexpiredate: "2512",
35
+ // cardcvc2: "1234",
36
+ // description: "3DS 2.0 with challenge - Password: 12345"
37
+ // }
38
+ ];
39
+
40
+ const CardDetailsInput = ({
41
+ cardtype,
42
+ setCardtype,
43
+ cardpan,
44
+ setCardpan,
45
+ cardexpiredate,
46
+ setCardexpiredate,
47
+ cardcvc2,
48
+ setCardcvc2
49
+ }) => {
50
+ const [selectedTestCard, setSelectedTestCard] = React.useState("");
51
+ const isUpdatingFromTestCard = useRef(false);
52
+
53
+ useEffect(() => {
54
+ if (isUpdatingFromTestCard.current) {
55
+ isUpdatingFromTestCard.current = false;
56
+ return;
57
+ }
58
+
59
+ const matchingCard = TEST_3DS_CARDS.find(
60
+ card => card.cardtype === cardtype && card.cardpan === cardpan
61
+ );
62
+
63
+ if (matchingCard) {
64
+ const testCardValue = `${matchingCard.cardtype}-${matchingCard.cardpan}`;
65
+ if (selectedTestCard !== testCardValue) {
66
+ setSelectedTestCard(testCardValue);
67
+ }
68
+ } else if (selectedTestCard) {
69
+ setSelectedTestCard("");
70
+ }
71
+ }, [cardtype, cardpan, selectedTestCard]);
72
+
73
+ const handleTestCardSelect = (value) => {
74
+ if (!value || value === "") {
75
+ setSelectedTestCard("");
76
+ return;
77
+ }
78
+
79
+ const selectedCard = TEST_3DS_CARDS.find(card =>
80
+ `${card.cardtype}-${card.cardpan}` === value
81
+ );
82
+
83
+ if (selectedCard) {
84
+ isUpdatingFromTestCard.current = true;
85
+
86
+ setCardtype(selectedCard.cardtype);
87
+ setCardpan(selectedCard.cardpan);
88
+ setCardexpiredate(selectedCard.cardexpiredate);
89
+ setCardcvc2(selectedCard.cardcvc2);
90
+ setSelectedTestCard(value);
91
+ }
92
+ };
93
+
94
+ return (
95
+ <Box>
96
+ <Flex direction="column" alignItems="stretch" gap={4}>
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>
115
+
116
+ <Flex gap={4} wrap="wrap" alignItems="flex-start">
117
+ <Select
118
+ label="Card Type *"
119
+ name="cardtype"
120
+ value={cardtype || ""}
121
+ onChange={(value) => setCardtype(value)}
122
+ required
123
+ hint="Select credit card type"
124
+ className="payment-input"
125
+ style={{ flex: 1, minWidth: "200px" }}
126
+ >
127
+ <Option value="V">VISA</Option>
128
+ <Option value="M">Mastercard</Option>
129
+ <Option value="A">American Express</Option>
130
+ <Option value="J">JCB</Option>
131
+ <Option value="O">Maestro International</Option>
132
+ <Option value="D">Diners Club</Option>
133
+ </Select>
134
+
135
+ <TextInput
136
+ label="Card Number (PAN) *"
137
+ name="cardpan"
138
+ value={cardpan || ""}
139
+ onChange={(e) => setCardpan(e.target.value)}
140
+ placeholder="Enter card number"
141
+ hint="Credit card number (PAN)"
142
+ required
143
+ className="payment-input"
144
+ style={{ flex: 2, minWidth: "300px" }}
145
+ />
146
+ </Flex>
147
+
148
+ <Flex gap={4} wrap="wrap" alignItems="flex-start">
149
+ <TextInput
150
+ label="Expiry Date *"
151
+ name="cardexpiredate"
152
+ value={cardexpiredate || ""}
153
+ onChange={(e) => setCardexpiredate(e.target.value)}
154
+ placeholder="YYMM (e.g., 2512)"
155
+ hint="Format: YYMM (e.g., 2512 = December 2025)"
156
+ required
157
+ maxLength={4}
158
+ className="payment-input"
159
+ style={{ flex: 1, minWidth: "150px" }}
160
+ />
161
+
162
+ <TextInput
163
+ label="CVC/CVV *"
164
+ name="cardcvc2"
165
+ value={cardcvc2 || ""}
166
+ onChange={(e) => setCardcvc2(e.target.value)}
167
+ placeholder="123 or 1234"
168
+ hint={cardtype === "A" ? "4 digits for AMEX" : "3 digits for other cards"}
169
+ required
170
+ maxLength={4}
171
+ className="payment-input"
172
+ style={{ flex: 1, minWidth: "150px" }}
173
+ />
174
+ </Flex>
175
+
176
+ <Box paddingTop={2}>
177
+ <Typography variant="pi" textColor="neutral600" style={{ textAlign: "left" }}>
178
+ For all test card numbers (positive, negative, frictionless 3DS), 3D Secure test data, and detailed documentation, please refer to the{" "}
179
+ <Link href="https://docs.payone.com/security-risk-management/3d-secure#/" target="_blank" rel="noopener noreferrer">
180
+ Payone 3D Secure Documentation
181
+ </Link>
182
+ .
183
+ </Typography>
184
+ </Box>
185
+ </Flex>
186
+ </Box>
187
+ );
188
+ };
189
+
190
+ export default CardDetailsInput;
191
+
@@ -0,0 +1,236 @@
1
+ import React from "react";
2
+ import {
3
+ Box,
4
+ Flex,
5
+ Select,
6
+ Option,
7
+ Typography,
8
+ Link,
9
+ Alert,
10
+ } from "@strapi/design-system";
11
+ import pluginId from "../../../../pluginId";
12
+ import {
13
+ getPaymentMethodOptions,
14
+ supportsCaptureMode,
15
+ getCaptureModeOptions,
16
+ getPaymentMethodDisplayName,
17
+ } from "../../../utils/paymentUtils";
18
+
19
+ const PaymentMethodSelector = ({
20
+ paymentMethod,
21
+ setPaymentMethod,
22
+ captureMode,
23
+ setCaptureMode,
24
+ onNavigateToConfig,
25
+ settings,
26
+ }) => {
27
+ const mode = (settings?.mode || "test").toLowerCase();
28
+ const isLiveMode = mode === "live";
29
+
30
+ return (
31
+ <Box>
32
+ <Flex direction="column" alignItems="stretch" gap={4}>
33
+ <Select
34
+ label="Select Payment Method"
35
+ name="paymentMethod"
36
+ value={paymentMethod}
37
+ onChange={(value) => setPaymentMethod(value)}
38
+ hint={`Current: ${getPaymentMethodDisplayName(paymentMethod)}`}
39
+ >
40
+ {getPaymentMethodOptions().map((option) => (
41
+ <Option key={option.value} value={option.value}>
42
+ {option.label}
43
+ </Option>
44
+ ))}
45
+ </Select>
46
+ {paymentMethod === "apl" && onNavigateToConfig && (
47
+ <>
48
+ <Alert
49
+ closeLabel="Close"
50
+ title="⚠️ Important: Middleware Configuration Required"
51
+ variant="warning"
52
+ >
53
+ <Typography variant="pi" marginTop={2}>
54
+ <strong>Apple Pay requires middleware configuration</strong> to
55
+ work properly. You must configure Content Security Policy (CSP)
56
+ in <code>config/middlewares.js</code> to allow Apple Pay
57
+ scripts, otherwise Apple Pay will NOT work.
58
+ </Typography>
59
+ <Typography variant="pi" marginTop={2}>
60
+ Required CSP directives for Apple Pay:
61
+ </Typography>
62
+ <Box
63
+ marginTop={2}
64
+ padding={2}
65
+ background="neutral100"
66
+ borderRadius="4px"
67
+ >
68
+ <Typography
69
+ variant="pi"
70
+ style={{ fontFamily: "monospace", fontSize: "12px" }}
71
+ >
72
+ 'script-src': ['https://applepay.cdn-apple.com',
73
+ 'https://www.apple.com']
74
+ <br />
75
+ 'connect-src': ['https://applepay.cdn-apple.com',
76
+ 'https://www.apple.com']
77
+ <br />
78
+ 'frame-src': ['https://applepay.cdn-apple.com']
79
+ </Typography>
80
+ </Box>
81
+ <Typography variant="pi" marginTop={2} fontWeight="bold">
82
+ Without this configuration, Apple Pay will NOT work!
83
+ </Typography>
84
+ </Alert>
85
+ <Alert
86
+ closeLabel="Close"
87
+ title="📥 Apple Pay Domain Verification File Required"
88
+ variant="default"
89
+ >
90
+ <Typography variant="pi" marginTop={2}>
91
+ <strong>Download the Apple Pay domain verification file</strong>{" "}
92
+ from your Payone merchant portal and place it in:
93
+ </Typography>
94
+ <Box
95
+ marginTop={2}
96
+ padding={2}
97
+ background="neutral100"
98
+ borderRadius="4px"
99
+ >
100
+ <Typography
101
+ variant="pi"
102
+ style={{ fontFamily: "monospace", fontSize: "12px" }}
103
+ >
104
+ <strong>Strapi:</strong>{" "}
105
+ <code>
106
+ public/.well-known/apple-developer-merchantid-domain-association
107
+ </code>
108
+ <br />
109
+ <strong>Frontend:</strong>{" "}
110
+ <code>
111
+ public/.well-known/apple-developer-merchantid-domain-association
112
+ </code>
113
+ </Typography>
114
+ </Box>
115
+ <Typography variant="pi" marginTop={2}>
116
+ <strong>Download URL:</strong> Download the domain verification
117
+ file from Payone documentation:{" "}
118
+ <Link
119
+ href="https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev"
120
+ target="_blank"
121
+ rel="noopener noreferrer"
122
+ style={{ color: "#0066ff", textDecoration: "underline" }}
123
+ >
124
+ https://docs.payone.com/payment-methods/apple-pay/apple-pay-without-dev
125
+ </Link>
126
+ </Typography>
127
+ <br />
128
+ <Typography
129
+ variant="pi"
130
+ marginTop={2}
131
+ fontWeight="bold"
132
+ textColor="danger600"
133
+ >
134
+ Without this file, Apple Pay will NOT work on your domain!
135
+ </Typography>
136
+ </Alert>
137
+ <Box padding={3} background="neutral100" borderRadius="4px">
138
+ <Typography variant="pi" textColor="neutral600">
139
+ Configure Apple Pay settings:{" "}
140
+ <Link
141
+ href={`/plugins/${pluginId}/apple-pay-config`}
142
+ onClick={(e) => {
143
+ e.preventDefault();
144
+ onNavigateToConfig("apple-pay");
145
+ }}
146
+ style={{
147
+ cursor: "pointer",
148
+ textDecoration: "underline",
149
+ color: "#0066ff",
150
+ }}
151
+ >
152
+ /plugins/{pluginId}/apple-pay-config
153
+ </Link>
154
+ </Typography>
155
+ </Box>
156
+ </>
157
+ )}
158
+ {paymentMethod === "gpp" && onNavigateToConfig && (
159
+ <>
160
+ <Alert
161
+ closeLabel="Close"
162
+ title="⚠️ Important: Middleware Configuration Required"
163
+ variant="warning"
164
+ >
165
+ <Typography variant="pi" marginTop={2}>
166
+ <strong>Google Pay requires middleware configuration</strong> to
167
+ work properly. You must configure Content Security Policy (CSP)
168
+ in <code>config/middlewares.js</code> to allow Google Pay
169
+ scripts, otherwise Google Pay will NOT work.
170
+ </Typography>
171
+ <Typography variant="pi" marginTop={2}>
172
+ Required CSP directives for Google Pay:
173
+ </Typography>
174
+ <Box
175
+ marginTop={2}
176
+ padding={2}
177
+ background="neutral100"
178
+ borderRadius="4px"
179
+ >
180
+ <Typography
181
+ variant="pi"
182
+ style={{ fontFamily: "monospace", fontSize: "12px" }}
183
+ >
184
+ 'script-src': ['https://pay.google.com']
185
+ <br />
186
+ 'connect-src': ['https://pay.google.com']
187
+ <br />
188
+ 'frame-src': ['https://pay.google.com']
189
+ </Typography>
190
+ </Box>
191
+ <Typography variant="pi" marginTop={2} fontWeight="bold">
192
+ ⚠️ Without this configuration, Google Pay will NOT work!
193
+ </Typography>
194
+ </Alert>
195
+ <Box padding={3} background="neutral100" borderRadius="4px">
196
+ <Typography variant="pi" textColor="neutral600">
197
+ Configure Google Pay settings:{" "}
198
+ <Link
199
+ href={`/plugins/${pluginId}/google-pay-config`}
200
+ onClick={(e) => {
201
+ e.preventDefault();
202
+ onNavigateToConfig("google-pay");
203
+ }}
204
+ style={{
205
+ cursor: "pointer",
206
+ textDecoration: "underline",
207
+ color: "#0066ff",
208
+ }}
209
+ >
210
+ /plugins/{pluginId}/google-pay-config
211
+ </Link>
212
+ </Typography>
213
+ </Box>
214
+ </>
215
+ )}
216
+ {supportsCaptureMode(paymentMethod) && (
217
+ <Select
218
+ label="Capture Mode"
219
+ name="captureMode"
220
+ value={captureMode}
221
+ onChange={(value) => setCaptureMode(value)}
222
+ hint="Select capture mode for wallet payments"
223
+ >
224
+ {getCaptureModeOptions().map((option) => (
225
+ <Option key={option.value} value={option.value}>
226
+ {option.label}
227
+ </Option>
228
+ ))}
229
+ </Select>
230
+ )}
231
+ </Flex>
232
+ </Box>
233
+ );
234
+ };
235
+
236
+ export default PaymentMethodSelector;