summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@codeispoetry.ru>2017-03-06 13:17:06 +0000
committerAndrej Mihajlov <and@codeispoetry.ru>2017-03-06 13:17:06 +0000
commit90a2c65bd89b8096c755a52c2673dde9ff4de969 (patch)
tree83cf9223c02218896b99745ce17c00bc0e6435a1
parentb530e6a7122143e293e15f5e9c988e24d2675412 (diff)
downloadmullvadvpn-90a2c65bd89b8096c755a52c2673dde9ff4de969.tar.xz
mullvadvpn-90a2c65bd89b8096c755a52c2673dde9ff4de969.zip
Add account subview
-rw-r--r--app/assets/css/style.css1
-rw-r--r--app/assets/images/icon-back.svg8
-rw-r--r--app/assets/images/icon-chevron.svg8
-rw-r--r--[-rwxr-xr-x]app/assets/images/icon-close.svg5
-rw-r--r--app/components/Account.css91
-rw-r--r--app/components/Account.js72
-rw-r--r--app/components/Settings.css45
-rw-r--r--app/components/Settings.js40
-rw-r--r--app/containers/AccountPage.js22
-rw-r--r--app/containers/SettingsPage.js4
-rw-r--r--app/routes.js6
11 files changed, 244 insertions, 58 deletions
diff --git a/app/assets/css/style.css b/app/assets/css/style.css
index 18a031d14b..4755c3c85f 100644
--- a/app/assets/css/style.css
+++ b/app/assets/css/style.css
@@ -9,6 +9,7 @@
@import '../../components/Login.css';
@import '../../components/Connect.css';
@import '../../components/Settings.css';
+@import '../../components/Account.css';
@import '../../components/SelectLocation.css';
@import '../../components/HeaderBar.css';
@import '../../components/Layout.css';
diff --git a/app/assets/images/icon-back.svg b/app/assets/images/icon-back.svg
new file mode 100644
index 0000000000..5ec98cbee6
--- /dev/null
+++ b/app/assets/images/icon-back.svg
@@ -0,0 +1,8 @@
+<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <title>icon-back</title>
+ <desc>Mullvad VPN app</desc>
+ <defs></defs>
+ <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="0.6">
+ <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M7.00548958,11.9978652 C6.97547323,12.2732292 7.06852694,12.5603856 7.28524783,12.7773547 L13.2129013,18.7117979 C13.5936146,19.0929473 14.2231287,19.090784 14.6233317,18.7027276 L14.6942341,18.6339771 C15.09248,18.2478183 15.1055305,17.6195657 14.7108992,17.2180331 L9.58045095,11.9978652 L14.7108992,6.77769718 C15.1055305,6.37616462 15.09248,5.74791199 14.6942341,5.36175323 L14.6233317,5.29300272 C14.2231287,4.90494629 13.5936146,4.90278303 13.2129013,5.28393238 L7.28524783,11.2183756 C7.06852694,11.4353448 6.97547323,11.7225011 7.00548958,11.9978652 L7.00548958,11.9978652 Z" id="path" fill="#FFFFFF"></path>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/assets/images/icon-chevron.svg b/app/assets/images/icon-chevron.svg
new file mode 100644
index 0000000000..2e7d154e0d
--- /dev/null
+++ b/app/assets/images/icon-chevron.svg
@@ -0,0 +1,8 @@
+<svg width="10px" height="15px" viewBox="0 0 10 15" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <title>icon-chevron</title>
+ <desc>Mullvad VPN app</desc>
+ <defs></defs>
+ <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="0.8">
+ <path d="M10,7.4966702 C9.99958901,7.16348359 9.85479536,6.83138119 9.56686274,6.57756713 L2.5380921,0.381670278 C1.95661897,-0.130901228 1.02053384,-0.125317014 0.439266854,0.387072772 C-0.146052619,0.903034846 -0.144744052,1.72779176 0.433138138,2.23719784 L6.40330308,7.49992841 L0.433138138,12.762659 C-0.148334995,13.2752305 -0.142000132,14.1003943 0.439266854,14.612784 C1.02458633,15.1287461 1.96020991,15.1275926 2.5380921,14.6181865 L9.56686274,8.42228969 C9.85657912,8.16690324 10.000373,7.83391619 9.99983696,7.50067932 L10,7.4966702 Z" id="icon-path" fill="#FFFFFF" fill-rule="nonzero"></path>
+ </g>
+</svg> \ No newline at end of file
diff --git a/app/assets/images/icon-close.svg b/app/assets/images/icon-close.svg
index 4bf7151743..df23259a13 100755..100644
--- a/app/assets/images/icon-close.svg
+++ b/app/assets/images/icon-close.svg
@@ -1,7 +1,8 @@
-<?xml version="1.0" encoding="UTF-8"?>
<svg width="24px" height="24px" viewBox="0 0 24 24" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>icon-close</title>
<desc>Mullvad VPN app</desc>
<defs></defs>
- <path d="M13.5,12 L17.2947612,8.20523878 C17.6857559,7.81424414 17.6838785,7.18387854 17.293923,6.79392296 L17.206077,6.70607704 C16.8181114,6.31811142 16.1842538,6.31574616 15.7947612,6.70523878 L12,10.5 L8.20523878,6.70523878 C7.81574616,6.31574616 7.18188858,6.31811142 6.79392296,6.70607704 L6.70607704,6.79392296 C6.31612146,7.18387854 6.31424414,7.81424414 6.70523878,8.20523878 L10.5,12 L6.70523878,15.7947612 C6.31424414,16.1857559 6.31612146,16.8161215 6.70607704,17.206077 L6.79392296,17.293923 C7.18188858,17.6818886 7.81574616,17.6842538 8.20523878,17.2947612 L12,13.5 L15.7947612,17.2947612 C16.1842538,17.6842538 16.8181114,17.6818886 17.206077,17.293923 L17.293923,17.206077 C17.6838785,16.8161215 17.6857559,16.1857559 17.2947612,15.7947612 L13.5,12 Z M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z" fill="#FFFFFF"></path>
+ <g id="icon" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd" fill-opacity="0.6">
+ <path d="M12,24 C5.37312,24 -3.2900871e-16,18.62688 -7.34788079e-16,12 C-1.14056745e-15,5.37312 5.37312,0 12,0 C18.62688,0 24,5.37312 24,12 C24,18.62688 18.62688,24 12,24 Z M13.5,12 L17.2947612,8.20523878 C17.6857559,7.81424414 17.6838785,7.18387854 17.293923,6.79392296 L17.206077,6.70607704 C16.8181114,6.31811142 16.1842538,6.31574616 15.7947612,6.70523878 L12,10.5 L8.20523878,6.70523878 C7.81574616,6.31574616 7.18188858,6.31811142 6.79392296,6.70607704 L6.70607704,6.79392296 C6.31612146,7.18387854 6.31424414,7.81424414 6.70523878,8.20523878 L10.5,12 L6.70523878,15.7947612 C6.31424414,16.1857559 6.31612146,16.8161215 6.70607704,17.206077 L6.79392296,17.293923 C7.18188858,17.6818886 7.81574616,17.6842538 8.20523878,17.2947612 L12,13.5 L15.7947612,17.2947612 C16.1842538,17.6842538 16.8181114,17.6818886 17.206077,17.293923 L17.293923,17.206077 C17.6838785,16.8161215 17.6857559,16.1857559 17.2947612,15.7947612 L13.5,12 L13.5,12 Z" id="path" fill="#FFFFFF"></path>
+ </g>
</svg> \ No newline at end of file
diff --git a/app/components/Account.css b/app/components/Account.css
new file mode 100644
index 0000000000..00b620fc7f
--- /dev/null
+++ b/app/components/Account.css
@@ -0,0 +1,91 @@
+.account {
+ background: #192E45;
+ height: 100%;
+}
+
+.account__container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+}
+
+.account__header {
+ flex: 0 0 auto;
+ padding: 40px 24px 24px;
+ position: relative; /* anchor for close button */
+}
+
+.account__close {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ border: 0;
+ padding: 0;
+ margin: 0;
+ top: 24px;
+ left: 12px;
+ z-index: 1; /* part of .account__container convers the button */
+
+}
+
+.account__close-icon {
+ opacity: 0.6;
+ margin-right: 8px;
+}
+
+.account__close-title {
+ font-family: "Open Sans";
+ font-size: 13px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.6);
+}
+
+.account__title {
+ font-family: DINPro;
+ font-size: 32px;
+ font-weight: 900;
+ line-height: 40px;
+ color: #FFFFFF;
+}
+
+.account__content {
+ flex: 1 1 auto;
+ display: flex;
+ flex-direction: column;
+ justify-content: space-between;
+}
+
+.account__main {
+ margin-bottom: 24px;
+}
+
+.account__footer {
+ padding: 24px;
+}
+
+.account__row {
+ padding: 0 24px;
+}
+
+.account__row + .account__row {
+ margin-top: 24px;
+}
+
+.account__row-label {
+ font-family: "Open Sans";
+ font-size: 13px;
+ font-weight: 600;
+ color: rgba(255, 255, 255, 0.8);
+ margin-bottom: 8px;
+}
+
+.account__row-value {
+ font-family: "Open Sans";
+ font-size: 16px;
+ font-weight: 800;
+ color: rgba(255, 255, 255, 0.8);
+}
+
+.account__footer .button + .button {
+ margin-top: 24px;
+} \ No newline at end of file
diff --git a/app/components/Account.js b/app/components/Account.js
new file mode 100644
index 0000000000..e724d314c5
--- /dev/null
+++ b/app/components/Account.js
@@ -0,0 +1,72 @@
+import React, { Component, PropTypes } from 'react';
+import { If, Then } from 'react-if';
+import { Layout, Container, Header } from './Layout';
+import { formatAccount } from '../lib/formatters';
+import { LoginState } from '../enums';
+
+export default class Account extends Component {
+
+ static propTypes = {
+ onLogout: PropTypes.func.isRequired,
+ onClose: PropTypes.func.isRequired,
+ onExternalLink: PropTypes.func.isRequired
+ }
+
+ onClose() {
+ this.props.onClose();
+ }
+
+ onExternalLink(type) {
+ this.props.onExternalLink(type);
+ }
+
+ onLogout() {
+ this.props.onLogout();
+ }
+
+ render() {
+ const isLoggedIn = this.props.user.status === LoginState.ok;
+ let formattedAccountId = formatAccount(this.props.user.account);
+
+ return (
+ <Layout>
+ <Header hidden={ true } style={ Header.Style.defaultDark } />
+ <Container>
+ <div className="account">
+ <div className="account__close" onClick={ ::this.onClose }>
+ <img className="account__close-icon" src="./assets/images/icon-back.svg" />
+ <span className="account__close-title">Settings</span>
+ </div>
+ <div className="account__container">
+
+ <div className="account__header">
+ <h2 className="account__title">Account</h2>
+ </div>
+
+ <div className="account__content">
+ <div className="account__main">
+
+ <div className="account__row">
+ <div className="account__row-label">Account ID</div>
+ <div className="account__row-value">{ formattedAccountId }</div>
+ </div>
+
+ <div className="account__row">
+ <div className="account__row-label">Paid until</div>
+ <div className="account__row-value">4:20pm, 12 November 2017</div>
+ </div>
+
+ <div className="account__footer">
+ <button className="button button--positive" onClick={ this.onExternalLink.bind(this, 'purchase') }>Buy more time</button>
+ <button className="button button--negative" onClick={ ::this.onLogout }>Logout</button>
+ </div>
+
+ </div>
+ </div>
+ </div>
+ </div>
+ </Container>
+ </Layout>
+ );
+ }
+}
diff --git a/app/components/Settings.css b/app/components/Settings.css
index 4189a0908e..5485efd20e 100644
--- a/app/components/Settings.css
+++ b/app/components/Settings.css
@@ -46,35 +46,6 @@
color: #FFFFFF;
}
-.settings__account {
- padding: 0 24px;
-}
-
-.settings__account-label {
- display: inline-block;
- vertical-align: baseline;
- font-family: "Open Sans";
- font-size: 13px;
- font-weight: 600;
- line-height: 20px;
- color: rgba(255,255,255,0.8);
-}
-
-.settings__account-id {
- display: inline-block;
- vertical-align: baseline;
- font-family: "Open Sans";
- font-size: 16px;
- font-weight: 800;
- line-height: 20px;
- color: rgba(255,255,255,0.8);
- margin-left: 8px;
-}
-
-.settings__main {
- margin-bottom: 24px;
-}
-
.settings__cell {
background-color:rgba(41,71,115,1);
padding: 15px 24px;
@@ -83,6 +54,15 @@
align-items: center;
}
+.settings__cell-disclosure {
+ display: block;
+ margin-left: 8px;
+}
+
+.settings__cell-spacer {
+ height: 24px;
+}
+
.settings__cell--active:hover {
background-color: rgba(41,71,115,0.9);
}
@@ -111,6 +91,13 @@
flex: 0 0 auto;
}
+.settings__account-paid-until-label {
+ font-family: "Open Sans";
+ font-size: 13px;
+ font-weight: 800;
+ color: rgba(255, 255, 255, 0.8);
+}
+
.settings__cell-footer {
padding: 8px 24px 24px;
font-family: "Open Sans";
diff --git a/app/components/Settings.js b/app/components/Settings.js
index 153627b646..4275ef77fe 100644
--- a/app/components/Settings.js
+++ b/app/components/Settings.js
@@ -3,14 +3,15 @@ import { If, Then } from 'react-if';
import { Layout, Container, Header } from './Layout';
import Switch from './Switch';
import CustomScrollbars from './CustomScrollbars';
-import { formatAccount } from '../lib/formatters';
import { LoginState } from '../enums';
export default class Settings extends Component {
static propTypes = {
+ onQuit: PropTypes.func.isRequired,
onLogout: PropTypes.func.isRequired,
onClose: PropTypes.func.isRequired,
+ onViewAccount: PropTypes.func.isRequired,
onExternalLink: PropTypes.func.isRequired,
onUpdateSettings: PropTypes.func.isRequired
}
@@ -33,10 +34,6 @@ export default class Settings extends Component {
render() {
const isLoggedIn = this.props.user.status === LoginState.ok;
- let formattedAccountId;
- if(isLoggedIn) {
- formattedAccountId = formatAccount(this.props.user.account);
- }
return (
<Layout>
@@ -56,6 +53,16 @@ export default class Settings extends Component {
<If condition={ isLoggedIn }>
<Then>
<div>
+
+ <div className="settings__cell settings__cell--disclosure" onClick={ this.props.onViewAccount }>
+ <div className="settings__cell-label">Account</div>
+ <div className="settings__cell-value">
+ <span className="settings__account-paid-until-label">12 DAYS LEFT</span>
+ </div>
+ <img className="settings__cell-disclosure" src="assets/images/icon-chevron.svg" />
+ </div>
+ <div className="settings__cell-spacer"></div>
+
<div className="settings__cell">
<div className="settings__cell-label">Auto-secure</div>
<div className="settings__cell-value">
@@ -81,26 +88,9 @@ export default class Settings extends Component {
</div>
</div>
- { /* show account details when logged in */ }
- <If condition={ isLoggedIn }>
- <div>
- <div className="settings__account">
- <div className="settings__account-row">
- <div className="settings__account-label">Account ID</div>
- <div className="settings__account-id">{ formattedAccountId }</div>
- </div>
- <div className="settings__account-row">
- <div className="settings__account-label">Time remaining</div>
- <div className="settings__account-id">12 days</div>
- </div>
- </div>
-
- <div className="settings__footer">
- <button className="button button--neutral" onClick={ this.onExternalLink.bind(this, 'purchase') }>Buy more time</button>
- <button className="button button--negative" onClick={ ::this.onLogout }>Logout</button>
- </div>
- </div>
- </If>
+ <div className="settings__footer">
+ <button className="button button--negative" onClick={ this.props.onQuit }>Quit app</button>
+ </div>
</div>
</CustomScrollbars>
diff --git a/app/containers/AccountPage.js b/app/containers/AccountPage.js
new file mode 100644
index 0000000000..bc5e3d3b73
--- /dev/null
+++ b/app/containers/AccountPage.js
@@ -0,0 +1,22 @@
+import { connect } from 'react-redux';
+import { bindActionCreators } from 'redux';
+import Account from '../components/Account';
+import userActions from '../actions/user';
+import { shell } from 'electron';
+import { links } from '../config';
+
+const mapStateToProps = (state) => {
+ return state;
+};
+
+const mapDispatchToProps = (dispatch, props) => {
+ const { logout } = bindActionCreators(userActions, dispatch);
+ return {
+ onLogout: () => logout(props.backend),
+ onClose: () => props.router.push('/settings'),
+ onViewAccount: () => props.router.push('/settings/account'),
+ onExternalLink: (type) => shell.openExternal(links[type])
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(Account);
diff --git a/app/containers/SettingsPage.js b/app/containers/SettingsPage.js
index 345d073d40..fa1a98a44b 100644
--- a/app/containers/SettingsPage.js
+++ b/app/containers/SettingsPage.js
@@ -3,7 +3,7 @@ import { bindActionCreators } from 'redux';
import Settings from '../components/Settings';
import userActions from '../actions/user';
import settingsActions from '../actions/settings';
-import { shell } from 'electron';
+import { remote, shell } from 'electron';
import { links } from '../config';
const mapStateToProps = (state) => {
@@ -14,8 +14,10 @@ const mapDispatchToProps = (dispatch, props) => {
const { logout } = bindActionCreators(userActions, dispatch);
const { updateSettings } = bindActionCreators(settingsActions, dispatch);
return {
+ onQuit: () => remote.app.quit(),
onLogout: () => logout(props.backend),
onClose: () => props.router.push('/connect'),
+ onViewAccount: () => props.router.push('/settings/account'),
onExternalLink: (type) => shell.openExternal(links[type]),
onUpdateSettings: updateSettings
};
diff --git a/app/routes.js b/app/routes.js
index cc7626484c..7edd8ad1d9 100644
--- a/app/routes.js
+++ b/app/routes.js
@@ -5,6 +5,7 @@ import App from './containers/App';
import LoginPage from './containers/LoginPage';
import ConnectPage from './containers/ConnectPage';
import SettingsPage from './containers/SettingsPage';
+import AccountPage from './containers/AccountPage';
import SelectLocationPage from './containers/SelectLocationPage';
import { LoginState } from './enums';
@@ -35,7 +36,10 @@ const makeRoutes = (store) => {
<Route path="/" component={ App }>
<IndexRoute component={ LoginPage } onEnter={ ensureConnect } />
<Route path="connect" component={ ConnectPage } onEnter={ ensureLoggedIn } />
- <Route path="settings" component={ SettingsPage } />
+ <Route path="settings">
+ <IndexRoute component={ SettingsPage } />
+ <Route path="account" component={ AccountPage } onEnter={ ensureLoggedIn } />
+ </Route>
<Route path="select-location" component={ SelectLocationPage } onEnter={ ensureLoggedIn } />
</Route>
);