mirror of
				https://github.com/juspay/hyperswitch.git
				synced 2025-11-01 02:57:02 +08:00 
			
		
		
		
	feat(payment-link): emit intent status to parent before rendering payment link UI (#7531)
Co-authored-by: hyperswitch-bot[bot] <148525504+hyperswitch-bot[bot]@users.noreply.github.com>
This commit is contained in:
		| @ -7944,6 +7944,7 @@ pub struct PaymentLinkDetails { | |||||||
|     pub background_colour: Option<String>, |     pub background_colour: Option<String>, | ||||||
|     pub sdk_ui_rules: Option<HashMap<String, HashMap<String, String>>>, |     pub sdk_ui_rules: Option<HashMap<String, HashMap<String, String>>>, | ||||||
|     pub payment_link_ui_rules: Option<HashMap<String, HashMap<String, String>>>, |     pub payment_link_ui_rules: Option<HashMap<String, HashMap<String, String>>>, | ||||||
|  |     pub status: api_enums::IntentStatus, | ||||||
|     pub enable_button_only_on_form_ready: bool, |     pub enable_button_only_on_form_ready: bool, | ||||||
| } | } | ||||||
|  |  | ||||||
|  | |||||||
| @ -191,7 +191,7 @@ pub async fn form_payment_link_data( | |||||||
|     let merchant_name = capitalize_first_char(&payment_link_config.seller_name); |     let merchant_name = capitalize_first_char(&payment_link_config.seller_name); | ||||||
|     let payment_link_status = check_payment_link_status(session_expiry); |     let payment_link_status = check_payment_link_status(session_expiry); | ||||||
|  |  | ||||||
|     let is_terminal_state = check_payment_link_invalid_conditions( |     let is_payment_link_terminal_state = check_payment_link_invalid_conditions( | ||||||
|         payment_intent.status, |         payment_intent.status, | ||||||
|         &[ |         &[ | ||||||
|             storage_enums::IntentStatus::Cancelled, |             storage_enums::IntentStatus::Cancelled, | ||||||
| @ -201,9 +201,11 @@ pub async fn form_payment_link_data( | |||||||
|             storage_enums::IntentStatus::RequiresMerchantAction, |             storage_enums::IntentStatus::RequiresMerchantAction, | ||||||
|             storage_enums::IntentStatus::Succeeded, |             storage_enums::IntentStatus::Succeeded, | ||||||
|             storage_enums::IntentStatus::PartiallyCaptured, |             storage_enums::IntentStatus::PartiallyCaptured, | ||||||
|  |             storage_enums::IntentStatus::RequiresCustomerAction, | ||||||
|         ], |         ], | ||||||
|     ); |     ); | ||||||
|     if is_terminal_state || payment_link_status == api_models::payments::PaymentLinkStatus::Expired |     if is_payment_link_terminal_state | ||||||
|  |         || payment_link_status == api_models::payments::PaymentLinkStatus::Expired | ||||||
|     { |     { | ||||||
|         let status = match payment_link_status { |         let status = match payment_link_status { | ||||||
|             api_models::payments::PaymentLinkStatus::Active => { |             api_models::payments::PaymentLinkStatus::Active => { | ||||||
| @ -211,7 +213,7 @@ pub async fn form_payment_link_data( | |||||||
|                 PaymentLinkStatusWrap::IntentStatus(payment_intent.status) |                 PaymentLinkStatusWrap::IntentStatus(payment_intent.status) | ||||||
|             } |             } | ||||||
|             api_models::payments::PaymentLinkStatus::Expired => { |             api_models::payments::PaymentLinkStatus::Expired => { | ||||||
|                 if is_terminal_state { |                 if is_payment_link_terminal_state { | ||||||
|                     logger::info!("displaying status page as the requested payment link has reached terminal state with payment status as {:?}", payment_intent.status); |                     logger::info!("displaying status page as the requested payment link has reached terminal state with payment status as {:?}", payment_intent.status); | ||||||
|                     PaymentLinkStatusWrap::IntentStatus(payment_intent.status) |                     PaymentLinkStatusWrap::IntentStatus(payment_intent.status) | ||||||
|                 } else { |                 } else { | ||||||
| @ -292,6 +294,7 @@ pub async fn form_payment_link_data( | |||||||
|         payment_button_text_colour: payment_link_config.payment_button_text_colour.clone(), |         payment_button_text_colour: payment_link_config.payment_button_text_colour.clone(), | ||||||
|         sdk_ui_rules: payment_link_config.sdk_ui_rules.clone(), |         sdk_ui_rules: payment_link_config.sdk_ui_rules.clone(), | ||||||
|         payment_link_ui_rules: payment_link_config.payment_link_ui_rules.clone(), |         payment_link_ui_rules: payment_link_config.payment_link_ui_rules.clone(), | ||||||
|  |         status: payment_intent.status, | ||||||
|         enable_button_only_on_form_ready: payment_link_config.enable_button_only_on_form_ready, |         enable_button_only_on_form_ready: payment_link_config.enable_button_only_on_form_ready, | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | |||||||
| @ -181,6 +181,30 @@ var hyper = null; | |||||||
|  |  | ||||||
| const translations = getTranslations(window.__PAYMENT_DETAILS.locale); | const translations = getTranslations(window.__PAYMENT_DETAILS.locale); | ||||||
|  |  | ||||||
|  | var isFramed = false; | ||||||
|  | try { | ||||||
|  |   isFramed = window.parent.location !== window.location; | ||||||
|  |  | ||||||
|  |   // If parent's window object is restricted, DOMException is | ||||||
|  |   // thrown which concludes that the webpage is iframed | ||||||
|  | } catch (err) { | ||||||
|  |   isFramed = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Trigger - on boot | ||||||
|  |  * Use - emit latest payment status to parent window | ||||||
|  |  */ | ||||||
|  | function emitPaymentStatus(paymentDetails) { | ||||||
|  |   var message = { | ||||||
|  |     payment: { | ||||||
|  |       status: paymentDetails.status, | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   window.parent.postMessage(message, "*"); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Trigger - init function invoked once the script tag is loaded |  * Trigger - init function invoked once the script tag is loaded | ||||||
|  * Use |  * Use | ||||||
| @ -190,13 +214,16 @@ const translations = getTranslations(window.__PAYMENT_DETAILS.locale); | |||||||
|  *  - Initialize event listeners for updating UI on screen size changes |  *  - Initialize event listeners for updating UI on screen size changes | ||||||
|  *  - Initialize SDK |  *  - Initialize SDK | ||||||
|  **/ |  **/ | ||||||
|  |  | ||||||
|  |  | ||||||
| function boot() { | function boot() { | ||||||
|  |  | ||||||
|   // @ts-ignore |   // @ts-ignore | ||||||
|   var paymentDetails = window.__PAYMENT_DETAILS; |   var paymentDetails = window.__PAYMENT_DETAILS; | ||||||
|  |  | ||||||
|  |   // Emit latest payment status | ||||||
|  |   if (isFramed) { | ||||||
|  |     emitPaymentStatus(paymentDetails); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   if (paymentDetails.display_sdk_only) { |   if (paymentDetails.display_sdk_only) { | ||||||
|     hide(".checkout-page") |     hide(".checkout-page") | ||||||
|     var sdkDisplayWidth = document.querySelector('.hyper-checkout-sdk'); |     var sdkDisplayWidth = document.querySelector('.hyper-checkout-sdk'); | ||||||
|  | |||||||
| @ -137,6 +137,10 @@ body > div { | |||||||
|   font-size: 13px; |   font-size: 13px; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | .hidden { | ||||||
|  |   display: none; | ||||||
|  | } | ||||||
|  |  | ||||||
| .ellipsis-container-2 { | .ellipsis-container-2 { | ||||||
|   height: 2.5em; |   height: 2.5em; | ||||||
|   overflow: hidden; |   overflow: hidden; | ||||||
|  | |||||||
| @ -16,7 +16,7 @@ | |||||||
|       {{ rendered_js }} |       {{ rendered_js }} | ||||||
|     </script> |     </script> | ||||||
|   </head> |   </head> | ||||||
|   <body onload="boot()"> |   <body onload="boot()" class="hidden"> | ||||||
|     <div> |     <div> | ||||||
|       <div class="hyper-checkout-status-wrap"> |       <div class="hyper-checkout-status-wrap"> | ||||||
|         <div id="hyper-checkout-status-header"></div> |         <div id="hyper-checkout-status-header"></div> | ||||||
|  | |||||||
| @ -52,8 +52,8 @@ function invertToBW(color, bw, asArr) { | |||||||
|       ? hexToRgbArray(options.black) |       ? hexToRgbArray(options.black) | ||||||
|       : options.black |       : options.black | ||||||
|     : asArr |     : asArr | ||||||
|     ? hexToRgbArray(options.white) |       ? hexToRgbArray(options.white) | ||||||
|     : options.white; |       : options.white; | ||||||
| } | } | ||||||
| function invert(color, bw) { | function invert(color, bw) { | ||||||
|   if (bw === void 0) { |   if (bw === void 0) { | ||||||
| @ -87,6 +87,31 @@ window.state = { | |||||||
| }; | }; | ||||||
|  |  | ||||||
| const translations = getTranslations(window.__PAYMENT_DETAILS.locale); | const translations = getTranslations(window.__PAYMENT_DETAILS.locale); | ||||||
|  |  | ||||||
|  | var isFramed = false; | ||||||
|  | try { | ||||||
|  |   isFramed = window.parent.location !== window.location; | ||||||
|  |  | ||||||
|  |   // If parent's window object is restricted, DOMException is | ||||||
|  |   // thrown which concludes that the webpage is iframed | ||||||
|  | } catch (err) { | ||||||
|  |   isFramed = true; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Trigger - on boot | ||||||
|  |  * Use - emit latest payment status to parent window | ||||||
|  |  */ | ||||||
|  | function emitPaymentStatus(paymentDetails) { | ||||||
|  |   var message = { | ||||||
|  |     payment: { | ||||||
|  |       status: paymentDetails.status, | ||||||
|  |     } | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   window.parent.postMessage(message, "*"); | ||||||
|  | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
|  * Trigger - init function invoked once the script tag is loaded |  * Trigger - init function invoked once the script tag is loaded | ||||||
|  * Use |  * Use | ||||||
| @ -100,20 +125,43 @@ function boot() { | |||||||
|   // @ts-ignore |   // @ts-ignore | ||||||
|   var paymentDetails = window.__PAYMENT_DETAILS; |   var paymentDetails = window.__PAYMENT_DETAILS; | ||||||
|  |  | ||||||
|   // Attach document icon |   // Emit latest payment status | ||||||
|   if (paymentDetails.merchant_logo) { |   if (isFramed) { | ||||||
|     var link = document.createElement("link"); |     emitPaymentStatus(paymentDetails); | ||||||
|     link.rel = "icon"; |  | ||||||
|     link.href = paymentDetails.merchant_logo; |  | ||||||
|     link.type = "image/x-icon"; |  | ||||||
|     document.head.appendChild(link); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Render status details |   if (shouldRenderUI(paymentDetails)) { | ||||||
|   renderStatusDetails(paymentDetails); |     removeClass("body", "hidden"); | ||||||
|  |     // Attach document icon | ||||||
|  |     if (paymentDetails.merchant_logo) { | ||||||
|  |       var link = document.createElement("link"); | ||||||
|  |       link.rel = "icon"; | ||||||
|  |       link.href = paymentDetails.merchant_logo; | ||||||
|  |       link.type = "image/x-icon"; | ||||||
|  |       document.head.appendChild(link); | ||||||
|  |     } | ||||||
|  |  | ||||||
|   // Add event listeners |     // Render status details | ||||||
|   initializeEventListeners(paymentDetails); |     renderStatusDetails(paymentDetails); | ||||||
|  |  | ||||||
|  |     // Add event listeners | ||||||
|  |     initializeEventListeners(paymentDetails); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Trigger - on boot | ||||||
|  |  * Use - Check if UI should be rendered based on some conditions | ||||||
|  |  * @returns {Boolean} | ||||||
|  |  */ | ||||||
|  | function shouldRenderUI(paymentDetails) { | ||||||
|  |   var status = paymentDetails.status; | ||||||
|  |   if (isFramed) { | ||||||
|  |     switch (status) { | ||||||
|  |       case "requires_customer_action": return false; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return true; | ||||||
| } | } | ||||||
|  |  | ||||||
| /** | /** | ||||||
| @ -158,6 +206,7 @@ function renderStatusDetails(paymentDetails) { | |||||||
|       ).toTimeString(); |       ).toTimeString(); | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
|  |     case "requires_customer_action": | ||||||
|     case "processing": |     case "processing": | ||||||
|       statusDetails.imageSource = "https://live.hyperswitch.io/payment-link-assets/pending.png"; |       statusDetails.imageSource = "https://live.hyperswitch.io/payment-link-assets/pending.png"; | ||||||
|       statusDetails.message = translations.paymentTakingLonger; |       statusDetails.message = translations.paymentTakingLonger; | ||||||
| @ -279,7 +328,7 @@ function renderStatusDetails(paymentDetails) { | |||||||
|           var innerText = |           var innerText = | ||||||
|             secondsLeft === 0 |             secondsLeft === 0 | ||||||
|               ? translations.redirecting |               ? translations.redirecting | ||||||
|               : translations.redirectingIn + secondsLeft + " "+translations.seconds; |               : translations.redirectingIn + secondsLeft + " " + translations.seconds; | ||||||
|           // @ts-ignore |           // @ts-ignore | ||||||
|           statusRedirectTextNode.innerText = innerText; |           statusRedirectTextNode.innerText = innerText; | ||||||
|           if (secondsLeft === 0) { |           if (secondsLeft === 0) { | ||||||
| @ -341,5 +390,18 @@ function initializeEventListeners(paymentDetails) { | |||||||
|   if (statusRedirectTextNode instanceof HTMLDivElement) { |   if (statusRedirectTextNode instanceof HTMLDivElement) { | ||||||
|     statusRedirectTextNode.style.color = contrastBWColor; |     statusRedirectTextNode.style.color = contrastBWColor; | ||||||
|   } |   } | ||||||
|   }; | }; | ||||||
|  |  | ||||||
|  | function addClass(id, className) { | ||||||
|  |   var element = document.querySelector(id); | ||||||
|  |   if (element instanceof HTMLElement) { | ||||||
|  |     element.classList.add(className); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | function removeClass(id, className) { | ||||||
|  |   var element = document.querySelector(id); | ||||||
|  |   if (element instanceof HTMLElement) { | ||||||
|  |     element.classList.remove(className); | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user
	 Kashif
					Kashif