diff --git a/public/css/header.css b/public/css/header.css index 03c7d444a..3d6e54c79 100644 --- a/public/css/header.css +++ b/public/css/header.css @@ -21,12 +21,72 @@ header.show-shadow { opacity: 1; } -.recruitment-banner { +.recruitment-banner, +.micro-survey-banner { background-color: #f9f7fd; - padding: .5em; + padding: 0.5em; text-align: center; } +#micro-survey-prompt { + font-size: 1.1rem; +} + +.micro-survey-banner { + background-color: #d8b7f7; + font-weight: bold; + padding-top: 1rem; +} + +.micro-survey-banner.hidden { + display: none; +} + +.micro-survey-options { + padding: 0; + font-size: 0.9rem; + display: flex; + align-items: center; + justify-content: center; + flex-direction: row; +} + +.micro-survey-options .micro-survey-option { + border-radius: 4px; + margin-right: 1rem; + color: var(--violet5); + border: 2px solid var(--violet5); + transition: all 0.1s ease-out; + cursor: pointer; +} + +.micro-survey-options .micro-survey-option:hover { + border-color: var(--violet6); + background: var(--violet6); + color: var(--grey1); +} + +.micro-survey-options-numeric .micro-survey-option { + width: 2.5rem; + height: 2.5rem; + display: flex; + align-items: center; + justify-content: center; +} + +.micro-survey-options-likert .micro-survey-option { + padding: 0.5rem 0.75rem; +} + +.nps-bookend { + display: inline-block; + margin-right: 1rem; +} + +.micro-survey-options li:last-child { + margin-right: 0; +} + #navigation-wrapper { background-color: var(--inkDark); } @@ -415,6 +475,12 @@ img.avatar, } } +@media screen and (max-width: 700px) { + .micro-survey-banner { + display: none; + } +} + @media screen and (max-width: 600px) { header, header.show-shadow { diff --git a/public/js/fxa-analytics.js b/public/js/fxa-analytics.js index 66b8a2d26..0c0a29f67 100644 --- a/public/js/fxa-analytics.js +++ b/public/js/fxa-analytics.js @@ -163,6 +163,173 @@ function setGAListeners(){ window.sessionStorage.setItem("gaInit", true); } +function resetBodyPadding() { + const header = document.querySelector("header"); + const headerHeight = header.clientHeight; + document.body.style.paddingTop = headerHeight + "px"; + return; +} + +function isGoogleAnalyticsAvailable() { + return (typeof(ga) !== "undefined"); +} + +function setSurveyedCookie() { + const date = new Date(); + date.setTime(date.getTime() + 30*24*60*60*1000); + document.cookie = "surveyed=true; expires=" + date.toUTCString(); + const microSurveyBanner = document.getElementById("micro-survey-banner"); + if (microSurveyBanner) { + microSurveyBanner.remove(); + } +} + +function analyticsSurveyLogic() { + + if (!isGoogleAnalyticsAvailable) { + return; + } + + const microSurveyBanner = document.getElementById("micro-survey-banner"); + if (!microSurveyBanner) { + return; + } + + const alreadySurveyed = document.cookie.split("; ").some((item) => item.trim().startsWith("surveyed=")); + if (alreadySurveyed) { + microSurveyBanner.remove(); + return; + } + + // Unhide the micro survey + microSurveyBanner.classList.remove("hidden"); + + const surveyPrompt = document.getElementById("micro-survey-prompt"); + const surveyType = surveyPrompt.dataset.surveyType; + const surveyOptions = document.getElementById("micro-survey-options"); + switch (surveyType) { + case "nps": { + const notLikely = document.createElement("li"); + notLikely.textContent = "Not likely"; + notLikely.classList = "nps-bookend"; + surveyOptions.appendChild(notLikely); + [...Array(10).keys()].forEach(option => { + const li = document.createElement("li"); + li.classList = "micro-survey-option"; + li.textContent = option + 1; + li.dataset.eventCategory = "NPS Survey"; + li.dataset.eventAction = "submitted"; + li.dataset.eventValue = option + 1; + if (option < 6) { + li.dataset.eventLabel = "detractor"; + li.dataset.npsValue = -1; + } else if (option < 8) { + li.dataset.eventLabel = "passive"; + li.dataset.npsValue = 0; + } else { + li.dataset.eventLabel = "promoter"; + li.dataset.npsValue = 1; + } + li.addEventListener("click", (evt) => { + const eventData = li.dataset; + ga("send", "event", + eventData.eventCategory, + eventData.eventAction, + eventData.eventLabel, + eventData.eventValue, + { + dimension1: eventData.eventLabel, + metric2: 1, + metric3: eventData.eventValue, + metric4: eventData.npsValue, + } + ); + }); + + li.addEventListener("click", setSurveyedCookie); + surveyOptions.appendChild(li); + }); + const veryLikely = document.createElement("li"); + veryLikely.textContent = "Very likely"; + veryLikely.classList = "nps-bookend"; + surveyOptions.appendChild(veryLikely); + break; + } + case "pmf": { + const options = [ + "Very disappointed", "Somewhat disappointed", "I wouldn't care", + ]; + options.forEach(option => { + const li = document.createElement("li"); + li.classList = "micro-survey-option"; + li.textContent = option; + li.dataset.eventCategory = "PMF Survey"; + li.dataset.eventAction = "submitted"; + li.dataset.eventLabel = option; + li.addEventListener("click", setSurveyedCookie); + li.addEventListener("click", (evt) => { + const eventData = li.dataset; + ga("send", "event", + eventData.eventCategory, + eventData.eventAction, + eventData.eventLabel, + eventData.eventValue + ); + }); + surveyOptions.appendChild(li); + }); + break; + } + case "usability": + case "credibility": + case "appearance": { + let countMetric = "metric5"; + let rankMetric = "metric6"; + if (surveyType === "credibility") { + countMetric = "metric7"; + rankMetric = "metric8"; + } + if (surveyType === "appearance") { + countMetric = "metric9"; + rankMetric = "metric10"; + } + + const options = [ + "Strongly disagree", "Disagree", "Unsure", "Agree", "Strongly agree", + ]; + let eventValue = 1; + options.forEach(option => { + const li = document.createElement("li"); + li.classList = "micro-survey-option"; + li.textContent = option; + li.dataset.eventCategory = `SUPR-Q Survey ${surveyType}`; + li.dataset.eventAction = "submitted"; + li.dataset.eventLabel = option; + li.dataset.eventValue = eventValue; + li.addEventListener("click", setSurveyedCookie); + li.addEventListener("click", (evt) => { + const eventData = li.dataset; + const gaFieldsObject = { + [countMetric]: 1, + [rankMetric]: eventData.eventValue, + }; + ga("send", "event", + eventData.eventCategory, + eventData.eventAction, + eventData.eventLabel, + eventData.eventValue, + gaFieldsObject + ); + }); + eventValue++; + surveyOptions.appendChild(li); + }); + break; + } + } + resetBodyPadding(); +} + (() => { const win = window; const winLocationSearch = win.location.search; @@ -219,8 +386,7 @@ function setGAListeners(){ setGAListeners(); }, false); - - + analyticsSurveyLogic(); } else { removeUtmsFromUrl(); diff --git a/template-helpers/hbs-helpers.js b/template-helpers/hbs-helpers.js index 42a5bdfba..94c900921 100644 --- a/template-helpers/hbs-helpers.js +++ b/template-helpers/hbs-helpers.js @@ -44,6 +44,71 @@ function recruitmentBanner(args) { return `
${AppConstants.RECRUITMENT_BANNER_TEXT}
`; } +function microsurveyBanner(args) { + // don't show micro survey if we're already showing a recruitment banner + if (AppConstants.RECRUITMENT_BANNER_LINK && AppConstants.RECRUITMENT_BANNER_TEXT) { + return; + } + + // don't show micro survey if language isn't English + // TODO: localize micro survey questions + if (!englishInAcceptLanguages(args)) { + return; + } + + // don't show micro survey if user is not signed in + if (!args.data.root.req.session.user){ + return; + } + + const bannerOpeningDiv = "
"; + const nowSecond = Math.abs(Math.floor(new Date().getTime() / 1000)) % 10; + let surveyElements; + switch (nowSecond) { + case 1: + case 6: { + surveyElements = ` + On a scale from 1-10, how likely are you to recommend Monitor to a friend or colleague? + + `; + break; + } + case 2: + case 7: { + surveyElements = ` + Is Monitor easy to use? + + `; + break; + } + case 3: + case 8: { + surveyElements = ` + Do you feel Monitor is trustworthy? + + `; + break; + } + case 4: + case 9: { + surveyElements = ` + Does Monitor have a clean and simple presentation? + + `; + break; + } + default: { + surveyElements = ` + How would you feel if you could no longer use Monitor? + + `; + break; + } + } + const bannerClosingDev = "
"; + + return [bannerOpeningDiv, surveyElements, bannerClosingDev].join(""); +} function getString (id, args) { const supportedLocales = getSupportedLocales(args); @@ -194,6 +259,7 @@ function breachMath(lValue, operator = null, rValue = null) { module.exports = { recruitmentBanner, + microsurveyBanner, englishInAcceptLanguages, getString, getStrings, diff --git a/views/partials/header/header.hbs b/views/partials/header/header.hbs index b2781e610..78f39da8a 100644 --- a/views/partials/header/header.hbs +++ b/views/partials/header/header.hbs @@ -1,5 +1,6 @@