diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-06-22 15:28:52 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-07-03 13:37:54 +0200 |
| commit | d8569969ff508d139140a128b136ccfff06a89f5 (patch) | |
| tree | a581504b79ca85a8fa5bc7cc8729d6a66215db8d | |
| parent | 6af054e0b7321e7f8ce2dc1c32d907e36c6218ee (diff) | |
| download | mullvadvpn-d8569969ff508d139140a128b136ccfff06a89f5.tar.xz mullvadvpn-d8569969ff508d139140a128b136ccfff06a89f5.zip | |
Pass individual props instead of AccountReduxState
| -rw-r--r-- | app/components/Login.js | 111 | ||||
| -rw-r--r-- | app/containers/LoginPage.js | 26 | ||||
| -rw-r--r-- | app/lib/backend.js | 7 | ||||
| -rw-r--r-- | test/components/Login.spec.js | 1 |
4 files changed, 85 insertions, 60 deletions
diff --git a/app/components/Login.js b/app/components/Login.js index d15681c58b..e70d84b7aa 100644 --- a/app/components/Login.js +++ b/app/components/Login.js @@ -10,17 +10,20 @@ import { BlueButton, Label, CellButton } from './styled'; import styles from './LoginStyles'; import { colors } from '../config'; -import type { AccountReduxState } from '../redux/account/reducers'; +import type { LoginState } from '../redux/account/reducers'; import type { AccountToken } from '../lib/daemon-rpc'; export type Props = { - account: AccountReduxState, - onLogin: (accountToken: AccountToken) => void, - onSettings: ?() => void, - onFirstChangeAfterFailure: () => void, - onExternalLink: (type: string) => void, - onAccountTokenChange: (accountToken: AccountToken) => void, - onRemoveAccountTokenFromHistory: (accountToken: AccountToken) => void, + accountToken: ?AccountToken, + accountHistory: Array<AccountToken>, + loginError: ?Error, + loginState: LoginState, + openSettings: ?() => void, + openExternalLink: (type: string) => void, + login: (accountToken: AccountToken) => void, + resetLoginError: () => void, + updateAccountToken: (accountToken: AccountToken) => void, + removeAccountTokenFromHistory: (accountToken: AccountToken) => Promise<void>, }; type State = { @@ -33,7 +36,7 @@ export default class Login extends Component<Props, State> { }; _accountInput: ?AccountInput; - _notifyOnFirstChangeAfterFailure = false; + _shouldResetLoginError = false; _showsFooter = true; _footerAnimatedValue = Animated.createValue(0); @@ -49,8 +52,8 @@ export default class Login extends Component<Props, State> { constructor(props: Props) { super(props); - if (props.account.status === 'failed') { - this._notifyOnFirstChangeAfterFailure = true; + if (props.loginState === 'failed') { + this._shouldResetLoginError = true; } this._footerAnimationStyle = Styles.createAnimatedViewStyle({ @@ -68,11 +71,11 @@ export default class Login extends Component<Props, State> { componentDidUpdate(prevProps: Props, _prevState: State) { if ( - this.props.account.status !== prevProps.account.status && - this.props.account.status === 'failed' && - !this._notifyOnFirstChangeAfterFailure + this.props.loginState !== prevProps.loginState && + this.props.loginState === 'failed' && + !this._shouldResetLoginError ) { - this._notifyOnFirstChangeAfterFailure = true; + this._shouldResetLoginError = true; // focus on login field when failed to log in const accountInput = this._accountInput; @@ -88,7 +91,7 @@ export default class Login extends Component<Props, State> { render() { return ( <Layout> - <Header showSettings={true} onSettings={this.props.onSettings} /> + <Header showSettings={true} onSettings={this.props.openSettings} /> <Container> <View style={styles.login_form}> {this._getStatusIcon()} @@ -110,7 +113,7 @@ export default class Login extends Component<Props, State> { ); } - _onCreateAccount = () => this.props.onExternalLink('createAccount'); + _onCreateAccount = () => this.props.openExternalLink('createAccount'); _onFocus = () => { this.setState({ isActive: true }); @@ -177,23 +180,24 @@ export default class Login extends Component<Props, State> { } _onLogin = () => { - const accountToken = this.props.account.accountToken; + const accountToken = this.props.accountToken; if (accountToken && accountToken.length > 0) { - this.props.onLogin(accountToken); + this.props.login(accountToken); } }; _onInputChange = (value: string) => { - // notify delegate on first change after login failure - if (this._notifyOnFirstChangeAfterFailure) { - this._notifyOnFirstChangeAfterFailure = false; - this.props.onFirstChangeAfterFailure(); + // reset error when user types in the new account number + if (this._shouldResetLoginError) { + this._shouldResetLoginError = false; + this.props.resetLoginError(); } - this.props.onAccountTokenChange(value); + + this.props.updateAccountToken(value); }; _formTitle() { - switch (this.props.account.status) { + switch (this.props.loginState) { case 'logging in': return 'Logging in...'; case 'failed': @@ -206,10 +210,10 @@ export default class Login extends Component<Props, State> { } _formSubtitle() { - const { status, error } = this.props.account; - switch (status) { + const { loginState, loginError } = this.props; + switch (loginState) { case 'failed': - return (error && error.message) || 'Unknown error'; + return (loginError && loginError.message) || 'Unknown error'; case 'logging in': return 'Checking account number'; default: @@ -227,7 +231,7 @@ export default class Login extends Component<Props, State> { } _getStatusIconPath(): ?string { - switch (this.props.account.status) { + switch (this.props.loginState) { case 'logging in': return 'icon-spinner'; case 'failed': @@ -245,7 +249,7 @@ export default class Login extends Component<Props, State> { classes.push(styles.account_input_group__active); } - switch (this.props.account.status) { + switch (this.props.loginState) { case 'logging in': classes.push(styles.account_input_group__inactive); break; @@ -258,10 +262,9 @@ export default class Login extends Component<Props, State> { } _accountInputButtonStyles(): Array<Object> { - const { status } = this.props.account; const classes = [styles.input_button]; - if (status === 'logging in') { + if (this.props.loginState === 'logging in') { classes.push(styles.input_button__invisible); } @@ -271,14 +274,14 @@ export default class Login extends Component<Props, State> { } _accountInputArrowStyles(): Array<Object> { - const { accountToken, status } = this.props.account; + const { accountToken, loginState } = this.props; const classes = [styles.input_arrow]; if (accountToken && accountToken.length > 0) { classes.push(styles.input_arrow__active); } - if (status === 'logging in') { + if (loginState === 'logging in') { classes.push(styles.input_arrow__invisible); } @@ -286,40 +289,54 @@ export default class Login extends Component<Props, State> { } _shouldActivateLoginButton() { - const { accountToken } = this.props.account; + const { accountToken } = this.props; return accountToken && accountToken.length > 0; } _shouldEnableAccountInput() { // enable account input always except when "logging in" - return this.props.account.status !== 'logging in'; + return this.props.loginState !== 'logging in'; } _shouldShowAccountHistory() { return ( this._shouldEnableAccountInput() && this.state.isActive && - this.props.account.accountHistory.length > 0 + this.props.accountHistory.length > 0 ); } _shouldShowLoginForm() { - return this.props.account.status !== 'ok'; + return this.props.loginState !== 'ok'; } _shouldShowFooter() { - const { status } = this.props.account; - return (status === 'none' || status === 'failed') && !this._shouldShowAccountHistory(); + return ( + (this.props.loginState === 'none' || this.props.loginState === 'failed') && + !this._shouldShowAccountHistory() + ); } _onSelectAccountFromHistory = (accountToken) => { - this.props.onAccountTokenChange(accountToken); - this.props.onLogin(accountToken); + this.props.updateAccountToken(accountToken); + this.props.login(accountToken); }; - _createLoginForm() { - const { accountHistory, accountToken } = this.props.account; + _onRemoveAccountFromHistory = (accountToken) => { + this._removeAccountFromHistory(accountToken); + }; + async _removeAccountFromHistory(accountToken: AccountToken) { + try { + await this.props.removeAccountTokenFromHistory(accountToken); + + // TODO: Remove account from memory + } catch (error) { + // TODO: Show error + } + } + + _createLoginForm() { return ( <View> <Text style={styles.subtitle}>{this._formSubtitle()}</Text> @@ -334,7 +351,7 @@ export default class Login extends Component<Props, State> { onBlur={this._onBlur} onChange={this._onInputChange} onEnter={this._onLogin} - value={accountToken || ''} + value={this.props.accountToken || ''} disabled={!this._shouldEnableAccountInput()} autoFocus={true} ref={(ref) => (this._accountInput = ref)} @@ -356,9 +373,9 @@ export default class Login extends Component<Props, State> { <Accordion height={this._shouldShowAccountHistory() ? 'auto' : 0}> { <AccountDropdown - items={accountHistory.slice().reverse()} + items={this.props.accountHistory.slice().reverse()} onSelect={this._onSelectAccountFromHistory} - onRemove={this.props.onRemoveAccountTokenFromHistory} + onRemove={this._onRemoveAccountFromHistory} /> } </Accordion> diff --git a/app/containers/LoginPage.js b/app/containers/LoginPage.js index 807c141799..fcf4dc8b7f 100644 --- a/app/containers/LoginPage.js +++ b/app/containers/LoginPage.js @@ -11,9 +11,15 @@ import { openLink } from '../lib/platform'; import type { ReduxState, ReduxDispatch } from '../redux/store'; import type { SharedRouteProps } from '../routes'; -const mapStateToProps = (state: ReduxState) => ({ - account: state.account, -}); +const mapStateToProps = (state: ReduxState) => { + const { accountToken, accountHistory, error, status } = state.account; + return { + accountToken, + accountHistory, + loginError: error, + loginState: status, + }; +}; const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => { const { push: pushHistory } = bindActionCreators({ push }, dispatch); const { login, resetLoginError, updateAccountToken } = bindActionCreators( @@ -22,20 +28,18 @@ const mapDispatchToProps = (dispatch: ReduxDispatch, props: SharedRouteProps) => ); const { backend } = props; return { - onSettings: () => { + openSettings: () => { pushHistory('/settings'); }, - onLogin: (account) => { + login: (account) => { login(backend, account); }, - onFirstChangeAfterFailure: () => { + resetLoginError: () => { resetLoginError(); }, - onExternalLink: (type) => openLink(links[type]), - onAccountTokenChange: (token) => { - updateAccountToken(token); - }, - onRemoveAccountTokenFromHistory: (token) => backend.removeAccountFromHistory(token), + openExternalLink: (type) => openLink(links[type]), + updateAccountToken: updateAccountToken, + removeAccountTokenFromHistory: (token) => backend.removeAccountFromHistory(token), }; }; diff --git a/app/lib/backend.js b/app/lib/backend.js index 75301df87a..3e128da0b1 100644 --- a/app/lib/backend.js +++ b/app/lib/backend.js @@ -222,7 +222,11 @@ export class Backend { const actions = this._reduxActions; try { - await Promise.all([this.disconnectTunnel(), this._daemonRpc.setAccount(null)]); + await Promise.all([ + this.disconnectTunnel(), + this._daemonRpc.setAccount(null), + this.fetchAccountHistory(), + ]); actions.account.loggedOut(); actions.history.push('/'); } catch (e) { @@ -526,6 +530,7 @@ export class Backend { this.fetchRelayLocations(), this.fetchAllowLan(), this.fetchLocation(), + this.fetchAccountHistory(), ]); } diff --git a/test/components/Login.spec.js b/test/components/Login.spec.js index 6a77313f5d..76acbd6330 100644 --- a/test/components/Login.spec.js +++ b/test/components/Login.spec.js @@ -73,7 +73,6 @@ const defaultProps = { login: (_accountToken) => {}, resetLoginError: () => {}, updateAccountToken: (_accountToken) => {}, - fetchAccountTokenHistory: () => Promise.resolve(), removeAccountTokenFromHistory: (_accountToken) => Promise.resolve(), }; |
