1/* global rcpStripe, rcp_processing, rcp_script_options */ 2 3/** 4 * Handle a failed Stripe payment 5 * 6 * This does an ajax request to trigger `rcp_registration_failed`, which changes the payment 7 * status to `failed` and disables the pending membership. 8 * 9 * @param {int} payment_id 10 * @param {string} message 11 * 12 * @since 3.2 13 */ 14function rcpStripeHandlePaymentFailure( payment_id, message ) { 15 16 let $ = jQuery; 17 18 function report( nonce ) { 19 $.ajax( { 20 type: 'post', 21 dataType: 'json', 22 url: rcp_script_options.ajaxurl, 23 data: { 24 action: 'rcp_stripe_handle_initial_payment_failure', 25 payment_id: payment_id, 26 message: message, 27 nonce: nonce 28 }, 29 success: function ( response ) { } 30 } ); 31 } 32 33 /* 34 * Registration creates the account and logs the visitor in, which leaves the nonce printed 35 * on the page belonging to the logged out visitor. Ask for one that matches who they are 36 * now, and fall back to the printed one if that request fails. 37 */ 38 $.ajax( { 39 type: 'post', 40 dataType: 'json', 41 url: rcp_script_options.ajaxurl, 42 data: { action: 'rcp_stripe_generate_payment_nonce' }, 43 success: function ( response ) { 44 report( response && response.success ? response.data : rcp_script_options.stripe_payment_nonce ); 45 }, 46 error: function () { 47 report( rcp_script_options.stripe_payment_nonce ); 48 } 49 } ); 50 51} 52 53/** 54 * Close the Stripe Checkout modal. 55 * 56 * @since 3.2 57 */ 58function rcpStripeCloseCheckoutModal() { 59 // Don't allow closing if we're already processing the form. 60 if ( rcp_processing ) { 61 return; 62 } 63 64 let $ = jQuery; 65 let modalWrapper = $( '.rcp-modal-wrapper' ); 66 let modalContainer = $( '.rcp-modal' ); 67 68 modalWrapper.fadeOut( 250 ); 69 modalContainer.hide(); 70 71 if ( ! document.getElementById( 'rcp-card-element' ) ) { 72 return; 73 } 74 75 // Unmount Stripe Elements. 76 rcpStripe.elements.card.unmount( '#rcp-card-element' ); 77} 78 79/** 80 * Handles a Stripe payment / setup intent, dynamically factoring in: 81 * - Saved vs new payment method 82 * - Setup Intent vs Payment Intent 83 * 84 * @param {string} handler Stripe handler to call - either `handleCardPayment` or `confirmCardSetup`. 85 * @param {string} client_secret Client secret to pass into the function. 86 * @param {object} args Arguments to pass into the function. For a saved payment method this 87 * should contain the payment method ID. For a new payment method this 88 * might contain the billing card name. 89 * 90 * @since 3.3 91 * @return {Promise} 92 */ 93function rcpStripeHandleIntent( handler, client_secret, args ) { 94 return rcpStripe.Stripe[ handler ]( client_secret, args ); 95} 96 97// Reliant on jQuery triggers, so setup jQuery. 98jQuery( function( $ ) { 99 100 var RCP_Stripe_Registration = { 101 102 /** 103 * Whether or not a payment method has been filled out. 104 */ 105 hasPaymentMethod: false, 106 107 /** 108 * ID of the saved payment method, or `false` if using a new card. 109 */ 110 paymentMethodID: false, 111 112 /** 113 * Initialize all our events 114 */ 115 init: function() { 116 $( 'body' ).on( 'rcp_gateway_loaded', RCP_Stripe_Registration.mountElements ); 117 $( '#rcp_submit' ).on( 'click', RCP_Stripe_Registration.maybeBlockSubmit ); 118 $( 'body' ).on( 'rcp_registration_form_processed', RCP_Stripe_Registration.handlePayment ); 119 $( 'body' ).on( 'click', '.rcp-stripe-register-submit-button', RCP_Stripe_Registration.launchModal ); 120 }, 121 122 /** 123 * Attempt to mount the Stripe Elements card when the gateway changes. 124 * 125 * @param e 126 * @param gateway 127 */ 128 mountElements: function ( e, gateway ) { 129 if ( ! document.getElementById( 'rcp-card-element' ) ) { 130 return; 131 } 132 133 // Update element styles. 134 rcpStripeUpdateElementStyles( rcpStripe.elements.card, '.rcp_card_name' ); 135 136 // Field is available, mount. 137 rcpStripe.elements.card.mount( '#rcp-card-element' ); 138 139 // Flag as having card details. 140 rcpStripe.elements.card.addEventListener( 'change', function ( event ) { 141 if ( event.complete ) { 142 RCP_Stripe_Registration.hasPaymentMethod = true; 143 } 144 } ); 145 146 /** 147 * Listen for selected payment method changing. 148 */ 149 RCP_Stripe_Registration.setPaymentMethodID(); 150 151 // Handle errors. 152 rcpStripe.elements.card.addEventListener( 'change', rcpStripeToggleElementErrors ); 153 }, 154 155 /** 156 * Set the current payment method ID and listen for changes. 157 */ 158 setPaymentMethodID: function() { 159 let savedPaymentMethod = $( 'input[name="rcp_gateway_existing_payment_method"]' ); 160 savedPaymentMethod.on( 'change', function( e ) { 161 rcpStripeToggleElementErrors( e ); // clear errors 162 let value = $( 'input[name="rcp_gateway_existing_payment_method"]:checked' ).val(); 163 $( '.rcp-gateway-saved-payment-method, .rcp-gateway-add-payment-method-wrap' ).removeClass( 'rcp-gateway-selected-payment-method' ); 164 if ( 'new' === value ) { 165 $( '.rcp-gateway-new-card-fields' ).show(); 166 $( '.rcp-gateway-add-payment-method-wrap' ).addClass( 'rcp-gateway-selected-payment-method' ); 167 RCP_Stripe_Registration.paymentMethodID = false;
168 } else { 169 $( '.rcp-gateway-new-card-fields' ).hide(); 170 $( this ).parents( '.rcp-gateway-saved-payment-method' ).addClass( 'rcp-gateway-selected-payment-method' ); 171 RCP_Stripe_Registration.paymentMethodID = value; 172 } 173 } ); 174 175 savedPaymentMethod.trigger( 'change' ); 176 }, 177 178 /** 179 * Block the form submission if Stripe is the selected gateway, payment is due, a new payment method is being 180 * entered, but no details have been provided. 181 * 182 * @param e 183 * @returns {boolean} 184 */ 185 maybeBlockSubmit: function ( e ) { 186 if ( 'stripe' === rcp_get_gateway().val() && document.getElementById( 'rcp-card-element' ) && ! RCP_Stripe_Registration.hasPaymentMethod && ! RCP_Stripe_Registration.paymentMethodID ) { 187 e.stopPropagation(); 188 rcpStripeHandleError( rcp_script_options.enter_card_details ); 189 return false; 190 } 191 }, 192 193 /** 194 * After registration has been processed, handle card payments. 195 * 196 * @param event 197 * @param form 198 * @param response 199 */ 200 handlePayment: function ( event, form, response ) { 201 // Not on Stripe gateway, bail. 202 if ( response.gateway.slug !== 'stripe' ) { 203 return; 204 } 205 206 /* 207 * Bail if the amount due today is 0 AND: 208 * the recurring amount is 0, or auto renew is off 209 */ 210 if ( ! response.total && ( ! response.recurring_total || ! response.auto_renew ) ) { 211 return; 212 } 213 214 // 100% discount, bail. 215 if ( $( '.rcp_gateway_fields' ).hasClass( 'rcp_discounted_100' ) ) { 216 return; 217 } 218 219 // Trigger error if we don't have a client secret. 220 if ( ! response.gateway.data.stripe_client_secret ) { 221 rcpStripeHandleError( rcp_script_options.error_occurred ); 222 rcpStripeHandlePaymentFailure( response.payment_id, rcp_script_options.error_occurred ); 223 224 return; 225 } 226 227 let cardHolderName = $( '.card-name' ).val(); 228 229 let handler = 'payment_intent' === response.gateway.data.stripe_intent_type ? 'confirmCardPayment' : 'confirmCardSetup'; 230 let args = { 231 payment_method: { 232 card: rcpStripe.elements.card, 233 billing_details: { name: cardHolderName } 234 } 235 }; 236 237 if ( RCP_Stripe_Registration.paymentMethodID ) { 238 args = { 239 payment_method: RCP_Stripe_Registration.paymentMethodID 240 }; 241 } 242 243 /** 244 * Handle payment intent / setup intent. 245 */ 246 rcpStripeHandleIntent( 247 handler, response.gateway.data.stripe_client_secret, args 248 ).then( function( paymentResult ) { 249 if ( paymentResult.error ) { 250 rcpStripeHandleError( paymentResult.error.message, paymentResult.error.code ); 251 rcpStripeHandlePaymentFailure( response.payment_id, paymentResult.error.message ); 252 } else { 253 rcp_submit_registration_form( form, response ); 254 } 255 } ); 256 }, 257 258 /** 259 * Launch the [register_form_stripe] modal. 260 * 261 * @param e 262 */ 263 launchModal: function( e ) { 264 e.preventDefault(); 265 266 let modalWrapper = $( '.rcp-modal-wrapper' ); 267 let modalContainer = $( '.rcp-modal' ); 268 let form = $( this ).parents( '.rcp-stripe-register' ); 269 270 // Mount the Stripe Elements card. 271 if ( ! document.getElementById( 'rcp-card-element' ) ) { 272 return; 273 } 274 275 // Fade in wrapper. 276 modalWrapper.fadeIn( 250 ); 277 278 // Field is available, mount. 279 rcpStripe.elements.card.mount( '#rcp-card-element' ); 280 281 let registerButton = modalContainer.find( 'input.rcp-modal-submit' ); 282 283 // Flag as having card details. 284 rcpStripe.elements.card.addEventListener( 'change', function ( event ) { 285 if ( event.complete ) { 286 RCP_Stripe_Registration.hasPaymentMethod = true; 287 } 288 } ); 289 290 // Handle errors. 291 rcpStripe.elements.card.addEventListener( 'change', rcpStripeToggleElementErrors ); 292 293 // Set up saved vs. new card. 294 RCP_Stripe_Registration.setPaymentMethodID(); 295 296 // Set form content. 297 if ( form.data( 'name' ) ) { 298 $( '.rcp-modal-membership-name' ).text( form.data( 'name' ) ).show(); 299 } 300 if ( form.data( 'description' ) ) { 301 $( '.rcp-modal-membership-description' ).text( form.data( 'description' ) ).show(); 302 } 303 if ( form.data( 'panel-label' ) ) { 304 registerButton.val( form.data( 'panel-label' ) ); 305 } 306 if ( form.data( 'level-id' ) ) { 307 modalContainer.find( '#rcp-stripe-checkout-level-id' ).val( form.data( 'level-id' ) ); 308 } 309 310 // Fade in container. 311 modalContainer.fadeIn( 250 ); 312 313 /** 314 * Close the modal on these three events... 315 */ 316 317 // If they click the close icon, close modal. 318 modalWrapper.find( '.rcp-modal-close' ).on( 'click', function() { 319 rcpStripeCloseCheckoutModal(); 320 } ); 321 322 // If they press "ESC" on the keyboard, close modal. 323 $( document ).on( 'keydown', function ( e ) { 324 if ( 27 === e.keyCode ) { 325 rcpStripeCloseCheckoutModal(); 326 } 327 } ); 328 329 // If they click outside the container, close modal. 330 $( document ).mouseup( function( e ) { 331 if ( ! modalContainer.is( e.target ) && modalContainer.has( e.target ).length === 0 ) { 332 rcpStripeCloseCheckoutModal(); 333 } 334 } ); 335 } 336 337 }; 338 RCP_Stripe_Registration.init(); 339} );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.