strapi-plugin-payone-provider 1.6.1 → 1.6.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.
Files changed (46) hide show
  1. package/admin/src/pages/App/components/ApplePayBtn.jsx +15 -13
  2. package/admin/src/pages/App/components/PaymentActionsPanel.jsx +68 -17
  3. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.jsx +4 -12
  4. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.jsx +163 -86
  5. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.jsx +21 -11
  6. package/admin/src/pages/hooks/usePaymentActions.js +0 -172
  7. package/admin/src/pages/utils/paymentUtils.js +2 -2
  8. package/package.json +1 -1
  9. package/server/bootstrap.js +0 -19
  10. package/server/services/transactionService.js +0 -28
  11. package/admin/src/components/Initializer/index.js +0 -16
  12. package/admin/src/components/PluginIcon/index.js +0 -6
  13. package/admin/src/pages/App/components/AppHeader.js +0 -55
  14. package/admin/src/pages/App/components/AppTabs.js +0 -158
  15. package/admin/src/pages/App/components/ApplePayButton.js +0 -950
  16. package/admin/src/pages/App/components/ApplePayConfig.js +0 -364
  17. package/admin/src/pages/App/components/ApplePayConfigPanel.js +0 -81
  18. package/admin/src/pages/App/components/ConfigurationPanel.js +0 -280
  19. package/admin/src/pages/App/components/DocsPanel.js +0 -1057
  20. package/admin/src/pages/App/components/GooglePayConfig.js +0 -217
  21. package/admin/src/pages/App/components/GooglePayConfigPanel.js +0 -82
  22. package/admin/src/pages/App/components/GooglePaybutton.js +0 -300
  23. package/admin/src/pages/App/components/HistoryPanel.js +0 -285
  24. package/admin/src/pages/App/components/PaymentActionsPanel.js +0 -190
  25. package/admin/src/pages/App/components/StatusBadge.js +0 -24
  26. package/admin/src/pages/App/components/TransactionHistoryItem.js +0 -377
  27. package/admin/src/pages/App/components/icons/BankIcon.js +0 -10
  28. package/admin/src/pages/App/components/icons/ChevronDownIcon.js +0 -9
  29. package/admin/src/pages/App/components/icons/ChevronUpIcon.js +0 -9
  30. package/admin/src/pages/App/components/icons/CreditCardIcon.js +0 -9
  31. package/admin/src/pages/App/components/icons/ErrorIcon.js +0 -10
  32. package/admin/src/pages/App/components/icons/InfoIcon.js +0 -9
  33. package/admin/src/pages/App/components/icons/PaymentIcon.js +0 -10
  34. package/admin/src/pages/App/components/icons/PendingIcon.js +0 -9
  35. package/admin/src/pages/App/components/icons/PersonIcon.js +0 -9
  36. package/admin/src/pages/App/components/icons/SuccessIcon.js +0 -9
  37. package/admin/src/pages/App/components/icons/WalletIcon.js +0 -9
  38. package/admin/src/pages/App/components/icons/index.js +0 -11
  39. package/admin/src/pages/App/components/paymentActions/AuthorizationForm.js +0 -195
  40. package/admin/src/pages/App/components/paymentActions/CaptureForm.js +0 -65
  41. package/admin/src/pages/App/components/paymentActions/CardDetailsInput.js +0 -191
  42. package/admin/src/pages/App/components/paymentActions/PaymentMethodSelector.js +0 -156
  43. package/admin/src/pages/App/components/paymentActions/PaymentResult.js +0 -148
  44. package/admin/src/pages/App/components/paymentActions/PreauthorizationForm.js +0 -199
  45. package/admin/src/pages/App/components/paymentActions/RefundForm.js +0 -90
  46. package/admin/src/pages/App/index.js +0 -127
@@ -1,950 +0,0 @@
1
- import React, { useEffect, useRef, useState } from "react";
2
- import { Box, Flex, Typography } from "@strapi/design-system";
3
- import { request } from "@strapi/helper-plugin";
4
- import pluginId from "../../../pluginId";
5
- import { DEFAULT_APPLE_PAY_CONFIG } from "../../utils/applePayConstants";
6
-
7
- /**
8
- * Apple Pay Button Component using Payment Request API
9
- * Based on Apple Pay documentation:
10
- * https://developer.apple.com/documentation/applepayontheweb/creating-an-apple-pay-session
11
- * https://developer.apple.com/documentation/applepayontheweb/displaying-apple-pay-buttons-using-css
12
- *
13
- * Supports Payment Request API (works in Chrome, Edge, Safari, etc.)
14
- * and falls back to Apple Pay JS API if needed
15
- */
16
- const ApplePayButton = ({
17
- amount,
18
- currency = "EUR",
19
- countryCode = "DE",
20
- merchantCapabilities = ["supports3DS"],
21
- supportedNetworks = ["visa", "masterCard", "girocard"],
22
- buttonStyle = "black",
23
- buttonType = "pay",
24
- requestPayerName = false,
25
- requestBillingAddress = false,
26
- requestPayerEmail = false,
27
- requestPayerPhone = false,
28
- requestShipping = false,
29
- shippingType = "shipping",
30
- merchantIdentifier = null,
31
- onTokenReceived,
32
- onError,
33
- settings
34
- }) => {
35
- const [isReady, setIsReady] = useState(false);
36
- const [isLoading, setIsLoading] = useState(true);
37
- const [isAvailable, setIsAvailable] = useState(false);
38
- const [errorMessage, setErrorMessage] = useState(null);
39
- const buttonContainerRef = useRef(null);
40
- const paymentRequestRef = useRef(null);
41
-
42
- const checkApplePayAvailability = async () => {
43
- try {
44
- console.log("[Apple Pay] Checking availability...");
45
-
46
- // Check secure context using browser's native property
47
- // This is the most reliable way to check if we're in a secure context
48
- const isSecureContext = typeof window !== 'undefined' && window.isSecureContext;
49
- const protocol = typeof window !== 'undefined' ? window.location.protocol : '';
50
- const hostname = typeof window !== 'undefined' ? window.location.hostname : '';
51
- const isLocalhost = hostname === 'localhost' || hostname === '127.0.0.1';
52
-
53
- // For Apple Pay, we need a secure context (HTTPS or localhost)
54
- // window.isSecureContext is true for:
55
- // - HTTPS pages
56
- // - localhost (even on HTTP)
57
- // - 127.0.0.1 (even on HTTP)
58
- // - file:// URLs
59
- const isSecure = isSecureContext || isLocalhost;
60
-
61
- console.log("[Apple Pay] Secure context check:", {
62
- isSecureContext: isSecureContext,
63
- protocol: protocol,
64
- hostname: hostname,
65
- isLocalhost: isLocalhost,
66
- isSecure: isSecure,
67
- fullUrl: typeof window !== 'undefined' ? window.location.href : ''
68
- });
69
-
70
- // If not secure, log detailed information
71
- if (!isSecure) {
72
- console.error("[Apple Pay] NOT in secure context!", {
73
- isSecureContext: isSecureContext,
74
- protocol: protocol,
75
- hostname: hostname,
76
- isLocalhost: isLocalhost,
77
- fullUrl: typeof window !== 'undefined' ? window.location.href : '',
78
- reason: !isSecureContext ? "window.isSecureContext is false" : "Unknown"
79
- });
80
- }
81
-
82
- // First, check if Payment Request API is available
83
- // Payment Request API works on HTTP too, but Apple Pay JS API requires HTTPS
84
- if (typeof window === 'undefined' || !window.PaymentRequest) {
85
- console.log("[Apple Pay] Payment Request API not available");
86
-
87
- // Fallback: Check Apple Pay JS API (for Safari, requires HTTPS)
88
- if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
89
- try {
90
- const canMakePayments = ApplePaySession.canMakePayments();
91
- console.log("[Apple Pay] Apple Pay JS API available:", canMakePayments);
92
- return { available: canMakePayments, method: 'applePayJS' };
93
- } catch (error) {
94
- console.error("[Apple Pay] Apple Pay JS API error (likely insecure context):", error.message);
95
- return { available: false, method: null, error: 'insecure_context' };
96
- }
97
- }
98
-
99
- if (!isSecure && typeof window !== 'undefined' && window.ApplePaySession) {
100
- console.warn("[Apple Pay] Apple Pay JS API requires HTTPS. Using Payment Request API fallback.");
101
- }
102
-
103
- console.log("[Apple Pay] No Apple Pay support found");
104
- return { available: false, method: null };
105
- }
106
-
107
- console.log("[Apple Pay] Payment Request API available, checking Apple Pay support...");
108
-
109
- // Check if Apple Pay payment method is supported
110
- const applePayMethod = {
111
- supportedMethods: "https://apple.com/apple-pay",
112
- data: {
113
- version: 3,
114
- merchantIdentifier: merchantIdentifier || settings?.merchantIdentifier || settings?.mid || "merchant.com.payone.test",
115
- merchantCapabilities: merchantCapabilities,
116
- supportedNetworks: supportedNetworks,
117
- countryCode: countryCode
118
- }
119
- };
120
-
121
- // Create a test payment request
122
- // Payment Request API works on HTTP too, but Apple Pay may require HTTPS
123
- let testRequest;
124
- try {
125
- testRequest = new PaymentRequest(
126
- [applePayMethod],
127
- {
128
- total: {
129
- label: "Test",
130
- amount: { value: "0.01", currency: currency }
131
- }
132
- },
133
- {
134
- requestPayerName: false,
135
- requestBillingAddress: false,
136
- requestPayerEmail: false,
137
- requestPayerPhone: false,
138
- requestShipping: false
139
- }
140
- );
141
- } catch (e) {
142
- console.error("[Apple Pay] Error creating PaymentRequest:", e);
143
- // If PaymentRequest creation fails, it might be due to insecure context
144
- if (e.message && e.message.includes('insecure')) {
145
- return { available: false, method: null, error: 'insecure_context' };
146
- }
147
- return { available: false, method: null };
148
- }
149
-
150
- // Check if can make payment
151
- if (testRequest.canMakePayment) {
152
- try {
153
- const canPay = await testRequest.canMakePayment();
154
- console.log("[Apple Pay] canMakePayment result:", canPay);
155
-
156
- if (canPay) {
157
- return { available: true, method: 'paymentRequest' };
158
- }
159
-
160
- // If PaymentRequest says no, try Apple Pay JS API as fallback (only on HTTPS)
161
- if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
162
- try {
163
- const canMakePaymentsJS = ApplePaySession.canMakePayments();
164
- console.log("[Apple Pay] Fallback to Apple Pay JS API:", canMakePaymentsJS);
165
- return { available: canMakePaymentsJS, method: 'applePayJS' };
166
- } catch (e) {
167
- console.error("[Apple Pay] Apple Pay JS API error:", e.message);
168
- // If it's insecure context error, Payment Request API might still work
169
- if (e.message && e.message.includes('insecure')) {
170
- // Payment Request API might work even on HTTP
171
- return { available: false, method: null, error: 'insecure_context' };
172
- }
173
- }
174
- }
175
-
176
- return { available: false, method: null };
177
- } catch (e) {
178
- console.error("[Apple Pay] Error checking canMakePayment:", e);
179
-
180
- // If it's insecure context error, we can't use Apple Pay JS API
181
- if (e.message && e.message.includes('insecure')) {
182
- console.warn("[Apple Pay] Insecure context detected. Apple Pay requires HTTPS.");
183
- return { available: false, method: null, error: 'insecure_context' };
184
- }
185
-
186
- // For other errors, try Apple Pay JS API as fallback (only on HTTPS)
187
- if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
188
- try {
189
- const canMakePaymentsJS = ApplePaySession.canMakePayments();
190
- return { available: canMakePaymentsJS, method: 'applePayJS' };
191
- } catch (jsError) {
192
- console.error("[Apple Pay] Apple Pay JS API error:", jsError.message);
193
- return { available: false, method: null };
194
- }
195
- }
196
-
197
- return { available: false, method: null };
198
- }
199
- }
200
-
201
- // If canMakePayment is not available, check secure context again
202
- // Re-check secure context to ensure we have the latest state
203
- const isSecureContextFinal = typeof window !== 'undefined' && window.isSecureContext;
204
- const hostnameFinal = typeof window !== 'undefined' ? window.location.hostname : '';
205
- const isLocalhostFinal = hostnameFinal === 'localhost' || hostnameFinal === '127.0.0.1';
206
- const isSecureFinal = isSecureContextFinal || isLocalhostFinal;
207
-
208
- if (isSecureFinal) {
209
- console.log("[Apple Pay] canMakePayment not available, assuming support (secure context)");
210
- return { available: true, method: 'paymentRequest' };
211
- } else {
212
- console.warn("[Apple Pay] canMakePayment not available and insecure context");
213
- console.warn("[Apple Pay] Context details:", {
214
- isSecureContext: isSecureContextFinal,
215
- hostname: hostnameFinal,
216
- isLocalhost: isLocalhostFinal
217
- });
218
- return { available: false, method: null, error: 'insecure_context' };
219
- }
220
- } catch (error) {
221
- console.error("[Apple Pay] Error checking availability:", error);
222
-
223
- // Check if it's insecure context error
224
- if (error.message && error.message.includes('insecure')) {
225
- console.warn("[Apple Pay] Insecure context - Apple Pay requires HTTPS");
226
- return { available: false, method: null, error: 'insecure_context' };
227
- }
228
-
229
- // Fallback: Try Apple Pay JS API (only on HTTPS)
230
- // Re-check secure context
231
- const isSecureContextFallback = typeof window !== 'undefined' && window.isSecureContext;
232
- const hostnameFallback = typeof window !== 'undefined' ? window.location.hostname : '';
233
- const isLocalhostFallback = hostnameFallback === 'localhost' || hostnameFallback === '127.0.0.1';
234
- const isSecureFallback = isSecureContextFallback || isLocalhostFallback;
235
-
236
- if (typeof window !== 'undefined' && window.ApplePaySession && isSecureFallback) {
237
- try {
238
- const canMakePayments = ApplePaySession.canMakePayments();
239
- return { available: canMakePayments, method: 'applePayJS' };
240
- } catch (e) {
241
- console.error("[Apple Pay] Apple Pay JS API error:", e.message);
242
- if (e.message && e.message.includes('insecure')) {
243
- return { available: false, method: null, error: 'insecure_context' };
244
- }
245
- }
246
- }
247
-
248
- return { available: false, method: null };
249
- }
250
- };
251
-
252
- useEffect(() => {
253
- const scriptUrl = "https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js";
254
-
255
- console.log("[Apple Pay] Loading Apple Pay SDK script...");
256
-
257
- if (document.querySelector(`script[src="${scriptUrl}"]`)) {
258
- console.log("[Apple Pay] Script already loaded");
259
- // Script already loaded, check if it's ready
260
- if (typeof window !== 'undefined' && window.ApplePaySession) {
261
- initializeButton();
262
- } else {
263
- // Wait a bit for script to initialize
264
- setTimeout(() => initializeButton(), 500);
265
- }
266
- return;
267
- }
268
-
269
- const script = document.createElement("script");
270
- script.src = scriptUrl;
271
- script.crossOrigin = "anonymous";
272
- script.async = true;
273
-
274
- script.onload = () => {
275
- console.log("[Apple Pay] SDK script loaded successfully");
276
- setTimeout(() => {
277
- initializeButton();
278
- }, 500);
279
- };
280
-
281
- script.onerror = (error) => {
282
- console.error("[Apple Pay] Failed to load SDK script:", error);
283
- setIsLoading(false);
284
- setIsAvailable(false);
285
- setErrorMessage("Failed to load Apple Pay SDK. Please check Content Security Policy settings.");
286
-
287
- // Even if script fails, try to use Payment Request API
288
- console.log("[Apple Pay] Trying Payment Request API as fallback...");
289
- setTimeout(() => {
290
- initializeButton();
291
- }, 1000);
292
- };
293
-
294
- try {
295
- document.head.appendChild(script);
296
- console.log("[Apple Pay] Script element added to head");
297
- } catch (error) {
298
- console.error("[Apple Pay] Error adding script to head:", error);
299
- // Try to use Payment Request API without SDK
300
- setTimeout(() => {
301
- initializeButton();
302
- }, 1000);
303
- }
304
- }, []);
305
-
306
- const initializeButton = async () => {
307
- try {
308
- console.log("[Apple Pay] Initializing button...");
309
-
310
- const isSecure = typeof window !== 'undefined' &&
311
- (window.location.protocol === 'https:' ||
312
- window.location.hostname === 'localhost' ||
313
- window.location.hostname === '127.0.0.1');
314
-
315
- console.log("[Apple Pay] Secure context check:", {
316
- protocol: window.location?.protocol,
317
- hostname: window.location?.hostname,
318
- isSecure: isSecure
319
- });
320
-
321
- const isLocalhost = typeof window !== 'undefined' &&
322
- (window.location.hostname === 'localhost' ||
323
- window.location.hostname === '127.0.0.1');
324
-
325
- if (!isSecure && !isLocalhost && window.location?.protocol === 'http:') {
326
- const errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP. Localhost (http://localhost) is allowed for development.";
327
- setErrorMessage(errorMsg);
328
- setIsLoading(false);
329
- setIsAvailable(false);
330
- console.warn("[Apple Pay]", errorMsg);
331
- console.warn("[Apple Pay] Current URL:", window.location.href);
332
- return;
333
- }
334
-
335
- // Log context information
336
- console.log("[Apple Pay] Context info:", {
337
- protocol: window.location?.protocol,
338
- hostname: window.location?.hostname,
339
- isSecure: isSecure,
340
- isLocalhost: isLocalhost,
341
- fullUrl: window.location?.href
342
- });
343
-
344
- // Check availability
345
- const availability = await checkApplePayAvailability();
346
- console.log("[Apple Pay] Availability check result:", availability);
347
-
348
- setIsAvailable(availability.available);
349
-
350
- if (!availability.available) {
351
- let errorMsg = "Apple Pay is not available on this device or browser.";
352
-
353
- if (isLocalhost) {
354
- errorMsg = "Apple Pay is not available on localhost. Apple Pay requires a registered domain with HTTPS. " +
355
- "For testing, please use a production domain with HTTPS or test on a device with Safari (iOS/macOS). " +
356
- "You can still test the payment flow by using the 'Process Preauthorization' button without Apple Pay token.";
357
- } else if (availability.error === 'insecure_context') {
358
- errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP.";
359
- } else if (typeof window !== 'undefined' && window.PaymentRequest) {
360
- errorMsg += " Payment Request API is available but Apple Pay is not supported. " +
361
- "Please use Safari on iOS, macOS, or iPadOS, or Chrome/Edge on supported devices. " +
362
- "Note: Apple Pay requires a registered domain and cannot work on localhost.";
363
- } else if (typeof window !== 'undefined' && window.ApplePaySession) {
364
- errorMsg += " Apple Pay JS API is available but cannot make payments. " +
365
- "Please check your device settings and ensure you have a card added to Wallet.";
366
- } else {
367
- errorMsg += " Please use Safari on iOS, macOS, or iPadOS, or a browser that supports Payment Request API (Chrome, Edge, Safari).";
368
- }
369
-
370
- setErrorMessage(errorMsg);
371
- setIsLoading(false);
372
- console.warn("[Apple Pay] Not available:", errorMsg);
373
- return;
374
- }
375
-
376
- console.log("[Apple Pay] Button initialized successfully, method:", availability.method);
377
- setIsReady(true);
378
- setIsLoading(false);
379
- } catch (error) {
380
- console.error("[Apple Pay] Initialization error:", error);
381
- setIsLoading(false);
382
- setIsAvailable(false);
383
-
384
- // Check for insecure context error
385
- if (error.message && error.message.includes('insecure')) {
386
- setErrorMessage("Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP. Localhost is allowed for development.");
387
- } else {
388
- setErrorMessage(error.message || "Failed to initialize Apple Pay");
389
- }
390
-
391
- if (onError) {
392
- onError(error);
393
- }
394
- }
395
- };
396
-
397
- const handleApplePayClick = async () => {
398
- console.log("[Apple Pay] Button clicked, checking readiness...", {
399
- isReady,
400
- isAvailable,
401
- amount,
402
- currency,
403
- countryCode,
404
- protocol: window.location?.protocol,
405
- hostname: window.location?.hostname
406
- });
407
-
408
- // Check HTTPS requirement
409
- const isSecure = typeof window !== 'undefined' &&
410
- (window.location.protocol === 'https:' ||
411
- window.location.hostname === 'localhost' ||
412
- window.location.hostname === '127.0.0.1');
413
-
414
- if (!isSecure && window.location?.protocol === 'http:') {
415
- const errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS.";
416
- console.error("[Apple Pay]", errorMsg);
417
- if (onError) {
418
- onError(new Error(errorMsg));
419
- }
420
- return;
421
- }
422
-
423
- if (!isReady || !isAvailable) {
424
- console.error("[Apple Pay] Not ready or not available");
425
- if (onError) {
426
- onError(new Error("Apple Pay is not ready"));
427
- }
428
- return;
429
- }
430
-
431
- try {
432
- const amountValue = (parseFloat(amount) / 100).toFixed(2);
433
- const gatewayMerchantId = settings?.mid || settings?.portalid || '';
434
- const merchantId = merchantIdentifier || gatewayMerchantId || "merchant.com.payone.test";
435
-
436
- console.log("[Apple Pay] Starting payment request:", {
437
- amount: amountValue,
438
- currency,
439
- merchantId,
440
- countryCode,
441
- supportedNetworks,
442
- merchantCapabilities
443
- });
444
-
445
- // Define PaymentMethodData for Apple Pay
446
- const paymentMethodData = [{
447
- supportedMethods: "https://apple.com/apple-pay",
448
- data: {
449
- version: 3,
450
- merchantIdentifier: merchantId,
451
- merchantCapabilities: merchantCapabilities,
452
- supportedNetworks: supportedNetworks,
453
- countryCode: countryCode,
454
- currencyCode: currency
455
- }
456
- }];
457
-
458
- // Define PaymentDetails
459
- const paymentDetails = {
460
- total: {
461
- label: settings?.merchantName || "Demo Payment",
462
- amount: {
463
- value: amountValue,
464
- currency: currency
465
- }
466
- }
467
- };
468
-
469
- // Define PaymentOptions
470
- const paymentOptions = {
471
- requestPayerName: requestPayerName,
472
- requestBillingAddress: requestBillingAddress,
473
- requestPayerEmail: requestPayerEmail,
474
- requestPayerPhone: requestPayerPhone,
475
- requestShipping: requestShipping,
476
- shippingType: shippingType
477
- };
478
-
479
- // Create PaymentRequest
480
- const request = new PaymentRequest(paymentMethodData, paymentDetails, paymentOptions);
481
-
482
- // Handle merchant validation
483
- request.onmerchantvalidation = async (event) => {
484
- console.log("[Apple Pay] Merchant validation requested:", {
485
- validationURL: event.validationURL,
486
- domain: window.location.hostname
487
- });
488
-
489
- try {
490
- // Call backend to validate merchant with Payone
491
- const merchantSessionPromise = validateMerchantWithPayone(event.validationURL, {
492
- mid: gatewayMerchantId,
493
- portalid: settings?.portalid,
494
- domain: window.location.hostname,
495
- displayName: settings?.merchantName || "Test Store"
496
- });
497
-
498
- merchantSessionPromise.then(session => {
499
- console.log("[Apple Pay] ========== MERCHANT SESSION RECEIVED ==========");
500
- console.log("[Apple Pay] Full Merchant Session (JSON):", JSON.stringify(session, null, 2));
501
- console.log("[Apple Pay] Session Type:", typeof session);
502
- console.log("[Apple Pay] Is Object:", session instanceof Object);
503
- console.log("[Apple Pay] Session Keys:", Object.keys(session || {}));
504
- console.log("[Apple Pay] Session Keys Count:", Object.keys(session || {}).length);
505
- console.log("[Apple Pay] Has Merchant Identifier:", !!session?.merchantIdentifier);
506
- console.log("[Apple Pay] Merchant Identifier:", session?.merchantIdentifier);
507
- console.log("[Apple Pay] Has Merchant Session Identifier:", !!session?.merchantSessionIdentifier);
508
- console.log("[Apple Pay] Merchant Session Identifier:", session?.merchantSessionIdentifier);
509
- console.log("[Apple Pay] Domain Name:", session?.domainName);
510
- console.log("[Apple Pay] Display Name:", session?.displayName);
511
- console.log("[Apple Pay] Epoch Timestamp:", session?.epochTimestamp);
512
- console.log("[Apple Pay] Expires At:", session?.expiresAt);
513
- console.log("[Apple Pay] Nonce:", session?.nonce);
514
-
515
- // Log all properties
516
- console.log("[Apple Pay] All Session Properties:");
517
- if (session && typeof session === 'object') {
518
- for (const [key, value] of Object.entries(session)) {
519
- if (typeof value === 'string' && value.length > 200) {
520
- console.log(`[Apple Pay] ${key}:`, value.substring(0, 200) + "... (truncated, length: " + value.length + ")");
521
- } else {
522
- console.log(`[Apple Pay] ${key}:`, value);
523
- }
524
- }
525
- }
526
- console.log("[Apple Pay] ==========================================");
527
-
528
- // Validate merchant session
529
- if (!session || (!session.merchantIdentifier && !session.merchantSessionIdentifier)) {
530
- console.error("[Apple Pay] Invalid merchant session - missing merchantIdentifier");
531
- console.error("[Apple Pay] Session object:", JSON.stringify(session, null, 2));
532
- throw new Error("Invalid merchant session: missing merchantIdentifier");
533
- }
534
- }).catch(err => {
535
- console.error("[Apple Pay] Merchant session error:", err);
536
- // Re-throw so Payment Request API knows validation failed
537
- throw err;
538
- });
539
-
540
- // Complete with the merchant session promise
541
- // If the promise rejects, Payment Request API will close the dialog
542
- // This is expected behavior - we cannot proceed without a valid merchant session
543
- event.complete(merchantSessionPromise);
544
- } catch (error) {
545
- console.error("[Apple Pay] Merchant validation error:", {
546
- message: error.message,
547
- stack: error.stack,
548
- response: error.response
549
- });
550
-
551
- // Call onError to notify the user
552
- if (typeof onError === 'function') {
553
- onError(new Error(`Apple Pay merchant validation failed: ${error.message}. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay).`));
554
- }
555
-
556
- // Complete with a rejected promise
557
- // This will cause Apple Pay to close the dialog, which is expected behavior
558
- // We cannot proceed without a valid merchant session from Payone
559
- event.complete(Promise.reject(error));
560
- }
561
- };
562
-
563
- // Handle payment method change
564
- request.onpaymentmethodchange = (event) => {
565
- // Update payment details if needed based on payment method
566
- const paymentDetailsUpdate = {
567
- total: paymentDetails.total
568
- };
569
- event.updateWith(paymentDetailsUpdate);
570
- };
571
-
572
- // Handle shipping option change
573
- request.onshippingoptionchange = (event) => {
574
- const paymentDetailsUpdate = {
575
- total: paymentDetails.total
576
- };
577
- event.updateWith(paymentDetailsUpdate);
578
- };
579
-
580
- // Handle shipping address change
581
- request.onshippingaddresschange = (event) => {
582
- const paymentDetailsUpdate = {};
583
- event.updateWith(paymentDetailsUpdate);
584
- };
585
-
586
- // Show payment sheet and get response
587
- console.log("[Apple Pay] Showing payment sheet...");
588
- let response;
589
- try {
590
- response = await request.show();
591
- console.log("[Apple Pay] Payment sheet shown successfully");
592
- } catch (error) {
593
- console.error("[Apple Pay] Error showing payment sheet:", {
594
- name: error.name,
595
- message: error.message,
596
- stack: error.stack
597
- });
598
-
599
- // Check if error is due to cancellation (user cancelled)
600
- // Payment Request API throws "AbortError" when user cancels
601
- if (error.name === 'AbortError' ||
602
- (error.message && (
603
- error.message.includes('Cancelled') ||
604
- error.message.includes('cancel') ||
605
- error.message.includes('abort')
606
- ))) {
607
- console.log("[Apple Pay] User cancelled the payment");
608
- // Don't call onError for user cancellation
609
- return;
610
- }
611
-
612
- // If it's a merchant validation error, log it specifically
613
- if (error.message && (
614
- error.message.includes('merchant') ||
615
- error.message.includes('validation') ||
616
- error.message.includes('identifier')
617
- )) {
618
- console.error("[Apple Pay] Merchant validation failed - this may cause the dialog to close");
619
- if (typeof onError === 'function') {
620
- onError(new Error("Merchant validation failed. Please check your Apple Pay configuration and merchant identifier in Payone settings."));
621
- }
622
- } else {
623
- // For other errors, call onError
624
- if (typeof onError === 'function') {
625
- onError(error);
626
- }
627
- }
628
- return;
629
- }
630
-
631
- console.log("[Apple Pay] Payment response received:", {
632
- hasDetails: !!response.details,
633
- payerName: response.payerName,
634
- shippingAddress: !!response.shippingAddress
635
- });
636
-
637
- // Extract payment token
638
- const paymentToken = response.details?.paymentToken || response.details?.token;
639
-
640
- if (!paymentToken) {
641
- console.error("[Apple Pay] Payment token is missing from response");
642
- try {
643
- await response.complete("fail");
644
- } catch (completeError) {
645
- console.error("[Apple Pay] Error completing payment with fail:", completeError);
646
- }
647
- if (onError) {
648
- onError(new Error("Apple Pay token is missing"));
649
- }
650
- return;
651
- }
652
-
653
- console.log("[Apple Pay] Payment token received:", {
654
- hasToken: !!paymentToken,
655
- tokenType: typeof paymentToken
656
- });
657
-
658
- // Convert token to base64 string for Payone
659
- let tokenString;
660
- try {
661
- if (typeof paymentToken === 'string') {
662
- tokenString = paymentToken;
663
- } else {
664
- tokenString = JSON.stringify(paymentToken);
665
- }
666
- // Base64 encode for Payone
667
- tokenString = btoa(unescape(encodeURIComponent(tokenString)));
668
- } catch (e) {
669
- console.error("Token encoding error:", e);
670
- tokenString = btoa(unescape(encodeURIComponent(JSON.stringify(paymentToken))));
671
- }
672
-
673
- // Call the callback with the token BEFORE completing payment
674
- // This ensures the token is saved before the dialog closes
675
- console.log("[Apple Pay] Sending token to callback");
676
- let callbackSuccess = true;
677
- let callbackError = null;
678
-
679
- if (onTokenReceived) {
680
- try {
681
- // Call the callback to save the token
682
- // The callback should set the token in state and return success immediately
683
- // It should NOT process the payment yet - that will happen when user clicks the button
684
- const callbackResult = onTokenReceived(tokenString, {
685
- paymentToken: paymentToken,
686
- billingContact: response.payerName || response.details?.billingContact,
687
- shippingContact: response.shippingAddress || response.details?.shippingAddress,
688
- shippingOption: response.shippingOption || response.details?.shippingOption
689
- });
690
-
691
- // If callback returns a promise, wait for it to resolve or reject
692
- if (callbackResult && typeof callbackResult.then === 'function') {
693
- try {
694
- const result = await callbackResult;
695
- console.log("[Apple Pay] Token callback completed successfully:", result);
696
- // Check if result indicates success
697
- if (result && result.success === false) {
698
- callbackSuccess = false;
699
- callbackError = new Error(result.message || "Token callback returned failure");
700
- }
701
- } catch (error) {
702
- console.error("[Apple Pay] Token callback promise rejected:", error);
703
- callbackSuccess = false;
704
- callbackError = error;
705
- }
706
- } else if (callbackResult === false) {
707
- // If callback explicitly returns false, treat as failure
708
- callbackSuccess = false;
709
- console.warn("[Apple Pay] Token callback returned false");
710
- } else {
711
- // If callback returns a value (not a promise), assume success
712
- console.log("[Apple Pay] Token callback returned synchronously");
713
- }
714
- } catch (error) {
715
- console.error("[Apple Pay] Error in token callback:", error);
716
- callbackSuccess = false;
717
- callbackError = error;
718
- }
719
- } else {
720
- console.warn("[Apple Pay] No onTokenReceived callback provided");
721
- // If no callback, we should still complete the payment
722
- // But mark as success since we can't determine the result
723
- callbackSuccess = true;
724
- }
725
-
726
- // Complete payment with success or fail based on callback result
727
- // IMPORTANT: Only call complete() after the callback has fully finished
728
- console.log("[Apple Pay] Completing payment with status:", callbackSuccess ? "success" : "fail");
729
-
730
- try {
731
- // Use a small delay to ensure state updates are complete
732
- // This prevents the dialog from closing before the token is saved
733
- await new Promise(resolve => setTimeout(resolve, 200));
734
-
735
- const completionStatus = callbackSuccess ? "success" : "fail";
736
- await response.complete(completionStatus);
737
- console.log("[Apple Pay] Payment completed with status:", completionStatus);
738
-
739
- // If there was an error, notify the error handler
740
- if (!callbackSuccess && callbackError && onError) {
741
- onError(callbackError);
742
- }
743
- } catch (completeError) {
744
- console.error("[Apple Pay] Error completing payment:", completeError);
745
- // Try to complete with fail status if there's an error
746
- try {
747
- await response.complete("fail");
748
- } catch (finalError) {
749
- console.error("[Apple Pay] Failed to complete payment even with fail status:", finalError);
750
- }
751
- // Only call onError if it's defined
752
- if (typeof onError === 'function') {
753
- onError(completeError);
754
- }
755
- }
756
-
757
- } catch (error) {
758
- console.error("[Apple Pay] Payment error:", {
759
- message: error.message,
760
- stack: error.stack,
761
- name: error.name
762
- });
763
- // Check if error is due to cancellation (user cancelled)
764
- if (error.message && error.message.includes('Cancelled')) {
765
- console.log("[Apple Pay] User cancelled the payment");
766
- // Don't call onError for user cancellation
767
- return;
768
- }
769
- // Only call onError if it's defined and it's not a cancellation
770
- if (typeof onError === 'function') {
771
- onError(error);
772
- }
773
- }
774
- };
775
-
776
- // Validate merchant with Payone
777
- const validateMerchantWithPayone = async (validationURL, config) => {
778
- console.log("[Apple Pay] Validating merchant with Payone:", {
779
- validationURL,
780
- config: {
781
- mid: config.mid,
782
- portalid: config.portalid,
783
- domain: config.domain,
784
- displayName: config.displayName
785
- }
786
- });
787
-
788
- try {
789
- console.log("[Apple Pay] Making validation request using Strapi helper...");
790
-
791
- // Use Strapi helper-plugin's request function which automatically handles authentication
792
- // This uses the admin API route which requires admin authentication
793
- const merchantSession = await request(`/${pluginId}/validate-apple-pay-merchant`, {
794
- method: 'POST',
795
- body: {
796
- validationURL,
797
- ...config
798
- }
799
- });
800
-
801
- console.log("[Apple Pay] ========== BACKEND RESPONSE START ==========");
802
- console.log("[Apple Pay] Full Backend Response:", JSON.stringify(merchantSession, null, 2));
803
- console.log("[Apple Pay] Response Type:", typeof merchantSession);
804
- console.log("[Apple Pay] Has Data:", !!merchantSession.data);
805
- console.log("[Apple Pay] Has Error:", !!merchantSession.error);
806
-
807
- if (merchantSession.data) {
808
- console.log("[Apple Pay] Data Object:", merchantSession.data);
809
- console.log("[Apple Pay] Data Type:", typeof merchantSession.data);
810
- console.log("[Apple Pay] Data Keys:", Object.keys(merchantSession.data));
811
- console.log("[Apple Pay] Data Keys Count:", Object.keys(merchantSession.data).length);
812
- console.log("[Apple Pay] Merchant Identifier:", merchantSession.data.merchantIdentifier);
813
- console.log("[Apple Pay] Domain Name:", merchantSession.data.domainName);
814
- console.log("[Apple Pay] Display Name:", merchantSession.data.displayName);
815
- console.log("[Apple Pay] Epoch Timestamp:", merchantSession.data.epochTimestamp);
816
- console.log("[Apple Pay] Expires At:", merchantSession.data.expiresAt);
817
- }
818
-
819
- if (merchantSession.error) {
820
- console.log("[Apple Pay] Error Object:", merchantSession.error);
821
- console.log("[Apple Pay] Error Message:", merchantSession.error.message);
822
- console.log("[Apple Pay] Error Details:", merchantSession.error.details);
823
- }
824
-
825
- console.log("[Apple Pay] ========== BACKEND RESPONSE END ==========");
826
-
827
- // Check if there's an error in the response
828
- if (merchantSession.error) {
829
- console.error("[Apple Pay] Backend returned error:", merchantSession.error);
830
- throw new Error(merchantSession.error.message || "Apple Pay merchant validation failed");
831
- }
832
-
833
- // Validate merchant session
834
- const session = merchantSession.data || merchantSession;
835
-
836
- // Check if session is empty object
837
- if (!session || Object.keys(session).length === 0) {
838
- console.error("[Apple Pay] Empty merchant session received from backend");
839
- console.error("[Apple Pay] Full response:", JSON.stringify(merchantSession, null, 2));
840
- throw new Error("Empty merchant session received. This usually means Payone did not return a valid merchant session. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay).");
841
- }
842
-
843
- if (!session.merchantIdentifier && !session.merchantSessionIdentifier) {
844
- console.error("[Apple Pay] Invalid merchant session - missing merchantIdentifier");
845
- console.error("[Apple Pay] Session object:", JSON.stringify(session, null, 2));
846
- console.error("[Apple Pay] Full response:", JSON.stringify(merchantSession, null, 2));
847
- throw new Error("Invalid merchant session: missing merchantIdentifier. Please check your Payone Apple Pay configuration in PMI (CONFIGURATION → PAYMENT PORTALS → [Your Portal] → Apple Pay). The merchant session must come from Payone after successful Apple Pay onboarding.");
848
- }
849
-
850
- return session;
851
- } catch (error) {
852
- console.error("[Apple Pay] Merchant validation error:", {
853
- message: error.message,
854
- status: error.response?.status,
855
- statusText: error.response?.statusText,
856
- data: error.response?.data,
857
- stack: error.stack
858
- });
859
-
860
- // Log specific error details
861
- if (error.response?.status === 403) {
862
- console.error("[Apple Pay] 403 Forbidden - Authentication failed. Make sure you are logged in as admin.");
863
- } else if (error.response?.status === 401) {
864
- console.error("[Apple Pay] 401 Unauthorized - Please log in again.");
865
- } else if (error.response?.status >= 500) {
866
- console.error("[Apple Pay] Server error - Check server logs for details.");
867
- }
868
-
869
- // If validation fails, we cannot proceed
870
- // Apple Pay requires a valid merchant session from Payone
871
- console.error("[Apple Pay] Merchant validation failed - cannot proceed without valid session");
872
- throw error;
873
- }
874
- };
875
-
876
- return (
877
- <Box width="100%">
878
- <Flex direction="column" gap={3} alignItems="stretch">
879
- {isLoading && (
880
- <Typography variant="pi" textColor="neutral600" style={{ textAlign: "left" }}>
881
- Checking Apple Pay availability...
882
- </Typography>
883
- )}
884
- {!isLoading && !isAvailable && (
885
- <Box style={{ width: "100%", display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "8px" }}>
886
- {errorMessage && (
887
- <Typography variant="sigma" textColor="neutral500" style={{ textAlign: "left", fontSize: "12px" }}>
888
- {errorMessage}
889
- </Typography>
890
- )}
891
- </Box>
892
- )}
893
- {!isLoading && isAvailable && (
894
- <>
895
- <Box ref={buttonContainerRef} style={{ minHeight: "40px", width: "100%", display: "flex", justifyContent: "flex-start" }}>
896
- {typeof window !== 'undefined' && window.customElements && window.customElements.get('apple-pay-button') ? (
897
- <apple-pay-button
898
- buttonstyle={buttonStyle}
899
- type={buttonType}
900
- locale="en-US"
901
- onClick={handleApplePayClick}
902
- style={{
903
- width: "200px",
904
- height: "40px",
905
- cursor: isReady ? "pointer" : "not-allowed",
906
- opacity: isReady ? 1 : 0.5
907
- }}
908
- />
909
- ) : (
910
- <button
911
- type="button"
912
- onClick={handleApplePayClick}
913
- disabled={!isReady}
914
- style={{
915
- appearance: "none",
916
- WebkitAppearance: "-apple-pay-button",
917
- ApplePayButtonType: buttonType,
918
- ApplePayButtonStyle: buttonStyle,
919
- height: "40px",
920
- width: "200px",
921
- border: "none",
922
- borderRadius: "4px",
923
- cursor: isReady ? "pointer" : "not-allowed",
924
- opacity: isReady ? 1 : 0.5,
925
- backgroundColor: buttonStyle === "black" ? "#000" : buttonStyle === "white" ? "#fff" : "transparent",
926
- color: buttonStyle === "black" ? "#fff" : "#000",
927
- borderWidth: buttonStyle === "white-outline" ? "1px" : "0",
928
- borderStyle: buttonStyle === "white-outline" ? "solid" : "none",
929
- borderColor: buttonStyle === "white-outline" ? "#000" : "transparent",
930
- fontSize: "16px",
931
- fontWeight: "400",
932
- fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
933
- display: "flex",
934
- alignItems: "center",
935
- justifyContent: "center"
936
- }}
937
- className="apple-pay-button-custom"
938
- >
939
- {buttonType === "pay" ? "Pay" : buttonType === "buy" ? "Buy" : buttonType === "donate" ? "Donate" : "Pay with Apple Pay"}
940
- </button>
941
- )}
942
- </Box>
943
- </>
944
- )}
945
- </Flex>
946
- </Box>
947
- );
948
- };
949
-
950
- export default ApplePayButton;