From fccd7952c4610ec083f30ced12c9aef0dc0d5f6d Mon Sep 17 00:00:00 2001 From: npgiano Date: Wed, 18 Mar 2026 18:30:19 -0400 Subject: [PATCH 1/2] Adds a configuration flag for opt-in ladders to always show TY page --- packages/scripts/dist/optin-ladder.js | 45 ++++++++++++++++++++------- packages/scripts/src/optin-ladder.ts | 45 ++++++++++++++++++++------- 2 files changed, 66 insertions(+), 24 deletions(-) diff --git a/packages/scripts/dist/optin-ladder.js b/packages/scripts/dist/optin-ladder.js index b6a82ce3..e46a0f65 100644 --- a/packages/scripts/dist/optin-ladder.js +++ b/packages/scripts/dist/optin-ladder.js @@ -1,9 +1,12 @@ -// This component is responsible for showing a ladder of checkboxes, one at a time, to the user. -// If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit. -// If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match. -// If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. -// If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. -import { EngridLogger, ENGrid, EnForm } from "."; +/** + * Docs: https://engrid.4sitestudios.com/component/optin-ladder + * This component is responsible for showing a ladder of checkboxes, one at a time, to the user. + * If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit. + * If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match. + * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. + * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. + */ +import { EngridLogger, ENGrid, EnForm } from '.'; export class OptInLadder { constructor() { this.logger = new EngridLogger("OptInLadder", "lightgreen", "darkgreen", "✔"); @@ -179,6 +182,12 @@ export class OptInLadder { return; } const hasOptInLadderStop = sessionStorage.getItem("engrid.optin-ladder-stop"); + const hasOptInLadderPersistStop = sessionStorage.getItem("engrid.optin-ladder-persist-stop"); + if (hasOptInLadderPersistStop) { + this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page"); + sessionStorage.removeItem("engrid.optin-ladder-persist-stop"); + return; + } if (hasOptInLadderStop) { this.logger.log("OptInLadder has been stopped"); return; @@ -186,9 +195,13 @@ export class OptInLadder { const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}"); const currentStep = sessionStorageOptInLadder.step || 0; const totalSteps = sessionStorageOptInLadder.totalSteps || 0; - if (currentStep <= totalSteps) { - this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`); + if (totalSteps == 0) { + this.logger.log("No total steps found in sessionStorage"); this.hidePage(); + } + else if (currentStep <= totalSteps) { + this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`); + this.hidePage(true); // Redirect to the first page window.location.href = this.getFirstPageUrl(); return; @@ -248,15 +261,23 @@ export class OptInLadder { isEmbeddedThankYouPage() { return ENGrid.getBodyData("embedded") === "thank-you-page-donation"; } - hidePage() { - const engridPage = document.querySelector("#engrid"); - if (engridPage) { - engridPage.classList.add("hide"); + hidePage(forceHide = false) { + if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) { + this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page"); + sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y"); + window.location.href = window.location.href.replace("data/1", "data/2"); + } + else { + const engridPage = document.querySelector("#engrid"); + if (engridPage) { + engridPage.classList.add("hide"); + } } } clearSessionStorage() { sessionStorage.removeItem("engrid.supporter.questions"); sessionStorage.removeItem("engrid.optin-ladder"); sessionStorage.removeItem("engrid.optin-ladder-stop"); + sessionStorage.removeItem("engrid.optin-ladder-persist-stop"); } } diff --git a/packages/scripts/src/optin-ladder.ts b/packages/scripts/src/optin-ladder.ts index 1701ba8d..6b8e80f3 100644 --- a/packages/scripts/src/optin-ladder.ts +++ b/packages/scripts/src/optin-ladder.ts @@ -1,9 +1,12 @@ -// This component is responsible for showing a ladder of checkboxes, one at a time, to the user. -// If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit. -// If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match. -// If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. -// If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. -import { EngridLogger, ENGrid, EnForm } from "."; +/** + * Docs: https://engrid.4sitestudios.com/component/optin-ladder + * This component is responsible for showing a ladder of checkboxes, one at a time, to the user. + * If the page is not embedded in an iframe, and there are EN's Opt-In fields on the page, we will store the values to sessionStorage upon Form Submit. + * If the page is embedded in an iframe and on a Thank You Page, we will look for .optin-ladder elements, compare the values to sessionStorage, and show the next checkbox in the ladder, removing all but the first match. + * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. + * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. + */ +import { EngridLogger, ENGrid, EnForm } from '.'; export class OptInLadder { private logger: EngridLogger = new EngridLogger( @@ -206,6 +209,14 @@ export class OptInLadder { const hasOptInLadderStop = sessionStorage.getItem( "engrid.optin-ladder-stop" ); + const hasOptInLadderPersistStop = sessionStorage.getItem( + "engrid.optin-ladder-persist-stop" + ); + if (hasOptInLadderPersistStop) { + this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page"); + sessionStorage.removeItem("engrid.optin-ladder-persist-stop"); + return; + } if (hasOptInLadderStop) { this.logger.log("OptInLadder has been stopped"); return; @@ -215,11 +226,14 @@ export class OptInLadder { ); const currentStep = sessionStorageOptInLadder.step || 0; const totalSteps = sessionStorageOptInLadder.totalSteps || 0; - if (currentStep <= totalSteps) { + if (totalSteps == 0) { + this.logger.log("No total steps found in sessionStorage"); + this.hidePage(); + } else if (currentStep <= totalSteps) { this.logger.log( `Current step ${currentStep} is less or equal to total steps ${totalSteps}` ); - this.hidePage(); + this.hidePage(true); // Redirect to the first page window.location.href = this.getFirstPageUrl(); return; @@ -296,15 +310,22 @@ export class OptInLadder { private isEmbeddedThankYouPage() { return ENGrid.getBodyData("embedded") === "thank-you-page-donation"; } - private hidePage() { - const engridPage = document.querySelector("#engrid") as HTMLElement; - if (engridPage) { - engridPage.classList.add("hide"); + private hidePage(forceHide: boolean = false) { + if(ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) { + this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page"); + sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y"); + window.location.href = window.location.href.replace("data/1", "data/2"); + } else { + const engridPage = document.querySelector("#engrid") as HTMLElement; + if (engridPage) { + engridPage.classList.add("hide"); + } } } private clearSessionStorage() { sessionStorage.removeItem("engrid.supporter.questions"); sessionStorage.removeItem("engrid.optin-ladder"); sessionStorage.removeItem("engrid.optin-ladder-stop"); + sessionStorage.removeItem("engrid.optin-ladder-persist-stop"); } } From 90d82510911054299ad6468b5cb812c1cf194d4b Mon Sep 17 00:00:00 2001 From: Fernando Santos Date: Thu, 19 Mar 2026 18:23:13 -0300 Subject: [PATCH 2/2] Refactor OptInLadder URL handling and fixes --- packages/scripts/dist/optin-ladder.d.ts | 3 +- packages/scripts/dist/optin-ladder.js | 26 ++++++++-------- packages/scripts/src/optin-ladder.ts | 41 +++++++++++++++---------- 3 files changed, 40 insertions(+), 30 deletions(-) diff --git a/packages/scripts/dist/optin-ladder.d.ts b/packages/scripts/dist/optin-ladder.d.ts index 1c5f1a60..eb396830 100644 --- a/packages/scripts/dist/optin-ladder.d.ts +++ b/packages/scripts/dist/optin-ladder.d.ts @@ -7,9 +7,10 @@ export declare class OptInLadder { private runAsChildThankYou; private inIframe; private saveStepToSessionStorage; - private getFirstPageUrl; private saveOptInsToSessionStorage; private isEmbeddedThankYouPage; + private getPageUrl; + private getFirstPageUrl; private hidePage; private clearSessionStorage; } diff --git a/packages/scripts/dist/optin-ladder.js b/packages/scripts/dist/optin-ladder.js index e46a0f65..392725b4 100644 --- a/packages/scripts/dist/optin-ladder.js +++ b/packages/scripts/dist/optin-ladder.js @@ -6,7 +6,7 @@ * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. */ -import { EngridLogger, ENGrid, EnForm } from '.'; +import { EngridLogger, ENGrid, EnForm } from "."; export class OptInLadder { constructor() { this.logger = new EngridLogger("OptInLadder", "lightgreen", "darkgreen", "✔"); @@ -98,7 +98,7 @@ export class OptInLadder { if (!emailField || !emailField.value) { this.logger.log("Email field is empty"); // Since this is a OptInLadder page with no e-mail address, hide the page - this.hidePage(); + this.hidePage(true); return; } const sessionStorageCheckboxValues = JSON.parse(sessionStorage.getItem("engrid.supporter.questions") || "{}"); @@ -195,9 +195,10 @@ export class OptInLadder { const sessionStorageOptInLadder = JSON.parse(sessionStorage.getItem("engrid.optin-ladder") || "{}"); const currentStep = sessionStorageOptInLadder.step || 0; const totalSteps = sessionStorageOptInLadder.totalSteps || 0; - if (totalSteps == 0) { + if (totalSteps === 0) { this.logger.log("No total steps found in sessionStorage"); this.hidePage(); + return; } else if (currentStep <= totalSteps) { this.logger.log(`Current step ${currentStep} is less or equal to total steps ${totalSteps}`); @@ -224,14 +225,6 @@ export class OptInLadder { sessionStorage.setItem("engrid.optin-ladder", JSON.stringify({ step, totalSteps })); this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`); } - getFirstPageUrl() { - // Get the current URL and replace the last path with 1?chain - const url = new URL(window.location.href); - const path = url.pathname.split("/"); - path.pop(); - path.push("1"); - return url.origin + path.join("/") + "?chain"; - } saveOptInsToSessionStorage(type = "parent") { // Grab all the checkboxes with the name starting with "supporter.questions" const checkboxes = document.querySelectorAll('input[name^="supporter.questions"]'); @@ -261,11 +254,20 @@ export class OptInLadder { isEmbeddedThankYouPage() { return ENGrid.getBodyData("embedded") === "thank-you-page-donation"; } + getPageUrl(page, chain = false) { + const url = new URL(window.location.href); + const path = url.pathname.split("/"); + path[path.length - 1] = String(page); + return url.origin + path.join("/") + (chain ? "?chain" : ""); + } + getFirstPageUrl() { + return this.getPageUrl(1, true); + } hidePage(forceHide = false) { if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) { this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page"); sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y"); - window.location.href = window.location.href.replace("data/1", "data/2"); + window.location.href = this.getPageUrl(2); } else { const engridPage = document.querySelector("#engrid"); diff --git a/packages/scripts/src/optin-ladder.ts b/packages/scripts/src/optin-ladder.ts index 6b8e80f3..64301fc9 100644 --- a/packages/scripts/src/optin-ladder.ts +++ b/packages/scripts/src/optin-ladder.ts @@ -6,7 +6,7 @@ * If the page is embedded in an iframe and on a Thank You Page, and the child iFrame is also a Thank You Page, we will look for a sessionStorage that has the current ladder step and the total number of steps. * If the current step is less than the total number of steps, we will redirect to the first page. If the current step is equal to the total number of steps, we will show the Thank You Page. */ -import { EngridLogger, ENGrid, EnForm } from '.'; +import { EngridLogger, ENGrid, EnForm } from "."; export class OptInLadder { private logger: EngridLogger = new EngridLogger( @@ -117,7 +117,7 @@ export class OptInLadder { if (!emailField || !emailField.value) { this.logger.log("Email field is empty"); // Since this is a OptInLadder page with no e-mail address, hide the page - this.hidePage(); + this.hidePage(true); return; } const sessionStorageCheckboxValues = JSON.parse( @@ -213,7 +213,9 @@ export class OptInLadder { "engrid.optin-ladder-persist-stop" ); if (hasOptInLadderPersistStop) { - this.logger.log("OptInLadder has been stopped with persist flag, showing the thank-you page"); + this.logger.log( + "OptInLadder has been stopped with persist flag, showing the thank-you page" + ); sessionStorage.removeItem("engrid.optin-ladder-persist-stop"); return; } @@ -226,9 +228,10 @@ export class OptInLadder { ); const currentStep = sessionStorageOptInLadder.step || 0; const totalSteps = sessionStorageOptInLadder.totalSteps || 0; - if (totalSteps == 0) { + if (totalSteps === 0) { this.logger.log("No total steps found in sessionStorage"); this.hidePage(); + return; } else if (currentStep <= totalSteps) { this.logger.log( `Current step ${currentStep} is less or equal to total steps ${totalSteps}` @@ -262,15 +265,6 @@ export class OptInLadder { this.logger.log(`Saved step ${step} of ${totalSteps} to sessionStorage`); } - private getFirstPageUrl() { - // Get the current URL and replace the last path with 1?chain - const url = new URL(window.location.href); - const path = url.pathname.split("/"); - path.pop(); - path.push("1"); - return url.origin + path.join("/") + "?chain"; - } - private saveOptInsToSessionStorage(type: "parent" | "child" = "parent") { // Grab all the checkboxes with the name starting with "supporter.questions" const checkboxes = document.querySelectorAll( @@ -310,11 +304,24 @@ export class OptInLadder { private isEmbeddedThankYouPage() { return ENGrid.getBodyData("embedded") === "thank-you-page-donation"; } + private getPageUrl(page: number, chain: boolean = false): string { + const url = new URL(window.location.href); + const path = url.pathname.split("/"); + path[path.length - 1] = String(page); + return url.origin + path.join("/") + (chain ? "?chain" : ""); + } + + private getFirstPageUrl(): string { + return this.getPageUrl(1, true); + } + private hidePage(forceHide: boolean = false) { - if(ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) { - this.logger.log("Hide activated, but opt-in ladder persist is enabled, showing the thank-you page"); - sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y"); - window.location.href = window.location.href.replace("data/1", "data/2"); + if (ENGrid.getBodyData("opt-in-ladder-persist") === "true" && !forceHide) { + this.logger.log( + "Hide activated, but opt-in ladder persist is enabled, showing the thank-you page" + ); + sessionStorage.setItem("engrid.optin-ladder-persist-stop", "Y"); + window.location.href = this.getPageUrl(2); } else { const engridPage = document.querySelector("#engrid") as HTMLElement; if (engridPage) {