diff --git a/css/base.css b/css/base.css
index f002cddb..e6a683e1 100644
--- a/css/base.css
+++ b/css/base.css
@@ -85,6 +85,20 @@ html, body {
}
/* END of top-level layout */
+/* Making the alert box less tall */
+.alert-block {
+ padding-top: 0.25em;
+ padding-bottom: 0.25em;
+ margin-bottom: 3px;
+ height: 2.3em;
+}
+
+.alert-error {
+ background-color: #FCC;
+ border-color: #C99;
+ color: #600;
+}
+
.avatar {
width: 32pt;
height: auto;
diff --git a/index.html b/index.html
index f70ca8f5..26c2e656 100644
--- a/index.html
+++ b/index.html
@@ -42,19 +42,36 @@
/* BEGIN Login: a login form */
var LoginView = React.createClass({
getInitialState: function() {
- return {login: '', password: ''};
+ return {
+ login: '',
+ password: '',
+ errorCleared: false
+ };
},
handleLoginChange: function(e) {
+ if (!this.state.errorCleared) {
+ this.props.onClearError();
+ this.setState({errorCleared: true});
+ }
this.setState({login: e.target.value});
},
handlePasswordChange: function(e) {
+ if (!this.state.errorCleared) {
+ this.props.onClearError();
+ this.setState({errorCleared: true});
+ }
this.setState({password: e.target.value});
},
handleSubmit: function(e) {
e.preventDefault();
+ this.setState({errorCleared: false, submitDisabled: true});
this.props.onLogin(this.state.login, this.state.password);
},
render: function() {
+ var submitClassList = "btn btn-primary";
+ if (this.props.disabled) {
+ submitClassList += " disabled";
+ }
return (
);
@@ -213,6 +230,18 @@
})
var SidepanelView = React.createClass({
+ getInitialState: function() {
+ return {
+ showErrorText: true,
+ };
+ },
+ handleClearErrorText: function() {
+ this.setState({showErrorText: false});
+ },
+ handleLoginRequested: function(login, password) {
+ this.props.onLogin(login, password);
+ this.setState({showErrorText: true});
+ },
render: function() {
var title = null;
var avatar = false;
@@ -235,8 +264,11 @@
onSignUp={this.props.onSignUp}
onSettings={this.props.onSettings}
onCancel={this.props.onCancel} />
+
{this.props.state === 'login' ?
- :
+ :
this.props.state === 'register' ?
:
this.props.state === 'settings' ?
@@ -248,6 +280,21 @@
);
}
});
+
+ SidepanelView.ErrorPanel = React.createClass({
+ render: function() {
+ var classList = "alert alert-block";
+ var errorText = null;
+ if (this.props.errorText && this.props.showError) {
+ classList += " alert-error";
+ errorText = this.props.errorText;
+ }
+ return (
+ {errorText}
+ );
+ }
+ });
+
/* END Side panel */
/* BEGIN Contact list (list of topics) */
@@ -508,7 +555,13 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
/* The top-level class to hold all fuinctionality together */
var AppView = React.createClass({
getInitialState: function() {
- return {sidePanel: 'login', loggedIn: false, selTopic: '', tinode: undefined};
+ return {
+ sidePanel: 'login',
+ loggedIn: false,
+ errorText: '',
+ selTopic: '',
+ loginDisabled: false
+ };
},
componentDidMount: function() {
Tinode.enableLogging(true);
@@ -516,12 +569,14 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab
Tinode.setup(HOST, API_KEY);
},
handleLogin: function(login, password) {
- Tinode.connect().then(function(){
+ var instance = this;
+ this.setState({loginDisabled: true, errorText: ''});
+ Tinode.connect().then(function() {
return Tinode.loginBasic(login, password);
- }).then(function(){
- this.setState({sidePanel: 'contacts', loggedIn: true});
+ }).then(function() {
+ instance.setState({sidePanel: 'contacts', loggedIn: true});
}).catch(function(err) {
- console.log(err);
+ instance.setState({loginDisabled: false, errorText: err.message});
});
},
handleNewAccount: function(login_, password_, public_, private_) {
@@ -550,6 +605,8 @@ dignissim a diam a hendrerit. Nulla vel est ut quam rhoncus pulvinar. In hac hab