{ } }); +/** + * The `duoHandOffMessage` is set in the client via a cookie. This allows us to + * make use of i18n translations. + * + * Format the message as an object and set is as a cookie. The following gives an + * example (be sure to replace strings with i18n translated text): + * + * ``` + * const duoHandOffMessage = { + * title: "You successfully logged in", + * message: "This window will automatically close in 5 seconds", + * buttonText: "Close", + * countdown: 5 + * }; + * + * document.cookie = `duoHandOffMessage=${encodeURIComponent(JSON.stringify(duoHandOffMessage))};SameSite=strict`; + * + * ``` + * + * The `title`, `message`, and `buttonText` properties will be used to create the relevant + * DOM elements. The `countdown` property will be used for the starting value of the countdown. + * Make sure the `countdown` number matches the number set in the `message` property. + * + * If no `countdown` property is given, there will be no countdown timer and the user will simply + * have to close the tab manually. + */ function processAndDisplayHandoffMessage() { - const handOffMessage = ("; " + document.cookie) + const handOffMessageCookie = ("; " + document.cookie) + .split("; duoHandOffMessage=") .pop() .split(";") .shift(); + const handOffMessage = JSON.parse(decodeURIComponent(handOffMessageCookie)); + // Clear the cookie document.cookie = "duoHandOffMessage=;SameSite=strict;max-age=0"; const content = document.getElementById("content"); + content.className = "text-center"; content.innerHTML = ""; + const h1 = document.createElement("h1"); const p = document.createElement("p"); - p.className = "text-center"; - p.innerText = handOffMessage; + const button = document.createElement("button"); + h1.textContent = handOffMessage.title; + p.textContent = handOffMessage.message; + button.textContent = handOffMessage.buttonText; + + h1.className = "font-weight-semibold"; + p.className = "mb-4"; + button.className = "bg-primary text-white border-0 rounded py-2 px-3"; + + button.addEventListener("click", () => { + window.close(); + }); + + content.appendChild(h1); content.appendChild(p); + content.appendChild(button); + + // Countdown timer (closes tab upon completion) + if (handOffMessage.countdown && Number.isInteger(handOffMessage.countdown)) { + let num = handOffMessage.countdown; + + const interval = setInterval(() => { + if (num > 1) { + p.textContent = `This window will automatically close in ${num - 1} seconds`; + num--; + } else { + clearInterval(interval); + window.close(); + } + }, 1000); + } } diff --git a/apps/web/src/images/logo-primary@2x.png b/apps/web/src/images/logo-primary@2x.png new file mode 100644 index 00000000000..2f6512bc253 Binary files /dev/null and b/apps/web/src/images/logo-primary@2x.png differ
+