@@ -5,6 +5,8 @@ import {PAYONE_ASSETS_URL} from '../../constants';
55import getPaymentMethodConfig from '../../services/getPaymentMethodConfig' ;
66import AssetService from '../../services/AssetService' ;
77
8+ const PLACE_ORDER_BUTTON_SELECTOR = '.wc-block-components-checkout-place-order-button' ;
9+
810const PayoneGooglePay = ( {
911 eventRegistration,
1012 emitResponse,
@@ -21,6 +23,7 @@ const PayoneGooglePay = ({
2123
2224 const googlePayFinishedRef = useRef ( false ) ;
2325 const googlePayTokenRef = useRef ( null ) ;
26+ const buttonContainerRef = useRef ( null ) ;
2427
2528 // Load Google Pay SDK via AssetService
2629 useEffect ( ( ) => {
@@ -32,23 +35,67 @@ const PayoneGooglePay = ({
3235 } ) ;
3336 } , [ ] ) ;
3437
35- // Intercept checkout validation — open Google Pay popup
36- useEffect ( ( ) => onCheckoutValidation ( async ( ) => {
37- if ( googlePayFinishedRef . current ) {
38- return true ;
38+ // Render Google Pay button once SDK is ready
39+ useEffect ( ( ) => {
40+ if ( ! sdkReady || ! buttonContainerRef . current ) {
41+ return ;
3942 }
4043
41- if ( ! sdkReady ) {
42- setErrorMessage ( __ ( 'Google Pay wird geladen, bitte versuchen Sie es erneut.' , 'payone-woocommerce-3' ) ) ;
43- return false ;
44+ const baseCardPaymentMethod = {
45+ type : 'CARD' ,
46+ parameters : {
47+ allowedAuthMethods : [ 'PAN_ONLY' , 'CRYPTOGRAM_3DS' ] ,
48+ allowedCardNetworks : [ 'MASTERCARD' , 'VISA' ] ,
49+ allowPrepaidCards : true ,
50+ allowCreditCards : true ,
51+ } ,
52+ } ;
53+
54+ const paymentsClient = new google . payments . api . PaymentsClient ( {
55+ environment : googlePayConfig . environment ,
56+ } ) ;
57+
58+ paymentsClient . isReadyToPay ( {
59+ apiVersion : 2 ,
60+ apiVersionMinor : 0 ,
61+ allowedPaymentMethods : [ baseCardPaymentMethod ] ,
62+ } ) . then ( ( response ) => {
63+ if ( response . result ) {
64+ const button = paymentsClient . createButton ( {
65+ onClick : handleGooglePayClick ,
66+ buttonColor : 'black' ,
67+ buttonType : 'buy' ,
68+ buttonSizeMode : 'fill' ,
69+ buttonLocale : 'de' ,
70+ allowedPaymentMethods : [ baseCardPaymentMethod ] ,
71+ } ) ;
72+ buttonContainerRef . current . innerHTML = '' ;
73+ buttonContainerRef . current . appendChild ( button ) ;
74+ togglePlaceOrderButton ( false ) ;
75+ }
76+ } ) . catch ( ( err ) => {
77+ console . error ( 'Google Pay isReadyToPay error:' , err ) ;
78+ } ) ;
79+
80+ return ( ) => {
81+ togglePlaceOrderButton ( true ) ;
82+ } ;
83+ } , [ sdkReady ] ) ;
84+
85+ const togglePlaceOrderButton = ( show ) => {
86+ const placeOrderButton = document . querySelector ( PLACE_ORDER_BUTTON_SELECTOR ) ;
87+ if ( placeOrderButton ) {
88+ placeOrderButton . style . display = show ? '' : 'none' ;
4489 }
90+ } ;
4591
92+ const handleGooglePayClick = ( ) => {
4693 const baseRequest = { apiVersion : 2 , apiVersionMinor : 0 } ;
4794 const tokenizationSpecification = {
4895 type : 'PAYMENT_GATEWAY' ,
4996 parameters : {
50- gateway : 'payonegmbh' ,
51- gatewayMerchantId : googlePayConfig . gatewayMerchantId ,
97+ gateway : googlePayConfig . merchantName ,
98+ gatewayMerchantId : googlePayConfig . googlePayMerchantId ,
5299 } ,
53100 } ;
54101 const baseCardPaymentMethod = {
@@ -65,13 +112,11 @@ const PayoneGooglePay = ({
65112 tokenizationSpecification,
66113 } ;
67114
68- // Get cart totals from WooCommerce Blocks store
69115 const { CART_STORE_KEY } = wc . wcBlocksData ;
70116 const store = select ( CART_STORE_KEY ) ;
71117 const cartTotals = store . getCartTotals ( ) ;
72118 const cartData = store . getCartData ( ) ;
73119
74- // total_price is in minor units as string (e.g. "1999" for 19.99 EUR)
75120 const totalPrice = ( parseInt ( cartTotals . total_price , 10 ) / 100 ) . toFixed ( 2 ) ;
76121 const currencyCode = cartTotals . currency_code ;
77122 const countryCode = cartData . billingAddress . country ;
@@ -80,48 +125,40 @@ const PayoneGooglePay = ({
80125 environment : googlePayConfig . environment ,
81126 } ) ;
82127
83- try {
84- const readyResponse = await paymentsClient . isReadyToPay ( {
85- ...baseRequest ,
86- allowedPaymentMethods : [ baseCardPaymentMethod ] ,
87- } ) ;
88-
89- if ( readyResponse . result ) {
90- const paymentData = await paymentsClient . loadPaymentData ( {
91- ...baseRequest ,
92- allowedPaymentMethods : [ cardPaymentMethod ] ,
93- transactionInfo : {
94- totalPriceStatus : 'FINAL' ,
95- totalPrice,
96- currencyCode,
97- countryCode,
98- } ,
99- } ) ;
100-
101- const token = btoa ( paymentData . paymentMethodData . tokenizationData . token ) ;
102- googlePayTokenRef . current = token ;
103- googlePayFinishedRef . current = true ;
104- setGooglePayToken ( token ) ;
105- setGooglePayFinished ( true ) ;
106- }
107- } catch ( err ) {
128+ paymentsClient . loadPaymentData ( {
129+ ...baseRequest ,
130+ allowedPaymentMethods : [ cardPaymentMethod ] ,
131+ transactionInfo : {
132+ totalPriceStatus : 'FINAL' ,
133+ totalPrice,
134+ currencyCode,
135+ countryCode,
136+ } ,
137+ } ) . then ( ( paymentData ) => {
138+ const token = btoa ( paymentData . paymentMethodData . tokenizationData . token ) ;
139+ googlePayTokenRef . current = token ;
140+ googlePayFinishedRef . current = true ;
141+ setGooglePayToken ( token ) ;
142+ setGooglePayFinished ( true ) ;
143+ } ) . catch ( ( err ) => {
108144 googlePayFinishedRef . current = false ;
109145 setGooglePayFinished ( false ) ;
110-
111- // User cancelled the popup — silently reset, no error message
112146 if ( err . statusCode !== 'CANCELED' ) {
113147 setErrorMessage (
114148 err . message
115149 || __ ( 'Google Pay konnte nicht durchgeführt werden.' , 'payone-woocommerce-3' ) ,
116150 ) ;
117151 console . error ( 'Google Pay error:' , err ) ;
118152 }
119- }
153+ } ) ;
154+ } ;
120155
121- return false ;
122- } ) , [ onCheckoutValidation , googlePayFinished , sdkReady ] ) ;
156+ // Validate checkout — only allow submit when token is present
157+ useEffect ( ( ) => onCheckoutValidation ( ( ) => {
158+ return ! ! ( googlePayFinishedRef . current && googlePayTokenRef . current ) ;
159+ } ) , [ onCheckoutValidation ] ) ;
123160
124- // Register onPaymentSetup and trigger re-submit when token arrives (Klarna pattern)
161+ // Provide token on payment setup and trigger re-submit
125162 useEffect ( ( ) => {
126163 const unsubscribe = onPaymentSetup ( ( ) => {
127164 if ( errorMessage ) {
@@ -158,7 +195,7 @@ const PayoneGooglePay = ({
158195 return unsubscribe ;
159196 } , [ onPaymentSetup , googlePayFinished , googlePayToken ] ) ;
160197
161- return null ;
198+ return < div ref = { buttonContainerRef } /> ;
162199} ;
163200
164201export default getPaymentMethodConfig (
0 commit comments