Skip to content

Commit

Permalink
Fixes mozilla-services#4790 - NonFxA Shot takers should be briefly on…
Browse files Browse the repository at this point in the history
…boarded
  • Loading branch information
punamdahiya committed Nov 9, 2018
1 parent 6d13320 commit f1ca077
Show file tree
Hide file tree
Showing 21 changed files with 353 additions and 57 deletions.
2 changes: 2 additions & 0 deletions docs/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ These are events that an add-on user can encounter on a shot they own
37. [x] Remove shot from favorites `web-unset-favorite/navbar`
38. [x] Signin to Firefox Accounts `web/fxa-signin`
39. [x] Signin to Firefox Accounts from banner `web/fxa-signin-ad-banner`
40. [x] Signin to Firefox Accounts from onboarding promo `web/fxa-signin-onboarding-promo`
41. [x] Click on dismiss of Firefox Accounts onboarding promo `web/onboarding-promo-closed`

#### Shot Index (My Shots)

Expand Down
11 changes: 11 additions & 0 deletions locales/en-US/server.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,17 @@ screenshotsLogo =
bannerSignIn = <a>Sign in or sign up</a> to access your shots across devices and save your favorites forever.
bannerUpsell = {gScreenshotsDescription} <a>Get Firefox now</a>
# Text used in Firefox Account onboarding promo shown below
# Sign in button in header
onboardingPromoTitle = What’s new with Firefox Screenshots?
onboardingPromoMessage = Now, sign in to Screenshots with a Firefox Account and do more:
onboardingPromoMessageListItem1 = Access your library on all of your devices
onboardingPromoMessageListItem2 = Store your favorite shots forever
onboardingPromoDismissButton = Dismiss
.title = Dismiss
onboardingPromoSigninButton = Sign in
.title = Sign in
## Footer

# Note: link text for a link to mozilla.org
Expand Down
6 changes: 4 additions & 2 deletions server/src/ad-banner.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const React = require("react");
const PropTypes = require("prop-types");
const { Localized } = require("fluent-react/compat");
const sendEvent = require("./browser-send-event.js");
const { PromotionStrategy } = require("./promotion-strategy.js");

exports.AdBanner = class AdBanner extends React.Component {
constructor(props) {
Expand All @@ -18,8 +19,9 @@ exports.AdBanner = class AdBanner extends React.Component {

render() {
let bannerContent = null;
const promoStrategy = new PromotionStrategy();

if (this.props.shouldGetFirefox && !this.props.isOwner) {
if (promoStrategy.shouldShowFirefoxBanner(this.props.shouldGetFirefox, this.props.isOwner)) {
const upsellLink = <a className="upsellLink"
href="https://www.mozilla.org/firefox/new/?utm_source=screenshots.firefox.com&utm_medium=referral&utm_campaign=screenshots-acquisition&utm_content=from-shot"
onClick={ this.clickedInstallFirefox.bind(this) }>Get Firefox now</a>;
Expand All @@ -28,7 +30,7 @@ exports.AdBanner = class AdBanner extends React.Component {
Screenshots made simple. Take, save and share screenshots without leaving Firefox. {upsellLink}
</p>
</Localized>;
} else if (!this.props.hasFxa) {
} else if (promoStrategy.shouldShowFxaBanner(this.props.hasFxa)) {
const signInLink = <a className="signInLink"
href="/api/fxa-oauth/login/shots"
onClick={ this.clickedSignIn.bind(this) }></a>;
Expand Down
66 changes: 66 additions & 0 deletions server/src/fxa-onboarding-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
const React = require("react");
const PropTypes = require("prop-types");
const { Localized } = require("fluent-react/compat");
const sendEvent = require("./browser-send-event.js");

exports.FxaOnboardingDialog = class FxaOnboardingDialog extends React.Component {
constructor(props) {
super(props);
}

render() {
if (this.props.display) {
return <div className="onboarding-promo-dialog right-align">
<div className="triangle"><div className="triangle-inner"></div></div>
<div className="promo-header">
<span className="promo-logo" />
<Localized id="onboardingPromoTitle">
<span className="promo-title">What’s new with Firefox Screenshots?</span>
</Localized>
</div>
<div className="promo-message">
<Localized id="onboardingPromoMessage">
<p>
Now, sign in to Screenshots with a Firefox Account and
do more:
</p>
</Localized>
<ul>
<Localized id="onboardingPromoMessageListItem1">
<li>Access your library on all of your devices</li>
</Localized>
<Localized id="onboardingPromoMessageListItem2">
<li>Store your favorite shots forever</li>
</Localized>
</ul>
</div>
<div className="promo-footer">
<Localized id="onboardingPromoDismissButton" attrs={{title: true}}>
<a href="#" title="Dismiss" onClick={ this.onCloseDialog.bind(this) }>Dismiss</a>
</Localized>
<Localized id="onboardingPromoSigninButton" attrs={{title: true}}>
<button className="button primary" title="Sign in" onClick={ this.onConfirm.bind(this) }>Sign in</button>
</Localized>
</div>
</div>;
}
return null;
}

onCloseDialog(event) {
this.props.hideDialog();
sendEvent("onboarding-promo-closed");
}

onConfirm(event) {
this.props.hideDialog();
sendEvent("fxa-signin-onboarding-promo");
location.href = this.props.logInURI;
}
};

exports.FxaOnboardingDialog.propTypes = {
logInURI: PropTypes.string,
display: PropTypes.bool,
hideDialog: PropTypes.func,
};
9 changes: 8 additions & 1 deletion server/src/header.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,14 @@ exports.Header = function Header(props) {
</Localized>
</div> : null;

const banner = !props.hasFxaOnboardingDialog ?
<AdBanner key="banner"
isOwner={props.isOwner}
hasFxa={props.hasFxa}
shouldGetFirefox={props.shouldGetFirefox} /> : null;

return [
<AdBanner key="banner" isOwner={props.isOwner} hasFxa={props.hasFxa} shouldGetFirefox={props.shouldGetFirefox} />,
banner,
<header key="header" className="header-panel">
{logo}
{props.children}
Expand All @@ -25,4 +31,5 @@ exports.Header.propTypes = {
isOwner: PropTypes.bool,
hasFxa: PropTypes.bool,
shouldGetFirefox: PropTypes.bool,
hasFxaOnboardingDialog: PropTypes.bool,
};
2 changes: 2 additions & 0 deletions server/src/pages/homepage/controller.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* globals Mozilla */
const page = require("./page").page;
const { PromotionStrategy } = require("../../promotion-strategy.js");

let model;

Expand All @@ -15,6 +16,7 @@ exports.launch = function(m) {
});
}
}
model.hasFxaOnboardingDialog = new PromotionStrategy().shouldShowOnboardingDialog();
render();
};

Expand Down
7 changes: 5 additions & 2 deletions server/src/pages/homepage/homepage-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ exports.HomePageHeader = class HomePageHeader extends React.Component {
renderFxASignIn() {
return (
<SignInButton isFxaAuthenticated={this.props.hasFxa} initialPage=""
staticLink={this.props.staticLink} />
staticLink={this.props.staticLink}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog} />
);
}

Expand All @@ -34,7 +35,8 @@ exports.HomePageHeader = class HomePageHeader extends React.Component {

const signin = this.renderFxASignIn();
return (
<Header hasLogo={true} isOwner={this.props.isOwner} hasFxa={this.props.hasFxa}>
<Header hasLogo={true} isOwner={this.props.isOwner} hasFxa={this.props.hasFxa}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog}>
<div className="alt-actions">
{ myShots }
{ signin }
Expand All @@ -48,4 +50,5 @@ exports.HomePageHeader.propTypes = {
hasFxa: PropTypes.bool,
isOwner: PropTypes.bool,
staticLink: PropTypes.func,
hasFxaOnboardingDialog: PropTypes.bool,
};
1 change: 1 addition & 0 deletions server/src/pages/homepage/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class Body extends React.Component {
isOwner={this.props.authenticated}
hasFxa={this.props.hasFxa}
staticLink={this.props.staticLink}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog}
/>
<div className="banner">
<div className="banner-image-back" />
Expand Down
38 changes: 9 additions & 29 deletions server/src/pages/shot/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,37 +5,11 @@ const page = require("./page").page;
const { AbstractShot } = require("../../../shared/shot");
const { createThumbnailUrl } = require("../../../shared/thumbnailGenerator");
const { shotGaFieldForValue } = require("../../ab-tests.js");
const { PromotionStrategy } = require("../../promotion-strategy.js");

// This represents the model we are rendering:
let model;

function shouldHighlightEditIcon(model) {
if (!model.isOwner) {
return false;
}
const hasSeen = localStorage.hasSeenEditButton;
if (!hasSeen && model.enableAnnotations) {
localStorage.hasSeenEditButton = "1";
}
return !hasSeen;
}

function shouldShowPromo(model) {
if (!model.isOwner || !model.enableAnnotations) {
return false;
}
let show = false;
const count = localStorage.hasSeenPromoDialog;
if (!count) {
localStorage.hasSeenPromoDialog = 1;
show = true;
} else if (count < 3) {
localStorage.hasSeenPromoDialog = parseInt(count, 10) + 1;
show = true;
}
return show;
}

function updateModel(authData) {
Object.assign(model, authData);
model.isExtInstalled = true;
Expand Down Expand Up @@ -75,8 +49,14 @@ exports.launch = function(data) {
}
}
}
model.highlightEditButton = shouldHighlightEditIcon(model);
model.promoDialog = shouldShowPromo(model);

const promoStrategy = new PromotionStrategy();

model.hasFxaOnboardingDialog = promoStrategy.shouldShowOnboardingDialog(model.isOwner, true);
model.highlightEditButton =
promoStrategy.shouldHighlightEditIcon(model.isOwner, model.enableAnnotations);
model.promoDialog =
promoStrategy.shouldShowEditToolPromotion(model.isOwner, model.enableAnnotations, model.hasFxaOnboardingDialog);

if (firstSet) {
refreshHash();
Expand Down
10 changes: 5 additions & 5 deletions server/src/pages/shot/shotpage-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,10 +90,9 @@ exports.ShotPageHeader = class ShotPageHeader extends React.Component {
renderFxASignIn() {
if (this.props.isOwner) {
return (
<div className="shot-fxa-signin">
<SignInButton isFxaAuthenticated={this.props.hasFxa} initialPage={this.props.shot.id}
staticLink={this.props.staticLink} />
</div>
<SignInButton isFxaAuthenticated={this.props.hasFxa} initialPage={this.props.shot.id}
staticLink={this.props.staticLink}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog} />
);
}
return null;
Expand All @@ -114,7 +113,7 @@ exports.ShotPageHeader = class ShotPageHeader extends React.Component {

return (
<Header shouldGetFirefox={this.props.shouldGetFirefox} isOwner={this.props.isOwner}
hasFxa={this.props.hasFxa}>
hasFxa={this.props.hasFxa} hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog}>
{ myShotsText }
{ shotInfo }
{ shotActions }
Expand All @@ -134,6 +133,7 @@ exports.ShotPageHeader.propTypes = {
shouldGetFirefox: PropTypes.bool,
shotActions: PropTypes.array,
staticLink: PropTypes.func,
hasFxaOnboardingDialog: PropTypes.bool,
};

class EditableTitle extends React.Component {
Expand Down
3 changes: 2 additions & 1 deletion server/src/pages/shot/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,8 @@ class Body extends React.Component {
<div id="frame" className="inverse-color-scheme full-height column-space">
<ShotPageHeader isOwner={this.props.isOwner} hasFxa={this.props.hasFxa}
shot={this.props.shot} expireTime={this.props.expireTime} shouldGetFirefox={renderGetFirefox}
staticLink={this.props.staticLink} shotActions={shotActions}>
staticLink={this.props.staticLink} shotActions={shotActions}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog}>
{ !this.props.isOwner ? downloadButton : null }
</ShotPageHeader>
<section className="clips">
Expand Down
6 changes: 6 additions & 0 deletions server/src/pages/shotindex/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const sendEvent = require("../../browser-send-event.js");
const page = require("./page").page;
const { AbstractShot } = require("../../../shared/shot");
const queryString = require("query-string");
const { PromotionStrategy } = require("../../promotion-strategy.js");

const FIVE_SECONDS = 5 * 1000;

Expand Down Expand Up @@ -65,6 +66,11 @@ exports.launch = function(m) {
// The actual shot data hasn't been loaded yet, so we'll immediately request it:
refreshModel();
}

if (!firstRun) {
model.hasFxaOnboardingDialog = new PromotionStrategy().shouldShowOnboardingDialog();
}

firstRun = false;
render();
};
Expand Down
7 changes: 5 additions & 2 deletions server/src/pages/shotindex/myshots-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ exports.MyShotsHeader = function MyShotsHeader(props) {
const signin = props.enableUserSettings && props.authenticated ?
<SignInButton
isFxaAuthenticated={props.hasFxa} initialPage="shots"
staticLink={props.staticLink} /> : null;
staticLink={props.staticLink}
hasFxaOnboardingDialog={props.hasFxaOnboardingDialog} /> : null;

return (
<Header hasLogo={true} isOwner={props.authenticated} hasFxa={props.hasFxa}>
<Header hasLogo={true} isOwner={props.authenticated} hasFxa={props.hasFxa}
hasFxaOnboardingDialog={props.hasFxaOnboardingDialog}>
<div className="alt-actions">
{ signin }
</div>
Expand All @@ -23,4 +25,5 @@ exports.MyShotsHeader.propTypes = {
authenticated: PropTypes.bool,
enableUserSettings: PropTypes.bool,
staticLink: PropTypes.func,
hasFxaOnboardingDialog: PropTypes.bool,
};
3 changes: 2 additions & 1 deletion server/src/pages/shotindex/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,8 @@ class Body extends React.Component {
<div className="column-space full-height" id="shot-index-page">
<MyShotsHeader
authenticated={this.props.authenticated} hasFxa={this.props.hasFxa}
enableUserSettings={this.props.enableUserSettings} staticLink={this.props.staticLink} />
enableUserSettings={this.props.enableUserSettings} staticLink={this.props.staticLink}
hasFxaOnboardingDialog={this.props.hasFxaOnboardingDialog} />
{ this.props.disableSearch ? null : this.renderSearchForm() }
<div id="shot-index" className="flex-1">
{ this.renderShots() }
Expand Down
Loading

0 comments on commit f1ca077

Please sign in to comment.