Skip to content

Commit

Permalink
Merge pull request #211 from rschamp/bugfix/GH-195
Browse files Browse the repository at this point in the history
Fix GH-195: Use a spinner component to convey activity while logging in
  • Loading branch information
rschamp committed Nov 11, 2015
2 parents e25eb1f + 0420457 commit 7c0363e
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 7 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"lodash.clone": "3.0.3",
"lodash.defaultsdeep": "3.10.0",
"lodash.omit": "3.1.0",
"lodash.range": "3.0.1",
"minilog": "2.0.8",
"node-sass": "3.3.3",
"po2icu": "git://github.com/LLK/po2icu.git#develop",
Expand Down
30 changes: 24 additions & 6 deletions src/components/login/login.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ var React = require('react');
var ReactDOM = require('react-dom');
var FormattedMessage = require('react-intl').FormattedMessage;

var log = require('../../lib/log.js');

var Input = require('../forms/input.jsx');
var Button = require('../forms/button.jsx');
var Spinner = require('../spinner/spinner.jsx');

require('./login.scss');

Expand All @@ -13,12 +16,21 @@ var Login = React.createClass({
onLogIn: React.PropTypes.func,
error: React.PropTypes.string
},
getInitialState: function () {
return {
waiting: false
};
},
handleSubmit: function (event) {
event.preventDefault();
this.setState({waiting: true});
this.props.onLogIn({
'username': ReactDOM.findDOMNode(this.refs.username).value,
'password': ReactDOM.findDOMNode(this.refs.password).value
});
}, function (err) {
if (err) log.error(err);
this.setState({waiting: false});
}.bind(this));
},
render: function () {
var error;
Expand All @@ -40,11 +52,17 @@ var Login = React.createClass({
defaultMessage={'Password'} />
</label>
<Input type="password" ref="password" name="password" />
<Button className="submit-button white" type="submit">
<FormattedMessage
id='general.signIn'
defaultMessage={'Sign in'} />
</Button>
{this.state.waiting ? [
<Button className="submit-button white" type="submit" disabled="disabled">
<Spinner />
</Button>
] : [
<Button className="submit-button white" type="submit">
<FormattedMessage
id='general.signIn'
defaultMessage={'Sign in'} />
</Button>
]}
<a className="right" href="/accounts/password_reset/">
<FormattedMessage
id='login.forgotPassword'
Expand Down
6 changes: 6 additions & 0 deletions src/components/login/login.scss
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
font-weight: bold;
}

.spinner {
margin: 0 .8rem;
width: 1rem;
height: 1rem;
}

.submit-button {
margin-top: 5px;
}
Expand Down
3 changes: 2 additions & 1 deletion src/components/navigation/navigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ var Navigation = React.createClass({
closeLogin: function () {
this.setState({'loginOpen': false});
},
handleLogIn: function (formData) {
handleLogIn: function (formData, callback) {
this.setState({'loginError': null});
formData['useMessages'] = true;
this.api({
Expand All @@ -142,6 +142,7 @@ var Navigation = React.createClass({
}.bind(this));
window.refreshSession();
}
callback();
}
}.bind(this));
},
Expand Down
20 changes: 20 additions & 0 deletions src/components/spinner/spinner.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
var range = require('lodash.range');
var React = require('react');

require('./spinner.scss');

var Spinner = React.createClass({
// Adapted from http://tobiasahlin.com/spinkit/
type: 'Spinner',
render: function () {
return (
<div className="spinner">
{range(1,13).map(function (id) {
return <div className={'circle' + id + ' circle'}></div>;
})}
</div>
);
}
});

module.exports = Spinner;
47 changes: 47 additions & 0 deletions src/components/spinner/spinner.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@import "../../colors";

.spinner {
position: relative;
width: 20px;
height: 20px;

.circle {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;

&:before {
display: block;
animation: circleFadeDelay 1.2s infinite ease-in-out both;
margin: 0 auto;
border-radius: 100%;
background-color: darken($ui-blue, 8%);
width: 15%;
height: 15%;
content: "";
-webkit-animation: circleFadeDelay 1.2s infinite ease-in-out both;
}
}

@for $i from 1 through 12 {
$rotation: 30deg * ($i - 1);
$delay: -1.3s + $i * .1;
.circle#{$i} {
transform: rotate($rotation);
-ms-transform: rotate($rotation);
-webkit-transform: rotate($rotation);
}
.circle#{$i}:before {
animation-delay: $delay;
-webkit-animation-delay: $delay;
}
}

}

@keyframes circleFadeDelay {
0%, 39%, 100% { opacity: 0; }
40% { opacity: 1; }
}
3 changes: 3 additions & 0 deletions src/views/components/components.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var Box = require('../../components/box/box.jsx');
var Button = require('../../components/forms/button.jsx');
var Carousel = require('../../components/carousel/carousel.jsx');
var Input = require('../../components/forms/input.jsx');
var Spinner = require('../../components/spinner/spinner.jsx');


require('./components.scss');
Expand Down Expand Up @@ -37,6 +38,8 @@ var Components = React.createClass({
<Activity />
<h1>{'Nothing!!!'}</h1>
<Activity items={[]} />
<h1>This is a Spinner</h1>
<Spinner />
</div>
);
}
Expand Down

0 comments on commit 7c0363e

Please sign in to comment.