strapi-plugin-payone-provider 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,704 @@
1
+ import React, { useEffect, useRef, useState } from "react";
2
+ import { Box, Flex, Typography } from "@strapi/design-system";
3
+ import { DEFAULT_APPLE_PAY_CONFIG } from "../../utils/applePayConstants";
4
+
5
+ /**
6
+ * Apple Pay Button Component using Payment Request API
7
+ * Based on Apple Pay documentation:
8
+ * https://developer.apple.com/documentation/applepayontheweb/creating-an-apple-pay-session
9
+ * https://developer.apple.com/documentation/applepayontheweb/displaying-apple-pay-buttons-using-css
10
+ *
11
+ * Supports Payment Request API (works in Chrome, Edge, Safari, etc.)
12
+ * and falls back to Apple Pay JS API if needed
13
+ */
14
+ const ApplePayButton = ({
15
+ amount,
16
+ currency = "EUR",
17
+ countryCode = "DE",
18
+ merchantCapabilities = ["supports3DS"],
19
+ supportedNetworks = ["visa", "masterCard", "girocard"],
20
+ buttonStyle = "black",
21
+ buttonType = "pay",
22
+ requestPayerName = false,
23
+ requestBillingAddress = false,
24
+ requestPayerEmail = false,
25
+ requestPayerPhone = false,
26
+ requestShipping = false,
27
+ shippingType = "shipping",
28
+ merchantIdentifier = null,
29
+ onTokenReceived,
30
+ onError,
31
+ settings
32
+ }) => {
33
+ const [isReady, setIsReady] = useState(false);
34
+ const [isLoading, setIsLoading] = useState(true);
35
+ const [isAvailable, setIsAvailable] = useState(false);
36
+ const [errorMessage, setErrorMessage] = useState(null);
37
+ const buttonContainerRef = useRef(null);
38
+ const paymentRequestRef = useRef(null);
39
+
40
+ const checkApplePayAvailability = async () => {
41
+ try {
42
+ console.log("[Apple Pay] Checking availability...");
43
+
44
+ // Check if we're on HTTPS (required for Apple Pay JS API)
45
+ const isSecure = typeof window !== 'undefined' &&
46
+ (window.location.protocol === 'https:' ||
47
+ window.location.hostname === 'localhost' ||
48
+ window.location.hostname === '127.0.0.1');
49
+
50
+ console.log("[Apple Pay] Secure context:", isSecure, "Protocol:", window.location?.protocol);
51
+
52
+ // First, check if Payment Request API is available
53
+ // Payment Request API works on HTTP too, but Apple Pay JS API requires HTTPS
54
+ if (typeof window === 'undefined' || !window.PaymentRequest) {
55
+ console.log("[Apple Pay] Payment Request API not available");
56
+
57
+ // Fallback: Check Apple Pay JS API (for Safari, requires HTTPS)
58
+ if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
59
+ try {
60
+ const canMakePayments = ApplePaySession.canMakePayments();
61
+ console.log("[Apple Pay] Apple Pay JS API available:", canMakePayments);
62
+ return { available: canMakePayments, method: 'applePayJS' };
63
+ } catch (error) {
64
+ console.error("[Apple Pay] Apple Pay JS API error (likely insecure context):", error.message);
65
+ return { available: false, method: null, error: 'insecure_context' };
66
+ }
67
+ }
68
+
69
+ if (!isSecure && typeof window !== 'undefined' && window.ApplePaySession) {
70
+ console.warn("[Apple Pay] Apple Pay JS API requires HTTPS. Using Payment Request API fallback.");
71
+ }
72
+
73
+ console.log("[Apple Pay] No Apple Pay support found");
74
+ return { available: false, method: null };
75
+ }
76
+
77
+ console.log("[Apple Pay] Payment Request API available, checking Apple Pay support...");
78
+
79
+ // Check if Apple Pay payment method is supported
80
+ const applePayMethod = {
81
+ supportedMethods: "https://apple.com/apple-pay",
82
+ data: {
83
+ version: 3,
84
+ merchantIdentifier: merchantIdentifier || settings?.merchantIdentifier || settings?.mid || "merchant.com.payone.test",
85
+ merchantCapabilities: merchantCapabilities,
86
+ supportedNetworks: supportedNetworks,
87
+ countryCode: countryCode
88
+ }
89
+ };
90
+
91
+ // Create a test payment request
92
+ // Payment Request API works on HTTP too, but Apple Pay may require HTTPS
93
+ let testRequest;
94
+ try {
95
+ testRequest = new PaymentRequest(
96
+ [applePayMethod],
97
+ {
98
+ total: {
99
+ label: "Test",
100
+ amount: { value: "0.01", currency: currency }
101
+ }
102
+ },
103
+ {
104
+ requestPayerName: false,
105
+ requestBillingAddress: false,
106
+ requestPayerEmail: false,
107
+ requestPayerPhone: false,
108
+ requestShipping: false
109
+ }
110
+ );
111
+ } catch (e) {
112
+ console.error("[Apple Pay] Error creating PaymentRequest:", e);
113
+ // If PaymentRequest creation fails, it might be due to insecure context
114
+ if (e.message && e.message.includes('insecure')) {
115
+ return { available: false, method: null, error: 'insecure_context' };
116
+ }
117
+ return { available: false, method: null };
118
+ }
119
+
120
+ // Check if can make payment
121
+ if (testRequest.canMakePayment) {
122
+ try {
123
+ const canPay = await testRequest.canMakePayment();
124
+ console.log("[Apple Pay] canMakePayment result:", canPay);
125
+
126
+ if (canPay) {
127
+ return { available: true, method: 'paymentRequest' };
128
+ }
129
+
130
+ // If PaymentRequest says no, try Apple Pay JS API as fallback (only on HTTPS)
131
+ if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
132
+ try {
133
+ const canMakePaymentsJS = ApplePaySession.canMakePayments();
134
+ console.log("[Apple Pay] Fallback to Apple Pay JS API:", canMakePaymentsJS);
135
+ return { available: canMakePaymentsJS, method: 'applePayJS' };
136
+ } catch (e) {
137
+ console.error("[Apple Pay] Apple Pay JS API error:", e.message);
138
+ // If it's insecure context error, Payment Request API might still work
139
+ if (e.message && e.message.includes('insecure')) {
140
+ // Payment Request API might work even on HTTP
141
+ return { available: false, method: null, error: 'insecure_context' };
142
+ }
143
+ }
144
+ }
145
+
146
+ return { available: false, method: null };
147
+ } catch (e) {
148
+ console.error("[Apple Pay] Error checking canMakePayment:", e);
149
+
150
+ // If it's insecure context error, we can't use Apple Pay JS API
151
+ if (e.message && e.message.includes('insecure')) {
152
+ console.warn("[Apple Pay] Insecure context detected. Apple Pay requires HTTPS.");
153
+ return { available: false, method: null, error: 'insecure_context' };
154
+ }
155
+
156
+ // For other errors, try Apple Pay JS API as fallback (only on HTTPS)
157
+ if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
158
+ try {
159
+ const canMakePaymentsJS = ApplePaySession.canMakePayments();
160
+ return { available: canMakePaymentsJS, method: 'applePayJS' };
161
+ } catch (jsError) {
162
+ console.error("[Apple Pay] Apple Pay JS API error:", jsError.message);
163
+ return { available: false, method: null };
164
+ }
165
+ }
166
+
167
+ return { available: false, method: null };
168
+ }
169
+ }
170
+
171
+ // If canMakePayment is not available, assume it's available (for older browsers)
172
+ // But only if we're in a secure context
173
+ // Reuse isSecure from line 47
174
+
175
+ if (isSecure) {
176
+ console.log("[Apple Pay] canMakePayment not available, assuming support (secure context)");
177
+ return { available: true, method: 'paymentRequest' };
178
+ } else {
179
+ console.warn("[Apple Pay] canMakePayment not available and insecure context");
180
+ return { available: false, method: null, error: 'insecure_context' };
181
+ }
182
+ } catch (error) {
183
+ console.error("[Apple Pay] Error checking availability:", error);
184
+
185
+ // Check if it's insecure context error
186
+ if (error.message && error.message.includes('insecure')) {
187
+ console.warn("[Apple Pay] Insecure context - Apple Pay requires HTTPS");
188
+ return { available: false, method: null, error: 'insecure_context' };
189
+ }
190
+
191
+ // Fallback: Try Apple Pay JS API (only on HTTPS)
192
+ // Reuse isSecure from line 47
193
+
194
+ if (typeof window !== 'undefined' && window.ApplePaySession && isSecure) {
195
+ try {
196
+ const canMakePayments = ApplePaySession.canMakePayments();
197
+ return { available: canMakePayments, method: 'applePayJS' };
198
+ } catch (e) {
199
+ console.error("[Apple Pay] Apple Pay JS API error:", e.message);
200
+ if (e.message && e.message.includes('insecure')) {
201
+ return { available: false, method: null, error: 'insecure_context' };
202
+ }
203
+ }
204
+ }
205
+
206
+ return { available: false, method: null };
207
+ }
208
+ };
209
+
210
+ useEffect(() => {
211
+ const scriptUrl = "https://applepay.cdn-apple.com/jsapi/1.latest/apple-pay-sdk.js";
212
+
213
+ console.log("[Apple Pay] Loading Apple Pay SDK script...");
214
+
215
+ if (document.querySelector(`script[src="${scriptUrl}"]`)) {
216
+ console.log("[Apple Pay] Script already loaded");
217
+ // Script already loaded, check if it's ready
218
+ if (typeof window !== 'undefined' && window.ApplePaySession) {
219
+ initializeButton();
220
+ } else {
221
+ // Wait a bit for script to initialize
222
+ setTimeout(() => initializeButton(), 500);
223
+ }
224
+ return;
225
+ }
226
+
227
+ const script = document.createElement("script");
228
+ script.src = scriptUrl;
229
+ script.crossOrigin = "anonymous";
230
+ script.async = true;
231
+
232
+ script.onload = () => {
233
+ console.log("[Apple Pay] SDK script loaded successfully");
234
+ setTimeout(() => {
235
+ initializeButton();
236
+ }, 500);
237
+ };
238
+
239
+ script.onerror = (error) => {
240
+ console.error("[Apple Pay] Failed to load SDK script:", error);
241
+ setIsLoading(false);
242
+ setIsAvailable(false);
243
+ setErrorMessage("Failed to load Apple Pay SDK. Please check Content Security Policy settings.");
244
+
245
+ // Even if script fails, try to use Payment Request API
246
+ console.log("[Apple Pay] Trying Payment Request API as fallback...");
247
+ setTimeout(() => {
248
+ initializeButton();
249
+ }, 1000);
250
+ };
251
+
252
+ try {
253
+ document.head.appendChild(script);
254
+ console.log("[Apple Pay] Script element added to head");
255
+ } catch (error) {
256
+ console.error("[Apple Pay] Error adding script to head:", error);
257
+ // Try to use Payment Request API without SDK
258
+ setTimeout(() => {
259
+ initializeButton();
260
+ }, 1000);
261
+ }
262
+ }, []);
263
+
264
+ const initializeButton = async () => {
265
+ try {
266
+ console.log("[Apple Pay] Initializing button...");
267
+
268
+ const isSecure = typeof window !== 'undefined' &&
269
+ (window.location.protocol === 'https:' ||
270
+ window.location.hostname === 'localhost' ||
271
+ window.location.hostname === '127.0.0.1');
272
+
273
+ console.log("[Apple Pay] Secure context check:", {
274
+ protocol: window.location?.protocol,
275
+ hostname: window.location?.hostname,
276
+ isSecure: isSecure
277
+ });
278
+
279
+ const isLocalhost = typeof window !== 'undefined' &&
280
+ (window.location.hostname === 'localhost' ||
281
+ window.location.hostname === '127.0.0.1');
282
+
283
+ if (!isSecure && !isLocalhost && window.location?.protocol === 'http:') {
284
+ 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.";
285
+ setErrorMessage(errorMsg);
286
+ setIsLoading(false);
287
+ setIsAvailable(false);
288
+ console.warn("[Apple Pay]", errorMsg);
289
+ console.warn("[Apple Pay] Current URL:", window.location.href);
290
+ return;
291
+ }
292
+
293
+ // Log context information
294
+ console.log("[Apple Pay] Context info:", {
295
+ protocol: window.location?.protocol,
296
+ hostname: window.location?.hostname,
297
+ isSecure: isSecure,
298
+ isLocalhost: isLocalhost,
299
+ fullUrl: window.location?.href
300
+ });
301
+
302
+ // Check availability
303
+ const availability = await checkApplePayAvailability();
304
+ console.log("[Apple Pay] Availability check result:", availability);
305
+
306
+ setIsAvailable(availability.available);
307
+
308
+ if (!availability.available) {
309
+ let errorMsg = "Apple Pay is not available on this device or browser.";
310
+
311
+ if (isLocalhost) {
312
+ errorMsg = "Apple Pay is not available on localhost. Apple Pay requires a registered domain with HTTPS. " +
313
+ "For testing, please use a production domain with HTTPS or test on a device with Safari (iOS/macOS). " +
314
+ "You can still test the payment flow by using the 'Process Preauthorization' button without Apple Pay token.";
315
+ } else if (availability.error === 'insecure_context') {
316
+ errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP.";
317
+ } else if (typeof window !== 'undefined' && window.PaymentRequest) {
318
+ errorMsg += " Payment Request API is available but Apple Pay is not supported. " +
319
+ "Please use Safari on iOS, macOS, or iPadOS, or Chrome/Edge on supported devices. " +
320
+ "Note: Apple Pay requires a registered domain and cannot work on localhost.";
321
+ } else if (typeof window !== 'undefined' && window.ApplePaySession) {
322
+ errorMsg += " Apple Pay JS API is available but cannot make payments. " +
323
+ "Please check your device settings and ensure you have a card added to Wallet.";
324
+ } else {
325
+ errorMsg += " Please use Safari on iOS, macOS, or iPadOS, or a browser that supports Payment Request API (Chrome, Edge, Safari).";
326
+ }
327
+
328
+ setErrorMessage(errorMsg);
329
+ setIsLoading(false);
330
+ console.warn("[Apple Pay] Not available:", errorMsg);
331
+ return;
332
+ }
333
+
334
+ console.log("[Apple Pay] Button initialized successfully, method:", availability.method);
335
+ setIsReady(true);
336
+ setIsLoading(false);
337
+ } catch (error) {
338
+ console.error("[Apple Pay] Initialization error:", error);
339
+ setIsLoading(false);
340
+ setIsAvailable(false);
341
+
342
+ // Check for insecure context error
343
+ if (error.message && error.message.includes('insecure')) {
344
+ setErrorMessage("Apple Pay requires HTTPS. Please access this page via HTTPS (https://yourdomain.com) instead of HTTP. Localhost is allowed for development.");
345
+ } else {
346
+ setErrorMessage(error.message || "Failed to initialize Apple Pay");
347
+ }
348
+
349
+ if (onError) {
350
+ onError(error);
351
+ }
352
+ }
353
+ };
354
+
355
+ const handleApplePayClick = async () => {
356
+ console.log("[Apple Pay] Button clicked, checking readiness...", {
357
+ isReady,
358
+ isAvailable,
359
+ amount,
360
+ currency,
361
+ countryCode,
362
+ protocol: window.location?.protocol,
363
+ hostname: window.location?.hostname
364
+ });
365
+
366
+ // Check HTTPS requirement
367
+ const isSecure = typeof window !== 'undefined' &&
368
+ (window.location.protocol === 'https:' ||
369
+ window.location.hostname === 'localhost' ||
370
+ window.location.hostname === '127.0.0.1');
371
+
372
+ if (!isSecure && window.location?.protocol === 'http:') {
373
+ const errorMsg = "Apple Pay requires HTTPS. Please access this page via HTTPS.";
374
+ console.error("[Apple Pay]", errorMsg);
375
+ if (onError) {
376
+ onError(new Error(errorMsg));
377
+ }
378
+ return;
379
+ }
380
+
381
+ if (!isReady || !isAvailable) {
382
+ console.error("[Apple Pay] Not ready or not available");
383
+ if (onError) {
384
+ onError(new Error("Apple Pay is not ready"));
385
+ }
386
+ return;
387
+ }
388
+
389
+ try {
390
+ const amountValue = (parseFloat(amount) / 100).toFixed(2);
391
+ const gatewayMerchantId = settings?.mid || settings?.portalid || '';
392
+ const merchantId = merchantIdentifier || gatewayMerchantId || "merchant.com.payone.test";
393
+
394
+ console.log("[Apple Pay] Starting payment request:", {
395
+ amount: amountValue,
396
+ currency,
397
+ merchantId,
398
+ countryCode,
399
+ supportedNetworks,
400
+ merchantCapabilities
401
+ });
402
+
403
+ // Define PaymentMethodData for Apple Pay
404
+ const paymentMethodData = [{
405
+ supportedMethods: "https://apple.com/apple-pay",
406
+ data: {
407
+ version: 3,
408
+ merchantIdentifier: merchantId,
409
+ merchantCapabilities: merchantCapabilities,
410
+ supportedNetworks: supportedNetworks,
411
+ countryCode: countryCode,
412
+ currencyCode: currency
413
+ }
414
+ }];
415
+
416
+ // Define PaymentDetails
417
+ const paymentDetails = {
418
+ total: {
419
+ label: settings?.merchantName || "Demo Payment",
420
+ amount: {
421
+ value: amountValue,
422
+ currency: currency
423
+ }
424
+ }
425
+ };
426
+
427
+ // Define PaymentOptions
428
+ const paymentOptions = {
429
+ requestPayerName: requestPayerName,
430
+ requestBillingAddress: requestBillingAddress,
431
+ requestPayerEmail: requestPayerEmail,
432
+ requestPayerPhone: requestPayerPhone,
433
+ requestShipping: requestShipping,
434
+ shippingType: shippingType
435
+ };
436
+
437
+ // Create PaymentRequest
438
+ const request = new PaymentRequest(paymentMethodData, paymentDetails, paymentOptions);
439
+
440
+ // Handle merchant validation
441
+ request.onmerchantvalidation = async (event) => {
442
+ console.log("[Apple Pay] Merchant validation requested:", {
443
+ validationURL: event.validationURL,
444
+ domain: window.location.hostname
445
+ });
446
+
447
+ try {
448
+ // Call backend to validate merchant with Payone
449
+ const merchantSessionPromise = validateMerchantWithPayone(event.validationURL, {
450
+ mid: gatewayMerchantId,
451
+ portalid: settings?.portalid,
452
+ domain: window.location.hostname,
453
+ displayName: settings?.merchantName || "Test Store"
454
+ });
455
+
456
+ merchantSessionPromise.then(session => {
457
+ console.log("[Apple Pay] Merchant session received:", {
458
+ hasMerchantIdentifier: !!session.merchantIdentifier,
459
+ domainName: session.domainName,
460
+ displayName: session.displayName
461
+ });
462
+ }).catch(err => {
463
+ console.error("[Apple Pay] Merchant session error:", err);
464
+ });
465
+
466
+ event.complete(merchantSessionPromise);
467
+ } catch (error) {
468
+ console.error("[Apple Pay] Merchant validation error:", error);
469
+ if (onError) {
470
+ onError(error);
471
+ }
472
+ // Complete with empty object - Payone will handle validation
473
+ event.complete({});
474
+ }
475
+ };
476
+
477
+ // Handle payment method change
478
+ request.onpaymentmethodchange = (event) => {
479
+ // Update payment details if needed based on payment method
480
+ const paymentDetailsUpdate = {
481
+ total: paymentDetails.total
482
+ };
483
+ event.updateWith(paymentDetailsUpdate);
484
+ };
485
+
486
+ // Handle shipping option change
487
+ request.onshippingoptionchange = (event) => {
488
+ const paymentDetailsUpdate = {
489
+ total: paymentDetails.total
490
+ };
491
+ event.updateWith(paymentDetailsUpdate);
492
+ };
493
+
494
+ // Handle shipping address change
495
+ request.onshippingaddresschange = (event) => {
496
+ const paymentDetailsUpdate = {};
497
+ event.updateWith(paymentDetailsUpdate);
498
+ };
499
+
500
+ // Show payment sheet and get response
501
+ console.log("[Apple Pay] Showing payment sheet...");
502
+ const response = await request.show();
503
+
504
+ console.log("[Apple Pay] Payment response received:", {
505
+ hasDetails: !!response.details,
506
+ payerName: response.payerName,
507
+ shippingAddress: !!response.shippingAddress
508
+ });
509
+
510
+ // Extract payment token
511
+ const paymentToken = response.details?.paymentToken || response.details?.token;
512
+
513
+ if (!paymentToken) {
514
+ console.error("[Apple Pay] Payment token is missing from response");
515
+ await response.complete("fail");
516
+ if (onError) {
517
+ onError(new Error("Apple Pay token is missing"));
518
+ }
519
+ return;
520
+ }
521
+
522
+ console.log("[Apple Pay] Payment token received:", {
523
+ hasToken: !!paymentToken,
524
+ tokenType: typeof paymentToken
525
+ });
526
+
527
+ // Convert token to base64 string for Payone
528
+ let tokenString;
529
+ try {
530
+ if (typeof paymentToken === 'string') {
531
+ tokenString = paymentToken;
532
+ } else {
533
+ tokenString = JSON.stringify(paymentToken);
534
+ }
535
+ // Base64 encode for Payone
536
+ tokenString = btoa(unescape(encodeURIComponent(tokenString)));
537
+ } catch (e) {
538
+ console.error("Token encoding error:", e);
539
+ tokenString = btoa(unescape(encodeURIComponent(JSON.stringify(paymentToken))));
540
+ }
541
+
542
+ // Call the callback with the token
543
+ console.log("[Apple Pay] Sending token to callback");
544
+ if (onTokenReceived) {
545
+ onTokenReceived(tokenString, {
546
+ paymentToken: paymentToken,
547
+ billingContact: response.payerName || response.details?.billingContact,
548
+ shippingContact: response.shippingAddress || response.details?.shippingAddress,
549
+ shippingOption: response.shippingOption || response.details?.shippingOption
550
+ });
551
+ }
552
+
553
+ // Complete payment with success
554
+ console.log("[Apple Pay] Completing payment with success status");
555
+ await response.complete("success");
556
+ console.log("[Apple Pay] Payment completed successfully");
557
+
558
+ } catch (error) {
559
+ console.error("[Apple Pay] Payment error:", {
560
+ message: error.message,
561
+ stack: error.stack,
562
+ name: error.name
563
+ });
564
+ if (onError) {
565
+ onError(error);
566
+ }
567
+ }
568
+ };
569
+
570
+ // Validate merchant with Payone
571
+ const validateMerchantWithPayone = async (validationURL, config) => {
572
+ console.log("[Apple Pay] Validating merchant with Payone:", {
573
+ validationURL,
574
+ config: {
575
+ mid: config.mid,
576
+ portalid: config.portalid,
577
+ domain: config.domain,
578
+ displayName: config.displayName
579
+ }
580
+ });
581
+
582
+ try {
583
+ // Call Strapi backend to validate with Payone
584
+ const response = await fetch('/api/strapi-plugin-payone-provider/validate-apple-pay-merchant', {
585
+ method: 'POST',
586
+ headers: {
587
+ 'Content-Type': 'application/json',
588
+ },
589
+ body: JSON.stringify({
590
+ validationURL,
591
+ ...config
592
+ })
593
+ });
594
+
595
+ console.log("[Apple Pay] Validation response status:", response.status);
596
+
597
+ if (response.ok) {
598
+ const merchantSession = await response.json();
599
+ console.log("[Apple Pay] Merchant session received from backend:", {
600
+ hasData: !!merchantSession.data,
601
+ merchantIdentifier: merchantSession.data?.merchantIdentifier
602
+ });
603
+ return merchantSession.data || merchantSession;
604
+ } else {
605
+ // If validation fails, return empty object - Payone will handle it
606
+ const errorText = await response.text();
607
+ console.warn("[Apple Pay] Merchant validation failed:", {
608
+ status: response.status,
609
+ statusText: response.statusText,
610
+ error: errorText
611
+ });
612
+ return {};
613
+ }
614
+ } catch (error) {
615
+ console.error("[Apple Pay] Merchant validation error:", {
616
+ message: error.message,
617
+ stack: error.stack
618
+ });
619
+ // Return empty object - Payone will handle validation
620
+ return {};
621
+ }
622
+ };
623
+
624
+ return (
625
+ <Box width="100%">
626
+ <Flex direction="column" gap={3} alignItems="stretch">
627
+ {isLoading && (
628
+ <Typography variant="pi" textColor="neutral600" style={{ textAlign: "left" }}>
629
+ Checking Apple Pay availability...
630
+ </Typography>
631
+ )}
632
+ {!isLoading && !isAvailable && (
633
+ <Box style={{ width: "100%", display: "flex", flexDirection: "row", alignItems: "flex-start", gap: "8px" }}>
634
+ {errorMessage && (
635
+ <Typography variant="sigma" textColor="neutral500" style={{ textAlign: "left", fontSize: "12px" }}>
636
+ {errorMessage}
637
+ </Typography>
638
+ )}
639
+ </Box>
640
+ )}
641
+ {!isLoading && isAvailable && (
642
+ <>
643
+ <Typography variant="sigma" textColor="neutral700" fontWeight="semiBold" style={{ textAlign: "left" }}>
644
+ Apple Pay Payment
645
+ </Typography>
646
+ <Typography variant="pi" textColor="neutral600" style={{ textAlign: "left" }}>
647
+ Click the button below to pay with Apple Pay. The token will be automatically sent to Payone.
648
+ </Typography>
649
+ <Box ref={buttonContainerRef} style={{ minHeight: "40px", width: "100%", display: "flex", justifyContent: "flex-start" }}>
650
+ {typeof window !== 'undefined' && window.customElements && window.customElements.get('apple-pay-button') ? (
651
+ <apple-pay-button
652
+ buttonstyle={buttonStyle}
653
+ type={buttonType}
654
+ locale="en-US"
655
+ onClick={handleApplePayClick}
656
+ style={{
657
+ width: "200px",
658
+ height: "40px",
659
+ cursor: isReady ? "pointer" : "not-allowed",
660
+ opacity: isReady ? 1 : 0.5
661
+ }}
662
+ />
663
+ ) : (
664
+ <button
665
+ type="button"
666
+ onClick={handleApplePayClick}
667
+ disabled={!isReady}
668
+ style={{
669
+ appearance: "none",
670
+ WebkitAppearance: "-apple-pay-button",
671
+ ApplePayButtonType: buttonType,
672
+ ApplePayButtonStyle: buttonStyle,
673
+ height: "40px",
674
+ width: "200px",
675
+ border: "none",
676
+ borderRadius: "4px",
677
+ cursor: isReady ? "pointer" : "not-allowed",
678
+ opacity: isReady ? 1 : 0.5,
679
+ backgroundColor: buttonStyle === "black" ? "#000" : buttonStyle === "white" ? "#fff" : "transparent",
680
+ color: buttonStyle === "black" ? "#fff" : "#000",
681
+ borderWidth: buttonStyle === "white-outline" ? "1px" : "0",
682
+ borderStyle: buttonStyle === "white-outline" ? "solid" : "none",
683
+ borderColor: buttonStyle === "white-outline" ? "#000" : "transparent",
684
+ fontSize: "16px",
685
+ fontWeight: "400",
686
+ fontFamily: "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif",
687
+ display: "flex",
688
+ alignItems: "center",
689
+ justifyContent: "center"
690
+ }}
691
+ className="apple-pay-button-custom"
692
+ >
693
+ {buttonType === "pay" ? "Pay" : buttonType === "buy" ? "Buy" : buttonType === "donate" ? "Donate" : "Pay with Apple Pay"}
694
+ </button>
695
+ )}
696
+ </Box>
697
+ </>
698
+ )}
699
+ </Flex>
700
+ </Box>
701
+ );
702
+ };
703
+
704
+ export default ApplePayButton;