diff --git a/crates/api_models/src/payments.rs b/crates/api_models/src/payments.rs index 27d7b82e54..840d427470 100644 --- a/crates/api_models/src/payments.rs +++ b/crates/api_models/src/payments.rs @@ -7944,6 +7944,7 @@ pub struct PaymentLinkDetails { pub background_colour: Option, pub sdk_ui_rules: Option>>, pub payment_link_ui_rules: Option>>, + pub status: api_enums::IntentStatus, pub enable_button_only_on_form_ready: bool, } diff --git a/crates/router/src/core/payment_link.rs b/crates/router/src/core/payment_link.rs index c13e087947..48004dd740 100644 --- a/crates/router/src/core/payment_link.rs +++ b/crates/router/src/core/payment_link.rs @@ -191,7 +191,7 @@ pub async fn form_payment_link_data( let merchant_name = capitalize_first_char(&payment_link_config.seller_name); 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, &[ storage_enums::IntentStatus::Cancelled, @@ -201,9 +201,11 @@ pub async fn form_payment_link_data( storage_enums::IntentStatus::RequiresMerchantAction, storage_enums::IntentStatus::Succeeded, 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 { api_models::payments::PaymentLinkStatus::Active => { @@ -211,7 +213,7 @@ pub async fn form_payment_link_data( PaymentLinkStatusWrap::IntentStatus(payment_intent.status) } 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); PaymentLinkStatusWrap::IntentStatus(payment_intent.status) } else { @@ -292,6 +294,7 @@ pub async fn form_payment_link_data( payment_button_text_colour: payment_link_config.payment_button_text_colour.clone(), sdk_ui_rules: payment_link_config.sdk_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, }; diff --git a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.js b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.js index e73e23076a..5c6f3a6b37 100644 --- a/crates/router/src/core/payment_link/payment_link_initiate/payment_link.js +++ b/crates/router/src/core/payment_link/payment_link_initiate/payment_link.js @@ -181,6 +181,30 @@ var hyper = null; 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 * Use @@ -190,13 +214,16 @@ const translations = getTranslations(window.__PAYMENT_DETAILS.locale); * - Initialize event listeners for updating UI on screen size changes * - Initialize SDK **/ - - function boot() { // @ts-ignore var paymentDetails = window.__PAYMENT_DETAILS; + // Emit latest payment status + if (isFramed) { + emitPaymentStatus(paymentDetails); + } + if (paymentDetails.display_sdk_only) { hide(".checkout-page") var sdkDisplayWidth = document.querySelector('.hyper-checkout-sdk'); diff --git a/crates/router/src/core/payment_link/payment_link_status/status.css b/crates/router/src/core/payment_link/payment_link_status/status.css index 113f135313..65b7b11d95 100644 --- a/crates/router/src/core/payment_link/payment_link_status/status.css +++ b/crates/router/src/core/payment_link/payment_link_status/status.css @@ -137,6 +137,10 @@ body > div { font-size: 13px; } +.hidden { + display: none; +} + .ellipsis-container-2 { height: 2.5em; overflow: hidden; diff --git a/crates/router/src/core/payment_link/payment_link_status/status.html b/crates/router/src/core/payment_link/payment_link_status/status.html index c78a0bb556..7531c8df44 100644 --- a/crates/router/src/core/payment_link/payment_link_status/status.html +++ b/crates/router/src/core/payment_link/payment_link_status/status.html @@ -16,7 +16,7 @@ {{ rendered_js }} - +
diff --git a/crates/router/src/core/payment_link/payment_link_status/status.js b/crates/router/src/core/payment_link/payment_link_status/status.js index 8c9697fd53..16949d546a 100644 --- a/crates/router/src/core/payment_link/payment_link_status/status.js +++ b/crates/router/src/core/payment_link/payment_link_status/status.js @@ -52,8 +52,8 @@ function invertToBW(color, bw, asArr) { ? hexToRgbArray(options.black) : options.black : asArr - ? hexToRgbArray(options.white) - : options.white; + ? hexToRgbArray(options.white) + : options.white; } function invert(color, bw) { if (bw === void 0) { @@ -87,6 +87,31 @@ window.state = { }; 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 * Use @@ -100,20 +125,43 @@ function boot() { // @ts-ignore var paymentDetails = window.__PAYMENT_DETAILS; - // 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); + // Emit latest payment status + if (isFramed) { + emitPaymentStatus(paymentDetails); } - // Render status details - renderStatusDetails(paymentDetails); + if (shouldRenderUI(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 - initializeEventListeners(paymentDetails); + // Render status details + 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(); break; + case "requires_customer_action": case "processing": statusDetails.imageSource = "https://live.hyperswitch.io/payment-link-assets/pending.png"; statusDetails.message = translations.paymentTakingLonger; @@ -279,7 +328,7 @@ function renderStatusDetails(paymentDetails) { var innerText = secondsLeft === 0 ? translations.redirecting - : translations.redirectingIn + secondsLeft + " "+translations.seconds; + : translations.redirectingIn + secondsLeft + " " + translations.seconds; // @ts-ignore statusRedirectTextNode.innerText = innerText; if (secondsLeft === 0) { @@ -341,5 +390,18 @@ function initializeEventListeners(paymentDetails) { if (statusRedirectTextNode instanceof HTMLDivElement) { 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); + } +} \ No newline at end of file