Skip to content

Commit

Permalink
Merge pull request mozilla#1323 from dannycoates/1303-completed-exper…
Browse files Browse the repository at this point in the history
…iments-addon

'Completed Experiment' addon changes
  • Loading branch information
lmorchard authored Sep 23, 2016
2 parents de72a87 + 74b26e6 commit b1c990e
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 12 deletions.
47 changes: 42 additions & 5 deletions addon/lib/survey.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ module.exports = {init, destroy, launchSurvey};

// set timecheck flags for initial run.
if (store.surveyChecks === undefined) store.surveyChecks = {};
['twoDaysSent', 'oneWeekSent', 'threeWeeksSent', 'monthAndAHalfSent'].forEach(k => {
['twoDaysSent', 'oneWeekSent', 'threeWeeksSent', 'monthAndAHalfSent', 'eol'].forEach(k => {
if (store.surveyChecks[k] === undefined) store.surveyChecks[k] = {};
});

function init() {
if (checkForCompletedExperiments()) { return; }
// wait about 10 minutes before prompting user for survey
setTimeout(() => {
// Only check/ask for survey if the user has addons installed.
Expand All @@ -40,6 +41,38 @@ function init() {
}, TEN_MINUTES);
}

function checkForCompletedExperiments() {
if (store.installedAddons) {
const now = Date.now();
const ids = Object.keys(store.installedAddons);
const eolSurveys = [];
for (let id of ids) { // eslint-disable-line prefer-const
let x = store.installedAddons[id]; // eslint-disable-line prefer-const
if (x.active &&
(new Date(x.completed)).getTime() < now &&
!(id in store.surveyChecks.eol)) {
eolSurveys.push(x);
}
}
const experiment = eolSurveys[Math.floor(Math.random() * eolSurveys.length)];
if (experiment) {
tabs.once('open', tab => { // eslint-disable-line no-unused-vars
setTimeout(() =>
launchSurvey({
experiment,
interval: 'eol',
label: `The ${experiment.title} experiment has ended. What did you think?`,
persistence: 10
}),
1000
);
});
return true;
}
}
return false;
}

function destroy() {
delete store.surveyChecks;
}
Expand Down Expand Up @@ -75,13 +108,14 @@ function checkInstallDate(installDate, addonId) {
return false;
}

function launchSurvey(experiment, interval) {
showRating({ experiment })
function launchSurvey(options) {
const { experiment, interval } = options;
showRating(options)
.then(
rating => {
if (!rating) { return Promise.resolve(); }
// TODO: add telemetry ping for rating
return showSurveyButton({ experiment })
return showSurveyButton(options)
.then(clicked => {
if (clicked) {
const urlParams = {
Expand Down Expand Up @@ -180,12 +214,15 @@ function showRating(options) {
let experimentRating = null;

const { notifyBox, box } = createNotificationBox({
label: `Please rate ${experiment.title}`,
label: options.label || `Please rate ${experiment.title}`,
image: experiment.thumbnail,
child: win => createRatingUI(win, uiClosed),
persistence: options.persistence,
pulse: true,
callback: () => {
if (options.interval === 'eol' && experimentRating === null) {
store.surveyChecks.eol[experiment.addon_id] = true;
}
clearTimeout(uiTimeout);
resolve(experimentRating);
}
Expand Down
2 changes: 1 addition & 1 deletion addon/lib/templates.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
module.exports.experimentList = `
<div class="experiment-list">
{{#experiments}}
<a class="experiment-item {{#active}}active{{/active}} {{#isNew}}is-new{{/isNew}}" href="{{base_url}}/experiments/{{slug}}?{{params}}">
<a class="experiment-item {{#active}}active{{/active}} {{#isNew}}is-new{{/isNew}}" href="{{link}}?{{params}}">
<div class="icon-wrapper"
style="background-color:{{gradient_start}}; background-image: linear-gradient(300deg, {{gradient_start}}, {{gradient_stop}})">
<div class="icon" style="background-image:url('{{thumbnail}}');"></div>
Expand Down
40 changes: 34 additions & 6 deletions addon/lib/toolbar-button.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const querystring = require('sdk/querystring');
const store = require('sdk/simple-storage').storage;
const tabs = require('sdk/tabs');
const self = require('sdk/self');
const { URL } = require('sdk/url');

const Mustache = require('mustache');
const templates = require('./templates');
Expand Down Expand Up @@ -38,12 +39,21 @@ function getExperimentList(availableExperiments, installedAddons) {
const created = (new Date(experiment.created)).getTime();
experiment.isNew = (now - created) < NEW_EXPERIMENT_PERIOD && !experiment.active;
experiment.params = getParams();
experiment.link = experiment.html_url;

if (experiment.completed) {
const completed = (new Date(experiment.completed)).getTime();
const delta = completed - Date.now();
if (delta < 0) {
experiment.eolMessage = 'Experiment Complete';
if (experiment.active &&
!(experiment.addon_id in store.surveyChecks.eol)) {
experiment.link = experiment.survey_url;
experiment.params = querystring.stringify({
id: experiment.addon_id,
interval: 'eol',
installed: Object.keys(store.installedAddons)});
}
} else if (delta < ONE_DAY) {
experiment.eolMessage = 'Ending Tomorrow';
} else if (delta < ONE_WEEK) {
Expand All @@ -55,7 +65,8 @@ function getExperimentList(availableExperiments, installedAddons) {
}
}
return experiment;
});
})
.filter(x => x.active || !x.completed); // remove inactive, completed experiments

// Sort new experiments to the top, otherwise sort by reverse-chronological
experiments.sort((a, b) => {
Expand All @@ -64,6 +75,10 @@ function getExperimentList(availableExperiments, installedAddons) {
return b.modified - a.modified;
});

return experiments;
}

function render(experiments) {
return Mustache.render(templates.experimentList, {
base_url: settings.BASE_URL,
view_all_params: getParams('view-all-experiments'),
Expand All @@ -72,8 +87,7 @@ function getExperimentList(availableExperiments, installedAddons) {
}

function showExperimentList() {
panel.port.emit('show', getExperimentList(store.availableExperiments || {},
store.installedAddons || {}));
panel.port.emit('show', render(panel.experiments));

// HACK: Record toolbar button click here, so that badging state is
// unchanged until after rendering the panel's instrumented links.
Expand All @@ -93,16 +107,26 @@ function getParams() {
function handleButtonChange(state) {
if (state.checked) {
Metrics.pingTelemetry('txp_toolbar_menu_1', 'clicked', Date.now());
const experimentCount = ('availableExperiments' in store) ?
Object.keys(store.availableExperiments).length : 0;
panel.experiments = getExperimentList(
store.availableExperiments || {},
store.installedAddons || {});

panel.show({
width: PANEL_WIDTH,
height: (experimentCount * EXPERIMENT_HEIGHT) + FOOTER_HEIGHT,
height: (panel.experiments.length * EXPERIMENT_HEIGHT) + FOOTER_HEIGHT,
position: button
});
}
}

function checkSurvey(url) {
// HACK an id field is currently unique to survey_urls
const addonId = querystring.parse(URL(url).search.substring(1)).id; // eslint-disable-line new-cap
if (addonId) {
store.surveyChecks.eol[addonId] = true;
}
}

const ToolbarButton = module.exports = {

init: function(settingsIn) {
Expand All @@ -127,6 +151,10 @@ const ToolbarButton = module.exports = {
panel.port.on('back', showExperimentList);
panel.port.on('link', url => {
// TODO: Record metrics event here, along with badge context

// if survey_url note survey as taken
checkSurvey(url);

tabs.open(url);
panel.hide();
});
Expand Down

0 comments on commit b1c990e

Please sign in to comment.