summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--app/app.js2
-rw-r--r--app/components/Account.js2
-rw-r--r--app/lib/backend-redux-actions.js15
-rw-r--r--app/lib/backend.js24
-rw-r--r--app/reducers/user.js1
-rw-r--r--package.json1
-rw-r--r--test/actions.spec.js30
7 files changed, 48 insertions, 27 deletions
diff --git a/app/app.js b/app/app.js
index 7c358dcbda..7c69648423 100644
--- a/app/app.js
+++ b/app/app.js
@@ -23,7 +23,7 @@ const backend = new Backend();
// reset login state if user quit the app during login
if([LoginState.connecting, LoginState.failed].includes(store.getState().user.status)) {
store.dispatch(userActions.loginChange({
- status: LoginState.none
+ status: LoginState.none
}));
}
diff --git a/app/components/Account.js b/app/components/Account.js
index e724d314c5..1e98a425d6 100644
--- a/app/components/Account.js
+++ b/app/components/Account.js
@@ -2,7 +2,6 @@ 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 {
@@ -25,7 +24,6 @@ export default class Account extends Component {
}
render() {
- const isLoggedIn = this.props.user.status === LoginState.ok;
let formattedAccountId = formatAccount(this.props.user.account);
return (
diff --git a/app/lib/backend-redux-actions.js b/app/lib/backend-redux-actions.js
index 5718278dde..3fff1e1127 100644
--- a/app/lib/backend-redux-actions.js
+++ b/app/lib/backend-redux-actions.js
@@ -29,23 +29,24 @@ export default function mapBackendEventsToReduxActions(backend, store) {
}));
};
- const onLoggingIn = (account) => {
- store.dispatch(userActions.loginChange({
+ const onLoggingIn = (info) => {
+ store.dispatch(userActions.loginChange(Object.assign({
status: LoginState.connecting,
- error: null,
- account
- }));
+ error: null
+ }, info)));
};
- const onLogin = (account, error) => {
+ const onLogin = (info, error) => {
const status = error ? LoginState.failed : LoginState.ok;
- store.dispatch(userActions.loginChange({ status, error }));
+ const paidUntil = info.paidUntil ? info.paidUntil : null;
+ store.dispatch(userActions.loginChange({ paidUntil, status, error }));
};
const onLogout = () => {
store.dispatch(userActions.loginChange({
status: LoginState.none,
account: null,
+ paidUntil: null,
error: null
}));
};
diff --git a/app/lib/backend.js b/app/lib/backend.js
index 2a608e52a1..601b0e7b64 100644
--- a/app/lib/backend.js
+++ b/app/lib/backend.js
@@ -1,3 +1,4 @@
+import moment from 'moment';
import Enum from './enum';
import { EventEmitter } from 'events';
import { servers } from '../config';
@@ -19,6 +20,7 @@ export default class Backend extends EventEmitter {
constructor() {
super();
this._account = null;
+ this._paidUntil = null;
this._serverAddress = null;
this._connStatus = ConnectionState.disconnected;
this._cancellationHandler = null;
@@ -30,6 +32,7 @@ export default class Backend extends EventEmitter {
// Accessors
get account() { return this._account; }
+ get paidUntil() { return this._paidUntil; }
get serverAddress() { return this._serverAddress; }
// Public methods
@@ -66,6 +69,10 @@ export default class Backend extends EventEmitter {
this._account = user.account;
}
+ if(user.paidUntil) {
+ this._paidUntil = user.paidUntil;
+ }
+
this._connStatus = mapConnStatus(connect.status);
}
@@ -99,23 +106,34 @@ export default class Backend extends EventEmitter {
login(account) {
this._account = account;
+ this._paidUntil = null;
// emit: logging in
- this.emit(EventType.logging, account, null);
+ this.emit(EventType.logging, { account, paidUntil: this._paidUntil }, null);
// @TODO: Add login call
setTimeout(() => {
let err = null;
- if(!account.startsWith('1111')) {
+ let res = { account };
+
+ if(account.startsWith('1111')) { // accounts starting with 1111 expire in one month
+ res.paidUntil = moment().add(1, 'month').millisecond(0).toISOString();
+ } else if(account.startsWith('2222')) { // expired in 2013
+ res.paidUntil = moment('2013-01-01').toISOString();
+ } else if(account.startsWith('3333')) { // expire in 2038
+ res.paidUntil = moment('2038-01-01').toISOString();
+ } else {
err = new Error('Invalid account number.');
}
+
// emit: login
- this.emit(EventType.login, account, err);
+ this.emit(EventType.login, res, err);
}, 2000);
}
logout() {
this._account = null;
+ this._paidUntil = null;
// emit event
this.emit(EventType.logout);
diff --git a/app/reducers/user.js b/app/reducers/user.js
index 5b89cfa991..e198ee4c26 100644
--- a/app/reducers/user.js
+++ b/app/reducers/user.js
@@ -4,6 +4,7 @@ import { LoginState } from '../enums';
const initialState = {
account: null,
+ paidUntil: null, // ISO8601
status: LoginState.none,
error: null
};
diff --git a/package.json b/package.json
index e566746203..12f701529a 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
"dependencies": {
"babel-runtime": "^6.22.0",
"cheap-ruler": "^2.4.1",
+ "moment": "^2.17.1",
"react": "^15.4.2",
"react-custom-scrollbars": "^4.0.2",
"react-dom": "^15.4.2",
diff --git a/test/actions.spec.js b/test/actions.spec.js
index 8b2e79e45a..0c691c2bd6 100644
--- a/test/actions.spec.js
+++ b/test/actions.spec.js
@@ -1,5 +1,4 @@
import { expect } from 'chai';
-
import { filterIpUpdateActions, mockBackend, mockState, mockStore } from './support';
import Backend from '../app/lib/backend';
import userActions from '../app/actions/user';
@@ -12,32 +11,31 @@ describe('actions', function() {
it('should login', (done) => {
const expectedActions = [
- { type: 'USER_LOGIN_CHANGE', payload: { status: 'connecting', error: null, account: '111123456789' } },
- { type: 'USER_LOGIN_CHANGE', payload: { status: 'ok', error: null } }
+ { type: 'USER_LOGIN_CHANGE', payload: { status: 'connecting', error: null, account: '222223456789', paidUntil: null } },
+ { type: 'USER_LOGIN_CHANGE', payload: { paidUntil: '2013-01-01T00:00:00.000Z', status: 'ok', error: null } }
];
-
const store = mockStore(mockState());
const backend = mockBackend(store);
mapBackendEventsToReduxActions(backend, store);
backend.once(Backend.EventType.login, () => {
const storeActions = filterIpUpdateActions(store.getActions());
-
expect(storeActions).deep.equal(expectedActions);
done();
});
- store.dispatch(userActions.login(backend, '111123456789'));
+ store.dispatch(userActions.login(backend, '222223456789'));
});
-
+
it('should logout', (done) => {
const expectedActions = [
- { type: 'USER_LOGIN_CHANGE', payload: { account: null, status: 'none', error: null } }
+ { type: 'USER_LOGIN_CHANGE', payload: { account: null, paidUntil: null, status: 'none', error: null } }
];
let state = Object.assign(mockState(), {
user: {
- account: '1111234567890',
+ account: '3333234567890',
+ paidUntil: '2038-01-01T00:00:00.000Z',
status: LoginState.ok
}
});
@@ -64,7 +62,8 @@ describe('actions', function() {
let state = Object.assign(mockState(), {
user: {
- account: '1111234567890',
+ account: '3333234567890',
+ paidUntil: '2038-01-01T00:00:00.000Z',
status: LoginState.ok
}
});
@@ -91,7 +90,8 @@ describe('actions', function() {
let state = Object.assign(mockState(), {
user: {
- account: '1111234567890',
+ account: '3333234567890',
+ paidUntil: '2038-01-01T00:00:00.000Z',
status: LoginState.ok
}
});
@@ -117,7 +117,8 @@ describe('actions', function() {
let state = Object.assign(mockState(), {
user: {
- account: '1111234567890',
+ account: '3333234567890',
+ paidUntil: '2038-01-01T00:00:00.000Z',
status: LoginState.ok
},
connect: {
@@ -142,13 +143,14 @@ describe('actions', function() {
it('should disconnect from VPN server on logout', (done) => {
const expectedActions = [
- { type: 'USER_LOGIN_CHANGE', payload: { account: null, status: 'none', error: null } },
+ { type: 'USER_LOGIN_CHANGE', payload: { account: null, paidUntil: null, status: 'none', error: null } },
{ type: 'CONNECTION_CHANGE', payload: { serverAddress: null, status: 'disconnected', error: null } }
];
let state = Object.assign(mockState(), {
user: {
- account: '1111234567890',
+ account: '3333234567890',
+ paidUntil: '2038-01-01T00:00:00.000Z',
status: LoginState.ok
},
connect: {