Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

Fixes #4724 - Add image editor new feature promotion dialog #4750

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/METRICS.md
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,7 @@ These are events that an add-on user can encounter on a shot they own
32. [x] Click the download button `web/download/navbar`
33. [x] Visit an image directly, when the image isn't embedded directly in a Screenshots shot page, `web/visit/direct-view-owner`
34. [x] View an image directly, when the image is being shown as part of a Facebook/Twitter style preview (the og:image or twitter:image), `web/visit/direct-view-embedded-owner`
35. [x] Close new edit tools promotion dialog, `web/promo-closed`

#### Shot Index (My Shots)

Expand Down
8 changes: 8 additions & 0 deletions locales/en-US/server.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,14 @@ timeDiffFutureDays = { $number ->

errorThirdPartyCookiesEnabled = If you took this shot and cannot delete it, you may need to temporarily enable third party cookies from your browser’s preferences.

## Shot Page New Feature Promotion Dialog.
# Note: If possible, choose a short translation to better fit into the card.
promoTitle = Take Note!
promoMessage = Updated editing tools let you crop, highlight, and even add text to your shot.
promoLink = Give them a try
promoCloseButton =
.title = Close notification

## Annotations

annotationPenButton =
Expand Down
17 changes: 17 additions & 0 deletions server/src/pages/shot/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,22 @@ function shouldHighlightEditIcon(model) {
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;
}

exports.launch = function(data) {
const firstSet = !model;
model = data;
Expand Down Expand Up @@ -57,6 +73,7 @@ exports.launch = function(data) {
}
}
model.highlightEditButton = shouldHighlightEditIcon(model);
model.promoDialog = shouldShowPromo(model);
if (firstSet) {
refreshHash();
}
Expand Down
40 changes: 40 additions & 0 deletions server/src/pages/shot/promo-dialog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const React = require("react");
const PropTypes = require("prop-types");
const { Localized } = require("fluent-react/compat");
const sendEvent = require("../../browser-send-event.js");

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

render() {
if (this.props.display) {
return <div id="promo-dialog-panel" className="promo-panel default-color-scheme" >
<Localized id="promoCloseButton">
<a className="box-close" title="Close notification" onClick={this.closePanel.bind(this)}></a>
</Localized>
<Localized id="promoTitle">
<h4 className="title">Take Note!</h4>
</Localized>
<Localized id="promoMessage">
<p className="message">
Updated editing tools let you crop, highlight, and even add text to your shot.
</p>
</Localized>
<p className="message">✨<Localized id="promoLink"><span className="message-text">Give them a try</span></Localized>✨</p>
</div>;
}
return null;
}

closePanel(event) {
this.props.promoClose();
sendEvent("promo-closed");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever a new metrics event is added, it should be documented in https://github.com/mozilla-services/screenshots/blob/master/docs/METRICS.md. Sorry I didn't catch this sooner.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}
};

exports.PromoDialog.propTypes = {
display: PropTypes.bool,
promoClose: PropTypes.func
};
26 changes: 22 additions & 4 deletions server/src/pages/shot/view.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const { Localized } = require("fluent-react/compat");
const { Footer } = require("../../footer-view");
const sendEvent = require("../../browser-send-event.js");
const { ShareButton } = require("../../share-buttons");
const { PromoDialog } = require("./promo-dialog");
const { DeleteShotButton } = require("../../delete-shot-button");
const { TimeDiff } = require("./time-diff");
const reactruntime = require("../../reactruntime");
Expand Down Expand Up @@ -181,7 +182,8 @@ class Body extends React.Component {
}

componentDidMount() {
this.setState({highlightEditButton: this.props.highlightEditButton});
this.setState({highlightEditButton: this.props.highlightEditButton || this.props.promoDialog});
this.setState({promoDialog: this.props.promoDialog});
}

doCloseBanner() {
Expand Down Expand Up @@ -358,9 +360,13 @@ class Body extends React.Component {
clickDeleteHandler={ this.clickDeleteHandler.bind(this) }
confirmDeleteHandler={ this.confirmDeleteHandler.bind(this) }
cancelDeleteHandler={ this.cancelDeleteHandler.bind(this) } />;
editButton = <Localized id="shotPageEditButton">
<button className="button transparent edit" title="Edit this image" onClick={ this.onClickEdit.bind(this) } ref={(edit) => { this.editButton = edit; }}></button>
</Localized>;

editButton = <div className="edit-shot-button">
<Localized id="shotPageEditButton">
<button className="button transparent edit" title="Edit this image" onClick={ this.onClickEdit.bind(this) } ref={(edit) => { this.editButton = edit; }}></button>
</Localized>
<PromoDialog promoClose={this.promoClose.bind(this)} display={this.state.promoDialog} />
</div>;
} else {
trashOrFlagButton = <Localized id="shotPageAbuseButton">
<button className="button transparent flag" title="Report this shot for abuse, spam, or other problems" onClick={ this.onClickFlag.bind(this) }></button>
Expand Down Expand Up @@ -408,6 +414,7 @@ class Body extends React.Component {

const noText = this.props.abTests && this.props.abTests.downloadText
&& this.props.abTests.downloadText.value === "no-download-text";

return (
<reactruntime.BodyTemplate {...this.props}>
{ renderGetFirefox ? this.renderFirefoxRequired() : null }
Expand Down Expand Up @@ -452,6 +459,12 @@ class Body extends React.Component {
</reactruntime.BodyTemplate>);
}

promoClose() {
this.setState({promoDialog: false});
// set counter to max to stop showing notification again
localStorage.hasSeenPromoDialog = 3;
}

onMouseOverHighlight() {
this.editButton.style.backgroundColor = "#ededf0";
}
Expand Down Expand Up @@ -480,6 +493,10 @@ class Body extends React.Component {
this.setState({imageEditing: true});
sendEvent("start-annotations", "navbar");
}
// Close promo dialog if user clicked edit after seeing new edit tool promo
if (this.props.promoDialog) {
this.promoClose();
}
}

onClickSave(dataUrl, dimensions) {
Expand Down Expand Up @@ -555,6 +572,7 @@ Body.propTypes = {
enableAnnotations: PropTypes.bool,
expireTime: PropTypes.number,
highlightEditButton: PropTypes.bool,
promoDialog: PropTypes.bool,
id: PropTypes.string,
isExtInstalled: PropTypes.bool,
isMobile: PropTypes.bool,
Expand Down
50 changes: 50 additions & 0 deletions static/css/frame.scss
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,61 @@
}
}

.promo-panel {
position: absolute;
top: 45px;
right: -45px;
border-radius: 3px;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3), 0 0 20px rgba(0, 0, 0, 0.2);
width: 150px;
z-index: 999;
padding: 5px;
text-align: center;

.title {
font-size: 14px;
line-height: 14px;
margin: 5px;
}

.message {
font-size: 12px;
margin: 5px 2px;
}

.message-text {
margin: 0 2px;
}

a.box-close {
position: absolute;
top: 2px;
right: 2px;
cursor: pointer;
color: $black;
width: 15px;
height: 15px;
line-height: 12px;
}

.box-close:before {
content: "×";
}

.box-close:hover {
background-color: $light-hover;
}
}

.shot-alt-actions {
#downloadIcon {
margin-right: 4px;
}

.edit-shot-button {
position: relative;
}

@include respond-to("small") {
padding-right: $grid-unit * 0.5;

Expand Down