Merge pull request #139 from rschamp/feature/email-confirmation-banner

Add email confirmation banner to homepage
This commit is contained in:
Ray Schamp 2015-10-25 12:19:42 -04:00
commit b7f795f2d9
7 changed files with 195 additions and 55 deletions

View file

@ -0,0 +1,29 @@
var classNames = require('classnames');
var React = require('react');
require('./banner.scss');
var Banner = React.createClass({
type: 'Banner',
propTypes: {
onRequestDismiss: React.PropTypes.func
},
render: function () {
var classes = classNames(
'banner',
this.props.className
);
return (
<div className={classes}>
<div className="inner">
{this.props.children}
{this.props.onRequestDismiss ? [
<a className="close" key="close" href="#" onClick={this.props.onRequestDismiss}>x</a>
] : []}
</div>
</div>
);
}
});
module.exports = Banner;

View file

@ -0,0 +1,41 @@
@import "../../colors";
$navigation-height: 50px;
.banner {
position: fixed;
top: $navigation-height;
z-index: 99;
box-shadow: 0 1px 1px $ui-dark-gray;
background-color: $ui-orange;
width: 100%;
overflow: hidden;
text-align: center;
line-height: $navigation-height;
&, a {
color: $ui-white;
}
a {
text-decoration: underline;
}
.close {
float: right;
margin-top: $navigation-height/4;
border-radius: $navigation-height/4;
background-color: $box-shadow-gray;
width: $navigation-height/2;
height: $navigation-height/2;
text-decoration: none;
text-shadow: none;
line-height: $navigation-height/2;
color: $ui-white;
font-weight: normal;
}
&.warning {
background-color: $ui-orange;
}
}

View file

@ -1,3 +1,4 @@
var classNames = require('classnames');
var React = require('react');
require('./box.scss');
@ -11,8 +12,12 @@ var Box = React.createClass({
moreProps: React.PropTypes.object
},
render: function () {
var classes = classNames(
'box',
this.props.className
);
return (
<div className={'box ' + this.props.className}>
<div className={classes}>
<div className="box-header">
<h4>{this.props.title}</h4>
<p>

View file

@ -1,3 +1,4 @@
var classNames = require('classnames');
var defaults = require('lodash.defaults');
var React = require('react');
var Slider = require('react-slick');
@ -31,9 +32,12 @@ var Carousel = React.createClass({
variableWidth: true
});
var arrows = this.props.items.length > settings.slidesToShow;
var classes = classNames(
'carousel',
this.props.className
);
return (
<Slider className={'carousel ' + this.props.className} arrows={arrows} {... settings}>
<Slider className={classes} arrows={arrows} {... settings}>
{this.props.items.map(function (item) {
var href = '';
switch (item.type) {

View file

@ -317,7 +317,7 @@ var Navigation = React.createClass({
</ul>
<Modal isOpen={this.state.canceledDeletionOpen}
onRequestClose={this.closeCanceledDeletion}
frameSettings={{padding: 15}}>
style={{content:{padding: 15}}}>
<h4>Your Account Will Not Be Deleted</h4>
<p>
Your account was scheduled for deletion but you logged in. Your account has been reactivated.

View file

@ -1,3 +1,4 @@
var classNames = require('classnames');
var React = require('react');
var render = require('../../lib/render.jsx');
@ -20,9 +21,13 @@ var Hoc = React.createClass({
});
},
render: function () {
var classes = classNames(
'top-banner',
this.state.bgClass
);
return (
<div>
<div className={'top-banner ' + this.state.bgClass}>
<div className={classes}>
<h1>Get Creative with Coding</h1>
<p>
With Scratch, you can program your own stories, games, and animations

View file

@ -1,4 +1,5 @@
var injectIntl = require('react-intl').injectIntl;
var omit = require('lodash.omit');
var React = require('react');
var render = require('../../lib/render.jsx');
@ -7,10 +8,12 @@ var Session = require('../../mixins/session.jsx');
var Activity = require('../../components/activity/activity.jsx');
var AdminPanel = require('../../components/adminpanel/adminpanel.jsx');
var Banner = require('../../components/banner/banner.jsx');
var Box = require('../../components/box/box.jsx');
var Button = require('../../components/forms/button.jsx');
var Carousel = require('../../components/carousel/carousel.jsx');
var Intro = require('../../components/intro/intro.jsx');
var Modal = require('../../components/modal/modal.jsx');
var News = require('../../components/news/news.jsx');
var Welcome = require('../../components/welcome/welcome.jsx');
@ -28,7 +31,8 @@ var Splash = injectIntl(React.createClass({
activity: [],
news: [],
featuredCustom: {},
featuredGlobal: {}
featuredGlobal: {},
showEmailConfirmationModal: false
};
},
componentDidUpdate: function (prevProps, prevState) {
@ -43,6 +47,11 @@ var Splash = injectIntl(React.createClass({
this.setState({news: []});
this.getProjectCount();
}
if (this.shouldShowEmailConfirmation()) {
window.addEventListener('message', this.onMessage);
} else {
window.removeEventListener('message', this.onMessage);
}
}
},
componentDidMount: function () {
@ -54,6 +63,22 @@ var Splash = injectIntl(React.createClass({
} else {
this.getProjectCount();
}
if (this.shouldShowEmailConfirmation()) window.addEventListener('message', this.onMessage);
},
componentWillUnmount: function () {
window.removeEventListener('message', this.onMessage);
},
onMessage: function (e) {
if (e.origin != window.location.origin) return;
if (e.source != this.refs.emailConfirmationiFrame.contentWindow) return;
if (e.data == 'resend-done') {
this.hideEmailConfirmationModal();
} else {
var data = JSON.parse(e.data);
if (data['action'] === 'leave-page') {
window.location.href = data['uri'];
}
}
},
getActivity: function () {
this.api({
@ -90,6 +115,12 @@ var Splash = injectIntl(React.createClass({
if (!err) this.setState({projectCount: body.count});
}.bind(this));
},
showEmailConfirmationModal: function () {
this.setState({emailConfirmationModalOpen: true});
},
hideEmailConfirmationModal: function () {
this.setState({emailConfirmationModalOpen: false});
},
handleDismiss: function (cue) {
this.api({
host: '',
@ -108,6 +139,11 @@ var Splash = injectIntl(React.createClass({
new Date(new Date - 2*7*24*60*60*1000) // Two weeks ago
);
},
shouldShowEmailConfirmation: function () {
return (
this.state.session.user && this.state.session.flags.has_outstanding_email_confirmation &&
this.state.session.flags.confirm_email_banner);
},
renderHomepageRows: function () {
var formatMessage = this.props.intl.formatMessage;
@ -249,58 +285,78 @@ var Splash = injectIntl(React.createClass({
},
render: function () {
var featured = this.renderHomepageRows();
var emailConfirmationStyle = {width: 500, height: 330, padding: 1};
return (
<div className="inner">
{this.state.session.user ? [
<div key="header" className="splash-header">
{this.shouldShowWelcome() ? [
<Welcome key="welcome" onDismiss={this.handleDismiss.bind(this, 'welcome')}/>
] : [
<Activity key="activity" items={this.state.activity} />
]}
<News items={this.state.news} />
</div>
] : [
<Intro projectCount={this.state.projectCount} key="intro"/>
]}
<div className="splash">
{this.shouldShowEmailConfirmation() ? [
<Banner key="confirmedEmail"
className="warning"
onRequestDismiss={this.handleDismiss.bind(this, 'confirmed_email')}>
<a href="#" onClick={this.showEmailConfirmationModal}>Confirm your email</a>
{' '}to enable sharing.{' '}
<a href="/info/faq/#accounts">Having trouble?</a>
</Banner>,
<Modal key="emailConfirmationModal"
isOpen={this.state.emailConfirmationModalOpen}
onRequestClose={this.hideEmailConfirmationModal}
style={{content: emailConfirmationStyle}}>
<iframe ref="emailConfirmationiFrame"
src="/accounts/email_resend_standalone/"
{...omit(emailConfirmationStyle, 'padding')} />
</Modal>
] : []}
<div key="inner" className="inner">
{this.state.session.user ? [
<div key="header" className="splash-header">
{this.state.session.flags.show_welcome ? [
<Welcome key="welcome" onDismiss={this.handleDismiss.bind(this, 'welcome')}/>
] : [
<Activity key="activity" items={this.state.activity} />
]}
<News items={this.state.news} />
</div>
] : [
<Intro projectCount={this.state.projectCount} key="intro"/>
]}
{featured}
{featured}
<AdminPanel>
<dt>Tools</dt>
<dd>
<ul>
<li>
<a href="/scratch_admin/tickets">Ticket Queue</a>
</li>
<li>
<a href="/scratch_admin/ip-search/">IP Search</a>
</li>
<li>
<a href="/scratch_admin/email-search/">Email Search</a>
</li>
</ul>
</dd>
<dt>Homepage Cache</dt>
<dd>
<ul className="cache-list">
<li>
<form
id="homepage-refresh-form"
method="post"
action="/scratch_admin/homepage/clear-cache/">
<AdminPanel>
<dt>Tools</dt>
<dd>
<ul>
<li>
<a href="/scratch_admin/tickets">Ticket Queue</a>
</li>
<li>
<a href="/scratch_admin/ip-search/">IP Search</a>
</li>
<li>
<a href="/scratch_admin/email-search/">Email Search</a>
</li>
</ul>
</dd>
<dt>Homepage Cache</dt>
<dd>
<ul className="cache-list">
<li>
<form
id="homepage-refresh-form"
method="post"
action="/scratch_admin/homepage/clear-cache/">
<div className="button-row">
<span>Refresh row data:</span>
<Button type="submit">
<span>Refresh</span>
</Button>
</div>
</form>
</li>
</ul>
</dd>
</AdminPanel>
<div className="button-row">
<span>Refresh row data:</span>
<Button type="submit">
<span>Refresh</span>
</Button>
</div>
</form>
</li>
</ul>
</dd>
</AdminPanel>
</div>
</div>
);
}