summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@codeispoetry.ru>2017-03-20 20:40:02 +0000
committerAndrej Mihajlov <and@codeispoetry.ru>2017-03-20 20:40:02 +0000
commit69131651560f8e38c99e8d025e1aca2ca7ecbbc5 (patch)
tree2296a3a157553e95c9ef48a624451df411aa69e1
parent812aa1832672a3ecce3198950269efb862966745 (diff)
downloadmullvadvpn-69131651560f8e38c99e8d025e1aca2ca7ecbbc5.tar.xz
mullvadvpn-69131651560f8e38c99e8d025e1aca2ca7ecbbc5.zip
Add backend errors and polish error views
-rw-r--r--app/components/Connect.css2
-rw-r--r--app/components/Connect.js19
-rw-r--r--app/containers/ConnectPage.js3
-rw-r--r--app/lib/backend.js54
4 files changed, 75 insertions, 3 deletions
diff --git a/app/components/Connect.css b/app/components/Connect.css
index a727b4a251..dc9a070c99 100644
--- a/app/components/Connect.css
+++ b/app/components/Connect.css
@@ -105,7 +105,9 @@
font-family: "Open Sans";
font-size: 13px;
font-weight: 600;
+ line-height: normal;
color: #fff;
+ margin-bottom: 24px;
}
.connect__status-security {
diff --git a/app/components/Connect.js b/app/components/Connect.js
index 2aef252a01..544b42860e 100644
--- a/app/components/Connect.js
+++ b/app/components/Connect.js
@@ -5,7 +5,9 @@ import ReactMapboxGl, { Marker } from 'react-mapbox-gl';
import cheapRuler from 'cheap-ruler';
import { Layout, Container, Header } from './Layout';
import { mapbox as mapboxConfig } from '../config';
+import Backend from '../lib/Backend';
import { ConnectionState } from '../enums';
+import ExternalLinkSVG from '../assets/images/icon-extLink.svg';
export default class Connect extends Component {
@@ -15,6 +17,7 @@ export default class Connect extends Component {
onConnect: PropTypes.func.isRequired,
onCopyIP: PropTypes.func.isRequired,
onDisconnect: PropTypes.func.isRequired,
+ onExternalLink: PropTypes.func.isRequired,
getServerInfo: PropTypes.func.isRequired
};
@@ -65,11 +68,21 @@ export default class Connect extends Component {
<img src="./assets/images/icon-fail.svg" alt="" />
</div>
<div className="connect__error-title">
- Error
+ { this.props.connect.error.title }
</div>
<div className="connect__error-message">
{ this.props.connect.error.message }
</div>
+ <If condition={ this.props.connect.error.code === Backend.ErrorType.noCredit }>
+ <Then>
+ <div>
+ <button className="button button--positive" onClick={ this.onExternalLink.bind(this, 'purchase') }>
+ <span className="button-label">Buy more time</span>
+ <ExternalLinkSVG className="button-icon button-icon--16" />
+ </button>
+ </div>
+ </Then>
+ </If>
</div>
</div>
)
@@ -294,6 +307,10 @@ export default class Connect extends Component {
this.props.onConnect(serverInfo.address);
}
+ onExternalLink(type) {
+ this.props.onExternalLink(type);
+ }
+
onIPAddressClick() {
this._copyTimer && clearTimeout(this._copyTimer);
this._copyTimer = setTimeout(() => this.setState({ showCopyIPMessage: false }), 3000);
diff --git a/app/containers/ConnectPage.js b/app/containers/ConnectPage.js
index 7b01258f18..5f7067b709 100644
--- a/app/containers/ConnectPage.js
+++ b/app/containers/ConnectPage.js
@@ -1,5 +1,7 @@
import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
+import { shell } from 'electron';
+import { links } from '../config';
import Connect from '../components/Connect';
import connectActions from '../actions/connect';
@@ -17,6 +19,7 @@ const mapDispatchToProps = (dispatch, props) => {
onConnect: (addr) => connect(backend, addr),
onCopyIP: () => copyIPAddress(),
onDisconnect: () => disconnect(backend),
+ onExternalLink: (type) => shell.openExternal(links[type]),
getServerInfo: (key) => backend.serverInfo(key)
};
};
diff --git a/app/lib/backend.js b/app/lib/backend.js
index 88be11a5a6..1a21dda496 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -72,6 +72,39 @@ import { ConnectionState as ReduxConnectionState } from '../enums';
* @param {object} location data
*/
+class BackendError extends Error {
+
+ constructor(code) {
+ super('');
+ this.code = code;
+ this.title = BackendError.localizedTitle(code);
+ this.message = BackendError.localizedMessage(code);
+ }
+
+ static localizedTitle(code) {
+ switch(code) {
+ case Backend.ErrorType.noCredit:
+ return 'Out of time';
+ case Backend.ErrorType.noInternetConnection:
+ return 'Offline';
+ default:
+ return 'Something went wrong';
+ }
+ }
+
+ static localizedMessage(code) {
+ switch(code) {
+ case Backend.ErrorType.noCredit:
+ return 'Buy more time, so you can continue using the internet securely';
+ case Backend.ErrorType.noInternetConnection:
+ return 'Your internet connection will be secured when you get back online';
+ default:
+ return '';
+ }
+ }
+
+}
+
/**
* Backend implementation
*
@@ -80,6 +113,19 @@ import { ConnectionState as ReduxConnectionState } from '../enums';
export default class Backend extends EventEmitter {
/**
+ * Backend error enum
+ *
+ * @static
+ *
+ * @memberOf Backend
+ */
+ static ErrorType = new Enum({
+ noCredit: 1,
+ noInternetConnection: 2,
+ invalidAccount: 3
+ });
+
+ /**
* Event type enum
*
* @type {EventType}
@@ -279,7 +325,7 @@ export default class Backend extends EventEmitter {
} else if(account.startsWith('3333')) { // expire in 2038
res.paidUntil = moment('2038-01-01').toISOString();
} else {
- err = new Error('Invalid account number.');
+ err = new BackendError(Backend.ErrorType.invalidAccount);
}
// emit: login
@@ -332,7 +378,11 @@ export default class Backend extends EventEmitter {
// Prototype: Swedish servers will throw error during connect
if(/se\d+\.mullvad\.net/.test(addr)) {
- err = new Error('Server is unreachable');
+ err = new BackendError(Backend.ErrorType.noInternetConnection);
+ }
+
+ if(/us\d+\.mullvad\.net/.test(addr)) {
+ err = new BackendError(Backend.ErrorType.noCredit);
}
this._connStatus = Backend.ConnectionState.connected;