summaryrefslogtreecommitdiffhomepage
path: root/gui/src/renderer/app.tsx
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2023-07-14 09:51:37 +0200
committerOskar Nyberg <oskar@mullvad.net>2023-08-28 16:07:31 +0200
commitfd67444fe038ac97c553493614b357745834bdb7 (patch)
treeb834d6bc2f370fcfa735d2d43484870d3c87b556 /gui/src/renderer/app.tsx
parentbab7783eee1ad89ecbe45fc061cea59804400740 (diff)
downloadmullvadvpn-fd67444fe038ac97c553493614b357745834bdb7.tar.xz
mullvadvpn-fd67444fe038ac97c553493614b357745834bdb7.zip
Replace out of time view when adding time
Diffstat (limited to 'gui/src/renderer/app.tsx')
-rw-r--r--gui/src/renderer/app.tsx106
1 files changed, 73 insertions, 33 deletions
diff --git a/gui/src/renderer/app.tsx b/gui/src/renderer/app.tsx
index 6efcd81887..0dfda5d688 100644
--- a/gui/src/renderer/app.tsx
+++ b/gui/src/renderer/app.tsx
@@ -2,6 +2,7 @@ import { batch, Provider } from 'react-redux';
import { Router } from 'react-router';
import { bindActionCreators } from 'redux';
+import { hasExpired } from '../shared/account-expiry';
import { ILinuxSplitTunnelingApplication, IWindowsApplication } from '../shared/application-types';
import {
AccountToken,
@@ -204,7 +205,6 @@ export default class AppRenderer {
initialState.translations.relayLocations,
);
- this.setAccountExpiry(initialState.accountData?.expiry);
this.setSettings(initialState.settings);
this.setIsPerformingPostUpgrade(initialState.isPerformingPostUpgrade);
@@ -219,6 +219,8 @@ export default class AppRenderer {
initialState.navigationHistory !== undefined,
);
}
+ // Login state and account needs to be set before expiry.
+ this.setAccountExpiry(initialState.accountData?.expiry);
this.setAccountHistory(initialState.accountHistory);
this.setTunnelState(initialState.tunnelState);
@@ -648,40 +650,54 @@ export default class AppRenderer {
const nextPath = this.getNavigationBase() as RoutePath;
if (pathname !== nextPath) {
- // First level contains the possible next locations and the second level contains the
- // possible current locations.
- const navigationTransitions: Partial<
- Record<RoutePath, Partial<Record<RoutePath | '*', ITransitionSpecification>>>
- > = {
- [RoutePath.launch]: {
- [RoutePath.login]: transitions.pop,
- [RoutePath.main]: transitions.pop,
- '*': transitions.dismiss,
- },
- [RoutePath.login]: {
- [RoutePath.launch]: transitions.push,
- [RoutePath.main]: transitions.pop,
- [RoutePath.deviceRevoked]: transitions.pop,
- '*': transitions.dismiss,
- },
- [RoutePath.main]: {
- [RoutePath.launch]: transitions.push,
- [RoutePath.login]: transitions.push,
- [RoutePath.tooManyDevices]: transitions.push,
- '*': transitions.dismiss,
- },
- [RoutePath.deviceRevoked]: {
- '*': transitions.pop,
- },
- };
-
- const transition =
- navigationTransitions[nextPath]?.[pathname] ?? navigationTransitions[nextPath]?.['*'];
+ const transition = this.getNavigationTransition(pathname, nextPath);
this.history.reset(nextPath, { transition });
}
}
}
+ private getNavigationTransition(prevPath: RoutePath, nextPath: RoutePath) {
+ // First level contains the possible next locations and the second level contains the
+ // possible current locations.
+ const navigationTransitions: Partial<
+ Record<RoutePath, Partial<Record<RoutePath | '*', ITransitionSpecification>>>
+ > = {
+ [RoutePath.launch]: {
+ [RoutePath.login]: transitions.pop,
+ [RoutePath.main]: transitions.pop,
+ '*': transitions.dismiss,
+ },
+ [RoutePath.login]: {
+ [RoutePath.launch]: transitions.push,
+ [RoutePath.main]: transitions.pop,
+ [RoutePath.deviceRevoked]: transitions.pop,
+ '*': transitions.dismiss,
+ },
+ [RoutePath.main]: {
+ [RoutePath.launch]: transitions.push,
+ [RoutePath.login]: transitions.push,
+ [RoutePath.tooManyDevices]: transitions.push,
+ '*': transitions.dismiss,
+ },
+ [RoutePath.expired]: {
+ [RoutePath.launch]: transitions.push,
+ [RoutePath.login]: transitions.push,
+ [RoutePath.tooManyDevices]: transitions.push,
+ '*': transitions.dismiss,
+ },
+ [RoutePath.timeAdded]: {
+ [RoutePath.expired]: transitions.push,
+ [RoutePath.redeemVoucher]: transitions.push,
+ '*': transitions.dismiss,
+ },
+ [RoutePath.deviceRevoked]: {
+ '*': transitions.pop,
+ },
+ };
+
+ return navigationTransitions[nextPath]?.[prevPath] ?? navigationTransitions[nextPath]?.['*'];
+ }
+
private getNavigationBase(): RoutePath {
if (this.connectedToDaemon && this.deviceState !== undefined) {
const loginState = this.reduxStore.getState().account.status;
@@ -689,10 +705,17 @@ export default class AppRenderer {
if (deviceRevoked) {
return RoutePath.deviceRevoked;
- } else if (this.isLoggedIn()) {
- return RoutePath.main;
- } else {
+ } else if (!this.isLoggedIn()) {
return RoutePath.login;
+ } else if (
+ loginState.type === 'ok' &&
+ (loginState.expiredState === 'expired' || loginState.method === 'new_account')
+ ) {
+ return RoutePath.expired;
+ } else if (loginState.type === 'ok' && loginState.expiredState === 'time_added') {
+ return RoutePath.timeAdded;
+ } else {
+ return RoutePath.main;
}
} else {
return RoutePath.launch;
@@ -884,7 +907,24 @@ export default class AppRenderer {
}
private setAccountExpiry(expiry?: string) {
+ const state = this.reduxStore.getState();
+ const previousExpiry = state.account.expiry;
this.reduxActions.account.updateAccountExpiry(expiry);
+
+ const expired = expiry !== undefined && hasExpired(expiry);
+ if (
+ this.history &&
+ state.account.status.type === 'ok' &&
+ expiry !== undefined &&
+ expiry !== previousExpiry &&
+ ((state.account.status.expiredState === undefined && expired) ||
+ (state.account.status.expiredState === 'expired' && !expired))
+ ) {
+ const prevPath = this.history.location.pathname as RoutePath;
+ const nextPath = expired ? RoutePath.expired : RoutePath.timeAdded;
+ const transition = this.getNavigationTransition(prevPath, nextPath);
+ this.history.replaceRoot(nextPath, { transition });
+ }
}
private storeAutoStart(autoStart: boolean) {