summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAndrej Mihajlov <and@mullvad.net>2018-08-01 14:21:58 +0200
committerAndrej Mihajlov <and@mullvad.net>2018-08-08 15:26:34 +0200
commit2f6e76531419c0653212410dc992bf952ee5fbe5 (patch)
tree43e2eae17b1ae61da6a05a2e333b88cc6060b2ee
parent21c62239a0ef590e77f3a5a3448f36259755d6d8 (diff)
downloadmullvadvpn-2f6e76531419c0653212410dc992bf952ee5fbe5.tar.xz
mullvadvpn-2f6e76531419c0653212410dc992bf952ee5fbe5.zip
Pull account expiry on demand
-rw-r--r--app/components/Account.js6
-rw-r--r--app/components/Connect.js13
-rw-r--r--app/components/Settings.js32
-rw-r--r--app/containers/ConnectPage.js1
-rw-r--r--app/containers/SettingsPage.js9
-rw-r--r--test/components/Account.spec.js3
-rw-r--r--test/components/Connect.spec.js3
-rw-r--r--test/components/Settings.spec.js129
8 files changed, 105 insertions, 91 deletions
diff --git a/app/components/Account.js b/app/components/Account.js
index 2edf277fa4..dd4994c76c 100644
--- a/app/components/Account.js
+++ b/app/components/Account.js
@@ -12,7 +12,7 @@ import { formatAccount } from '../lib/formatters';
import type { AccountToken } from '../lib/daemon-rpc';
-export type AccountProps = {
+type Props = {
accountToken: AccountToken,
accountExpiry: string,
expiryLocale: string,
@@ -28,7 +28,7 @@ type State = {
showAccountTokenCopiedMessage: boolean,
};
-export default class Account extends Component<AccountProps, State> {
+export default class Account extends Component<Props, State> {
state = {
isRefreshingExpiry: false,
showAccountTokenCopiedMessage: false,
@@ -119,7 +119,7 @@ export default class Account extends Component<AccountProps, State> {
<Text style={styles.account__row_label}>Paid until</Text>
{isOutOfTime ? (
<Text style={styles.account__out_of_time} testName="account__out_of_time">
- OUT OF TIME
+ {'OUT OF TIME'}
</Text>
) : (
<Text style={styles.account__row_value}>{formattedExpiry}</Text>
diff --git a/app/components/Connect.js b/app/components/Connect.js
index 037ab02495..cd27b33719 100644
--- a/app/components/Connect.js
+++ b/app/components/Connect.js
@@ -15,7 +15,7 @@ import Map from './Map';
import type { HeaderBarStyle } from './HeaderBar';
import type { ConnectionReduxState } from '../redux/connection/reducers';
-export type ConnectProps = {
+type Props = {
connection: ConnectionReduxState,
accountExpiry: string,
selectedRelayName: string,
@@ -25,14 +25,15 @@ export type ConnectProps = {
onCopyIP: () => void,
onDisconnect: () => void,
onExternalLink: (type: string) => void,
+ updateAccountExpiry: () => Promise<void>,
};
-type ConnectState = {
+type State = {
showCopyIPMessage: boolean,
mapOffset: [number, number],
};
-export default class Connect extends Component<ConnectProps, ConnectState> {
+export default class Connect extends Component<Props, State> {
state = {
showCopyIPMessage: false,
mapOffset: [0, 0],
@@ -40,7 +41,7 @@ export default class Connect extends Component<ConnectProps, ConnectState> {
_copyTimer: ?TimeoutID;
- shouldComponentUpdate(nextProps: ConnectProps, nextState: ConnectState) {
+ shouldComponentUpdate(nextProps: Props, nextState: State) {
const { connection: prevConnection, ...otherPrevProps } = this.props;
const { connection: nextConnection, ...otherNextProps } = nextProps;
@@ -56,6 +57,10 @@ export default class Connect extends Component<ConnectProps, ConnectState> {
);
}
+ componentDidMount() {
+ this.props.updateAccountExpiry();
+ }
+
componentWillUnmount() {
if (this._copyTimer) {
clearTimeout(this._copyTimer);
diff --git a/app/components/Settings.js b/app/components/Settings.js
index 4a8784fe0e..c447940338 100644
--- a/app/components/Settings.js
+++ b/app/components/Settings.js
@@ -11,13 +11,12 @@ import CustomScrollbars from './CustomScrollbars';
import styles from './SettingsStyles';
import Img from './Img';
-import type { AccountReduxState } from '../redux/account/reducers';
-import type { SettingsReduxState } from '../redux/settings/reducers';
+import type { LoginState } from '../redux/account/reducers';
-export type SettingsProps = {
- account: AccountReduxState,
- settings: SettingsReduxState,
- version: string,
+type Props = {
+ loginState: LoginState,
+ accountExpiry: ?string,
+ appVersion: string,
onQuit: () => void,
onClose: () => void,
onViewAccount: () => void,
@@ -25,9 +24,14 @@ export type SettingsProps = {
onViewPreferences: () => void,
onViewAdvancedSettings: () => void,
onExternalLink: (type: string) => void,
+ updateAccountExpiry: () => Promise<void>,
};
-export default class Settings extends Component<SettingsProps> {
+export default class Settings extends Component<Props> {
+ componentDidMount() {
+ this.props.updateAccountExpiry();
+ }
+
render() {
return (
<Layout>
@@ -60,17 +64,17 @@ export default class Settings extends Component<SettingsProps> {
}
_renderTopButtons() {
- const isLoggedIn = this.props.account.status === 'ok';
+ const isLoggedIn = this.props.loginState === 'ok';
if (!isLoggedIn) {
return null;
}
- let isOutOfTime = false,
- formattedExpiry = '';
- const expiryIso = this.props.account.expiry;
+ let isOutOfTime = false;
+ let formattedExpiry = '';
+ const expiryIso = this.props.accountExpiry;
if (isLoggedIn && expiryIso) {
- const expiry = moment(this.props.account.expiry);
+ const expiry = moment(expiryIso);
isOutOfTime = expiry.isSameOrBefore(moment());
formattedExpiry = (expiry.fromNow(true) + ' left').toUpperCase();
}
@@ -86,7 +90,7 @@ export default class Settings extends Component<SettingsProps> {
<Cell.SubText
testName="settings__account_paid_until_subtext"
style={styles.settings__account_paid_until_Label__error}>
- OUT OF TIME
+ {'OUT OF TIME'}
</Cell.SubText>
<Img height={12} width={7} source="icon-chevron" />
</Cell.CellButton>
@@ -136,7 +140,7 @@ export default class Settings extends Component<SettingsProps> {
// the version in package.json has to be semver, but we use a YEAR.release-channel
// version scheme. in package.json we thus have to write YEAR.release.X-channel and
// this function is responsible for removing .X part.
- return this.props.version
+ return this.props.appVersion
.replace('.0-', '-') // remove the .0 in 2018.1.0-beta9
.replace(/\.0$/, ''); // remove the .0 in 2018.1.0
}
diff --git a/app/containers/ConnectPage.js b/app/containers/ConnectPage.js
index 6f906f1c82..d1d11af334 100644
--- a/app/containers/ConnectPage.js
+++ b/app/containers/ConnectPage.js
@@ -83,6 +83,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) =>
}
},
onExternalLink: (type) => openLink(links[type]),
+ updateAccountExpiry: () => props.app.updateAccountExpiry(),
};
};
diff --git a/app/containers/SettingsPage.js b/app/containers/SettingsPage.js
index 8ffd0691fd..f0e8d7c53b 100644
--- a/app/containers/SettingsPage.js
+++ b/app/containers/SettingsPage.js
@@ -11,11 +11,11 @@ import type { ReduxState, ReduxDispatch } from '../redux/store';
import type { SharedRouteProps } from '../routes';
const mapStateToProps = (state: ReduxState) => ({
- account: state.account,
- settings: state.settings,
- version: getAppVersion(),
+ loginState: state.account.status,
+ accountExpiry: state.account.expiry,
+ appVersion: getAppVersion(),
});
-const mapDispatchToProps = (dispatch: ReduxDispatch, _props: SharedRouteProps) => {
+const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => {
const { push: pushHistory } = bindActionCreators({ push }, dispatch);
return {
onQuit: () => exit(),
@@ -25,6 +25,7 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, _props: SharedRouteProps) =
onViewPreferences: () => pushHistory('/settings/preferences'),
onViewAdvancedSettings: () => pushHistory('/settings/advanced'),
onExternalLink: (type) => openLink(links[type]),
+ updateAccountExpiry: () => props.app.updateAccountExpiry(),
};
};
diff --git a/test/components/Account.spec.js b/test/components/Account.spec.js
index a850c6af06..703ce3d27f 100644
--- a/test/components/Account.spec.js
+++ b/test/components/Account.spec.js
@@ -4,7 +4,8 @@ import * as React from 'react';
import { shallow } from 'enzyme';
import Account from '../../app/components/Account';
import { BackBarItem } from '../../app/components/NavigationBar';
-import type { AccountProps } from '../../app/components/Account';
+
+type AccountProps = React.ElementProps<typeof Account>;
describe('components/Account', () => {
const makeProps = (mergeProps: $Shape<AccountProps>): AccountProps => {
diff --git a/test/components/Connect.spec.js b/test/components/Connect.spec.js
index d21a8eb510..67dae303d8 100644
--- a/test/components/Connect.spec.js
+++ b/test/components/Connect.spec.js
@@ -5,7 +5,7 @@ import { shallow } from 'enzyme';
import Connect from '../../app/components/Connect';
-import type { ConnectProps } from '../../app/components/Connect';
+type ConnectProps = React.ElementProps<typeof Connect>;
describe('components/Connect', () => {
it('shows unsecured hints when disconnected', () => {
@@ -125,6 +125,7 @@ const defaultProps: ConnectProps = {
country: null,
city: null,
},
+ updateAccountExpiry: () => Promise.resolve(),
};
function renderWithProps(customProps: $Shape<ConnectProps>) {
diff --git a/test/components/Settings.spec.js b/test/components/Settings.spec.js
index 9edf46fcc3..4d52d96b11 100644
--- a/test/components/Settings.spec.js
+++ b/test/components/Settings.spec.js
@@ -5,57 +5,14 @@ import { shallow } from 'enzyme';
import Settings from '../../app/components/Settings';
import { CloseBarItem } from '../../app/components/NavigationBar';
-import type { AccountReduxState } from '../../app/redux/account/reducers';
-import type { SettingsReduxState } from '../../app/redux/settings/reducers';
-import type { SettingsProps } from '../../app/components/Settings';
+type SettingsProps = React.ElementProps<typeof Settings>;
describe('components/Settings', () => {
- const loggedOutAccountState: AccountReduxState = {
- accountToken: null,
- accountHistory: [],
- expiry: null,
- status: 'none',
- error: null,
- };
-
- const loggedInAccountState: AccountReduxState = {
- accountToken: '1234',
- accountHistory: [],
- expiry: new Date('2038-01-01').toISOString(),
- status: 'ok',
- error: null,
- };
-
- const unpaidAccountState: AccountReduxState = {
- accountToken: '1234',
- accountHistory: [],
- expiry: new Date('2001-01-01').toISOString(),
- status: 'ok',
- error: null,
- };
-
- const settingsState: SettingsReduxState = {
- relaySettings: {
- normal: {
- location: 'any',
- protocol: 'udp',
- port: 1301,
- },
- },
- relayLocations: [],
- autoConnect: false,
- allowLan: false,
- };
-
- const makeProps = (
- anAccountState: AccountReduxState,
- aSettingsState: SettingsReduxState,
- mergeProps: $Shape<SettingsProps> = {},
- ): SettingsProps => {
+ const makeProps = (mergeProps: $Shape<SettingsProps> = {}): SettingsProps => {
const defaultProps: SettingsProps = {
- account: anAccountState,
- settings: aSettingsState,
- version: '',
+ loginState: 'none',
+ accountExpiry: null,
+ appVersion: '',
onQuit: () => {},
onClose: () => {},
onViewAccount: () => {},
@@ -63,67 +20,97 @@ describe('components/Settings', () => {
onViewAdvancedSettings: () => {},
onViewPreferences: () => {},
onExternalLink: (_type) => {},
+ updateAccountExpiry: () => Promise.resolve(),
};
return Object.assign({}, defaultProps, mergeProps);
};
it('should show quit button when logged out', () => {
- const props = makeProps(loggedOutAccountState, settingsState);
+ const props = makeProps({
+ loginState: 'none',
+ accountExpiry: null,
+ });
const component = getComponent(render(props), 'settings__quit');
expect(component).to.have.length(1);
});
it('should show quit button when logged in', () => {
- const props = makeProps(loggedInAccountState, settingsState);
+ const props = makeProps({
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
+ });
const component = getComponent(render(props), 'settings__quit');
expect(component).to.have.length(1);
});
it('should show external links when logged out', () => {
- const props = makeProps(loggedOutAccountState, settingsState);
+ const props = makeProps({
+ loginState: 'none',
+ accountExpiry: null,
+ });
const component = getComponent(render(props), 'settings__external_link');
expect(component.length).to.be.above(0);
});
it('should show external links when logged in', () => {
- const props = makeProps(loggedInAccountState, settingsState);
+ const props = makeProps({
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
+ });
const component = getComponent(render(props), 'settings__external_link');
expect(component.length).to.be.above(0);
});
it('should show account section when logged in', () => {
- const props = makeProps(loggedInAccountState, settingsState);
+ const props = makeProps({
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
+ });
const component = getComponent(render(props), 'settings__account');
expect(component).to.have.length(1);
});
it('should hide account section when logged out', () => {
- const props = makeProps(loggedOutAccountState, settingsState);
+ const props = makeProps({
+ loginState: 'none',
+ accountExpiry: null,
+ });
const elements = getComponent(render(props), 'settings__account');
expect(elements).to.have.length(0);
});
it('should hide account link when not logged in', () => {
- const props = makeProps(loggedOutAccountState, settingsState);
+ const props = makeProps({
+ loginState: 'none',
+ accountExpiry: null,
+ });
const elements = getComponent(render(props), 'settings__view_account');
expect(elements).to.have.length(0);
});
it('should show out-of-time message for unpaid account', () => {
- const props = makeProps(unpaidAccountState, settingsState);
+ const props = makeProps({
+ accountExpiry: new Date('2001-01-01').toISOString(),
+ loginState: 'ok',
+ });
const component = getComponent(render(props), 'settings__account_paid_until_subtext');
expect(component.children().text()).to.equal('OUT OF TIME');
});
it('should hide out-of-time message for paid account', () => {
- const props = makeProps(loggedInAccountState, settingsState);
+ const props = makeProps({
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
+ });
const component = getComponent(render(props), 'settings__account_paid_until_subtext');
expect(component.children().text()).not.to.equal('OUT OF TIME');
});
it('should call close callback', (done) => {
- const props = makeProps(loggedOutAccountState, settingsState, {
+ const props = makeProps({
onClose: () => done(),
+ loginState: 'none',
+ accountExpiry: null,
});
const component = render(props)
.find(CloseBarItem)
@@ -132,40 +119,51 @@ describe('components/Settings', () => {
});
it('should call quit callback', (done) => {
- const props = makeProps(loggedOutAccountState, settingsState, {
+ const props = makeProps({
onQuit: () => done(),
+
+ loginState: 'none',
+ accountExpiry: null,
});
const component = getComponent(render(props), 'settings__quit');
component.simulate('press');
});
it('should call account callback', (done) => {
- const props = makeProps(loggedInAccountState, settingsState, {
+ const props = makeProps({
onViewAccount: () => done(),
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
});
const component = getComponent(render(props), 'settings__account_paid_until_button');
component.simulate('press');
});
it('should call advanced settings callback', (done) => {
- const props = makeProps(loggedInAccountState, settingsState, {
+ const props = makeProps({
onViewAdvancedSettings: () => done(),
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
});
const component = getComponent(render(props), 'settings__advanced');
component.simulate('press');
});
it('should call preferences callback', (done) => {
- const props = makeProps(loggedInAccountState, settingsState, {
+ const props = makeProps({
onViewPreferences: () => done(),
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
});
const component = getComponent(render(props), 'settings__preferences');
component.simulate('press');
});
it('should call support callback', (done) => {
- const props = makeProps(loggedInAccountState, settingsState, {
+ const props = makeProps({
onViewSupport: () => done(),
+ accountExpiry: new Date('2038-01-01').toISOString(),
+ loginState: 'ok',
});
const component = getComponent(render(props), 'settings__view_support');
component.simulate('press');
@@ -173,10 +171,13 @@ describe('components/Settings', () => {
it('should call external links callback', () => {
const collectedExternalLinkTypes: Array<string> = [];
- const props = makeProps(loggedOutAccountState, settingsState, {
+ const props = makeProps({
onExternalLink: (type) => {
collectedExternalLinkTypes.push(type);
},
+
+ loginState: 'none',
+ accountExpiry: null,
});
const container = getComponent(render(props), 'settings__external_link');
container