Browse Source

Added experiment for firefox download promo

Danny Coates 7 years ago
parent
commit
e7fdf76120

+ 25 - 3
app/experiments.js

@@ -1,6 +1,28 @@
 import hash from 'string-hash';
 
-const experiments = {};
+const experiments = {
+  'SyI-hI7gT9agiH-f3f0BYg': {
+    id: 'SyI-hI7gT9agiH-f3f0BYg',
+    run: function(variant, state, emitter) {
+      state.promo = variant === 1 ? 'body' : 'header';
+      emitter.emit('render');
+    },
+    eligible: function() {
+      return (
+        !/firefox/i.test(navigator.userAgent) &&
+        document.querySelector('html').lang === 'en-US'
+      );
+    },
+    variant: function(state) {
+      return this.luckyNumber(state) > 0.5 ? 1 : 0;
+    },
+    luckyNumber: function(state) {
+      return luckyNumber(
+        `${this.id}:${state.storage.get('testpilot_ga__cid')}`
+      );
+    }
+  }
+};
 
 //Returns a number between 0 and 1
 // eslint-disable-next-line no-unused-vars
@@ -32,12 +54,12 @@ export default function initialize(state, emitter) {
       checkExperiments(state, emitter);
     });
   } else {
-    const enrolled = state.storage.enrolled;
-    enrolled.forEach(([id, variant]) => {
+    const enrolled = state.storage.enrolled.filter(([id, variant]) => {
       const xp = experiments[id];
       if (xp) {
         xp.run(variant, state, emitter);
       }
+      return !!xp;
     });
     // single experiment per session for now
     if (enrolled.length === 0) {

+ 1 - 1
app/main.js

@@ -47,4 +47,4 @@ app.use(fileManager);
 app.use(dragManager);
 app.use(experiments);
 
-app.mount('#page-one');
+app.mount('body');

+ 7 - 1
app/metrics.js

@@ -20,7 +20,7 @@ let experiment = null;
 export default function initialize(state, emitter) {
   appState = state;
   emitter.on('DOMContentLoaded', () => {
-    addExitHandlers();
+    // addExitHandlers();
     experiment = storage.enrolled[0];
     sendEvent(category(), 'visit', {
       cm5: storage.totalUploads,
@@ -29,6 +29,9 @@ export default function initialize(state, emitter) {
     });
     //TODO restart handlers... somewhere
   });
+  emitter.on('exit', evt => {
+    exitEvent(evt);
+  });
 }
 
 function category() {
@@ -81,6 +84,8 @@ function urlToMetric(url) {
     case 'https://testpilot.firefox.com/':
     case 'https://testpilot.firefox.com/experiments/send':
       return 'testpilot';
+    case 'https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com':
+      return 'promo';
     default:
       return 'other';
   }
@@ -244,6 +249,7 @@ function exitEvent(target) {
   });
 }
 
+// eslint-disable-next-line no-unused-vars
 function addExitHandlers() {
   const links = Array.from(document.querySelectorAll('a'));
   links.forEach(l => {

+ 36 - 10
app/routes/index.js

@@ -1,17 +1,43 @@
 const choo = require('choo');
+const html = require('choo/html');
 const download = require('./download');
+const header = require('../templates/header');
+const footer = require('../templates/footer');
+const fxPromo = require('../templates/fxPromo');
 
 const app = choo();
 
-app.route('/', require('./home'));
-app.route('/share/:id', require('../templates/share'));
-app.route('/download/:id', download);
-app.route('/download/:id/:key', download);
-app.route('/completed', require('../templates/completed'));
-app.route('/unsupported/:reason', require('../templates/unsupported'));
-app.route('/legal', require('../templates/legal'));
-app.route('/error', require('../templates/error'));
-app.route('/blank', require('../templates/blank'));
-app.route('*', require('../templates/notFound'));
+function body(template) {
+  return function(state, emit) {
+    const b = html`<body>
+      ${state.promo === 'header' ? fxPromo(state, emit) : ''}
+      ${header(state)}
+      <div class="all">
+        <noscript>
+          <h2>Firefox Send requires JavaScript</h2>
+          <p><a href="https://github.com/mozilla/send/blob/master/docs/faq.md#why-does-firefox-send-require-javascript">Why does Firefox Send require JavaScript?</a></p>
+          <p>Please enable JavaScript and try again.</p>
+        </noscript>
+        ${template(state, emit)}
+      </div>
+      ${footer(state)}
+    </body>`;
+    if (state.layout) {
+      return state.layout(state, b);
+    }
+    return b;
+  };
+}
+
+app.route('/', body(require('./home')));
+app.route('/share/:id', body(require('../templates/share')));
+app.route('/download/:id', body(download));
+app.route('/download/:id/:key', body(download));
+app.route('/completed', body(require('../templates/completed')));
+app.route('/unsupported/:reason', body(require('../templates/unsupported')));
+app.route('/legal', body(require('../templates/legal')));
+app.route('/error', body(require('../templates/error')));
+app.route('/blank', body(require('../templates/blank')));
+app.route('*', body(require('../templates/notFound')));
 
 module.exports = app;

+ 1 - 4
app/templates/blank.js

@@ -1,9 +1,6 @@
 const html = require('choo/html');
 
-module.exports = function(state) {
+module.exports = function() {
   const div = html`<div id="page-one"></div>`;
-  if (state.layout) {
-    return state.layout(state, div);
-  }
   return div;
 };

+ 4 - 0
app/templates/completed.js

@@ -1,9 +1,11 @@
 const html = require('choo/html');
 const progress = require('./progress');
 const { fadeOut } = require('../utils');
+const fxPromo = require('./fxPromo');
 
 module.exports = function(state, emit) {
   const div = html`
+  <div id="page-one">
   <div id="download" class="fadeIn">
     <div id="download-progress">
       <div id="dl-title" class="title">${state.translate(
@@ -19,6 +21,8 @@ module.exports = function(state, emit) {
       sendNew
     }>${state.translate('sendYourFilesLink')}</a>
   </div>
+  ${state.promo === 'body' ? fxPromo(state, emit) : ''}
+  </div>
   `;
 
   async function sendNew(e) {

+ 5 - 1
app/templates/download.js

@@ -1,10 +1,12 @@
 const html = require('choo/html');
 const progress = require('./progress');
 const { bytes } = require('../utils');
+const fxPromo = require('./fxPromo');
 
-module.exports = function(state) {
+module.exports = function(state, emit) {
   const transfer = state.transfer;
   const div = html`
+  <div id="page-one">
   <div id="download-progress" class="fadeIn">
     <div id="dl-title" class="title">${state.translate(
       'downloadingPageProgress',
@@ -21,6 +23,8 @@ module.exports = function(state) {
         transfer.sizes
       )}</div>
     </div>
+    </div>
+    ${state.promo === 'body' ? fxPromo(state, emit) : ''}
   </div>
   `;
 

+ 31 - 0
app/templates/footer.js

@@ -0,0 +1,31 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function(state) {
+  return html`<div class="footer">
+    <div class="legal-links">
+      <a href="https://www.mozilla.org" role="presentation"><img class="mozilla-logo" src="${assets.get(
+        'mozilla-logo.svg'
+      )}" alt="mozilla"/></a>
+      <a href="https://www.mozilla.org/about/legal">${state.translate(
+        'footerLinkLegal'
+      )}</a>
+      <a href="https://testpilot.firefox.com/about">${state.translate(
+        'footerLinkAbout'
+      )}</a>
+      <a href="/legal">${state.translate('footerLinkPrivacy')}</a>
+      <a href="/legal">${state.translate('footerLinkTerms')}</a>
+      <a href="https://www.mozilla.org/privacy/websites/#cookies">${state.translate(
+        'footerLinkCookies'
+      )}</a>
+    </div>
+    <div class="social-links">
+      <a href="https://github.com/mozilla/send" role="presentation"><img class="github" src="${assets.get(
+        'github-icon.svg'
+      )}" alt="github"/></a>
+      <a href="https://twitter.com/FxTestPilot" role="presentation"><img class="twitter" src="${assets.get(
+        'twitter-icon.svg'
+      )}" alt="twitter"/></a>
+    </div>
+  </div>`;
+};

+ 44 - 0
app/templates/fxPromo.js

@@ -0,0 +1,44 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+// function replaceLinks(str, urls) {
+//   let i = -1;
+//   const s = str.replace(/<a>([^<]+)<\/a>/g, (m, v) => {
+//     i++;
+//     return `<a class="link" href="${urls[i]}">${v}</a>`;
+//   });
+//   return [`<span>${s}</span>`];
+// }
+
+module.exports = function(state, emit) {
+  // function close() {
+  //   document.querySelector('.banner').remove();
+  // }
+
+  function clicked(evt) {
+    emit('exit', evt);
+  }
+
+  return html`
+    <div class="banner">
+      <div>
+        <img
+        src="${assets.get('firefox_logo-only.svg')}"
+        class="firefox-logo-small"
+        alt="Firefox"/>
+        <span>Send is brought to you by the all-new Firefox.
+        <a
+          class="link"
+          href="https://www.mozilla.org/firefox/new/?utm_campaign=send-acquisition&utm_medium=referral&utm_source=send.firefox.com"
+          onclick=${clicked}
+          >Download Firefox now ≫</a></span>
+      </div>
+    </div>`;
+};
+
+/*
+<img
+  src="${assets.get('close-16.svg')}"
+  class="icon-delete"
+  onclick=${close}>
+*/

+ 21 - 0
app/templates/header.js

@@ -0,0 +1,21 @@
+const html = require('choo/html');
+const assets = require('../../common/assets');
+
+module.exports = function(state) {
+  return html`<header class="header">
+  <div class="send-logo">
+    <a href="/">
+      <img src="${assets.get(
+        'send_logo.svg'
+      )}" alt="Send"/><h1 class="site-title">Send</h1>
+    </a>
+    <div class="site-subtitle">
+      <a href="https://testpilot.firefox.com">Firefox Test Pilot</a>
+      <div>${state.translate('siteSubtitle')}</div>
+    </div>
+  </div>
+  <a href="https://qsurvey.mozilla.com/s3/txp-firefox-send" rel="noreferrer noopener" class="feedback" target="_blank">${state.translate(
+    'siteFeedback'
+  )}</a>
+</header>`;
+};

Some files were not shown because too many files changed in this diff