diff options
| author | Andrej Mihajlov <and@mullvad.net> | 2018-06-01 16:13:10 +0200 |
|---|---|---|
| committer | Andrej Mihajlov <and@mullvad.net> | 2018-06-05 12:11:55 +0200 |
| commit | ca2f6fbfcad7b73d4ea63ef46cb1cab943ec9087 (patch) | |
| tree | b1f7754eb50896ab3681e35fa4e08be642b940c9 /app/components/Login.js | |
| parent | 5852c980980de53e00d76a0bdb4b41bf5c0f5b39 (diff) | |
| download | mullvadvpn-ca2f6fbfcad7b73d4ea63ef46cb1cab943ec9087.tar.xz mullvadvpn-ca2f6fbfcad7b73d4ea63ef46cb1cab943ec9087.zip | |
Add formatted source code
Diffstat (limited to 'app/components/Login.js')
| -rw-r--r-- | app/components/Login.js | 320 |
1 files changed, 183 insertions, 137 deletions
diff --git a/app/components/Login.js b/app/components/Login.js index b711f089b5..3100cc54f0 100644 --- a/app/components/Login.js +++ b/app/components/Login.js @@ -16,7 +16,7 @@ import type { AccountToken } from '../lib/ipc-facade'; export type LoginPropTypes = { account: AccountReduxState, onLogin: (accountToken: AccountToken) => void, - onSettings: ?(() => void), + onSettings: ?() => void, onFirstChangeAfterFailure: () => void, onExternalLink: (type: string) => void, onAccountTokenChange: (accountToken: AccountToken) => void, @@ -48,14 +48,18 @@ export default class Login extends Component<LoginPropTypes, State> { constructor(props: LoginPropTypes) { super(props); - if(props.account.status === 'failed') { + if (props.account.status === 'failed') { this.state.notifyOnFirstChangeAfterFailure = true; } this.state.footerAnimationStyle = Styles.createAnimatedViewStyle({ - transform: [{translateY: this.state.animatedFooterValue }] + transform: [{ translateY: this.state.animatedFooterValue }], }); this.state.loginButtonAnimationStyle = Styles.createAnimatedViewStyle({ - backgroundColor: Animated.interpolate(this.state.animatedLoginButtonValue, [0.0, 1.0], [colors.white, colors.green]), + backgroundColor: Animated.interpolate( + this.state.animatedLoginButtonValue, + [0.0, 1.0], + [colors.white, colors.green], + ), }); } @@ -63,7 +67,7 @@ export default class Login extends Component<LoginPropTypes, State> { const prev = this.props.account || {}; const next = nextProps.account || {}; - if(prev.status !== next.status && next.status === 'failed') { + if (prev.status !== next.status && next.status === 'failed') { this.setState({ notifyOnFirstChangeAfterFailure: true }); } @@ -73,36 +77,38 @@ export default class Login extends Component<LoginPropTypes, State> { render() { return ( <Layout> - <Header showSettings={ true } onSettings={ this.props.onSettings } /> + <Header showSettings={true} onSettings={this.props.onSettings} /> <Container> <View style={styles.login_form}> - { this._getStatusIcon() } - <Text style={styles.title}>{ this._formTitle() }</Text> + {this._getStatusIcon()} + <Text style={styles.title}>{this._formTitle()}</Text> - {this._shouldShowLoginForm() && <View> - { this._createLoginForm() } - </View>} + {this._shouldShowLoginForm() && <View>{this._createLoginForm()}</View>} </View> - <Animated.View onLayout={this._onFooterLayout} style={[styles.login_footer, this.state.footerAnimationStyle]} testName={'footerVisibility ' + this._shouldShowFooter(this.props).toString()}> - { this._createFooter() } + <Animated.View + onLayout={this._onFooterLayout} + style={[styles.login_footer, this.state.footerAnimationStyle]} + testName={'footerVisibility ' + this._shouldShowFooter(this.props).toString()}> + {this._createFooter()} </Animated.View> </Container> </Layout> ); } - _onCreateAccount = () => this.props.onExternalLink('createAccount') + _onCreateAccount = () => this.props.onExternalLink('createAccount'); - _onFocus = () => this.setState({ isActive: true }, () => { - this._animate(this.props); - }) + _onFocus = () => + this.setState({ isActive: true }, () => { + this._animate(this.props); + }); _onBlur = (e) => { const relatedTarget = e.relatedTarget; // restore focus if click happened within dropdown - if(relatedTarget) { + if (relatedTarget) { e.target.focus(); return; } @@ -110,7 +116,7 @@ export default class Login extends Component<LoginPropTypes, State> { this.setState({ isActive: false }, () => { this._animate(this.props); }); - } + }; _animate = (props: LoginPropTypes) => { if (this.state.animation) { @@ -119,95 +125,103 @@ export default class Login extends Component<LoginPropTypes, State> { const accountToken = props.account.accountToken || []; const footerPosition = this._shouldShowFooter(props) ? 0 : this.state.footerHeight; - const loginButtonValue = (accountToken.length) > 0 ? 1 : 0; - this._setAnimation(this._getFooterAnimation(footerPosition), this._getLoginButtonAnimation(loginButtonValue)); - } + const loginButtonValue = accountToken.length > 0 ? 1 : 0; + this._setAnimation( + this._getFooterAnimation(footerPosition), + this._getLoginButtonAnimation(loginButtonValue), + ); + }; - _setAnimation = (footerAnimation: Animated.CompositeAnimation, loginButtonAnimation: Animated.CompositeAnimation) => { - let compositeAnimation = Animated.parallel([ footerAnimation, loginButtonAnimation]); - this.setState({animation: compositeAnimation}, () => { - compositeAnimation.start(() => this.setState({ - animation: null - })); + _setAnimation = ( + footerAnimation: Animated.CompositeAnimation, + loginButtonAnimation: Animated.CompositeAnimation, + ) => { + let compositeAnimation = Animated.parallel([footerAnimation, loginButtonAnimation]); + this.setState({ animation: compositeAnimation }, () => { + compositeAnimation.start(() => + this.setState({ + animation: null, + }), + ); }); - } + }; _onLogin = () => { const accountToken = this.props.account.accountToken; - if(accountToken && accountToken.length > 0) { + if (accountToken && accountToken.length > 0) { this.props.onLogin(accountToken); } - } + }; _onInputChange = (value: string) => { // notify delegate on first change after login failure - if(this.state.notifyOnFirstChangeAfterFailure) { + if (this.state.notifyOnFirstChangeAfterFailure) { this.setState({ notifyOnFirstChangeAfterFailure: false }); this.props.onFirstChangeAfterFailure(); } this.props.onAccountTokenChange(value); - } + }; _formTitle() { - switch(this.props.account.status) { - case 'logging in': - return 'Logging in...'; - case 'failed': - return 'Login failed'; - case 'ok': - return 'Login successful'; - default: - return 'Login'; + switch (this.props.account.status) { + case 'logging in': + return 'Logging in...'; + case 'failed': + return 'Login failed'; + case 'ok': + return 'Login successful'; + default: + return 'Login'; } } _formSubtitle() { const { status, error } = this.props.account; - switch(status) { - case 'failed': - return (error && error.message) || 'Unknown error'; - case 'logging in': - return 'Checking account number'; - default: - return 'Enter your account number'; + switch (status) { + case 'failed': + return (error && error.message) || 'Unknown error'; + case 'logging in': + return 'Checking account number'; + default: + return 'Enter your account number'; } } _getStatusIcon() { const statusIconPath = this._getStatusIconPath(); - return <View style={ styles.status_icon}> - { statusIconPath ? - <Img source={ statusIconPath } height={48} width={48} alt="" /> : - null } - </View>; + return ( + <View style={styles.status_icon}> + {statusIconPath ? <Img source={statusIconPath} height={48} width={48} alt="" /> : null} + </View> + ); } _getStatusIconPath(): ?string { - switch(this.props.account.status) { - case 'logging in': - return 'icon-spinner'; - case 'failed': - return 'icon-fail'; - case 'ok': - return 'icon-success'; - default: - return undefined; + switch (this.props.account.status) { + case 'logging in': + return 'icon-spinner'; + case 'failed': + return 'icon-fail'; + case 'ok': + return 'icon-success'; + default: + return undefined; } } _accountInputGroupStyles(): Array<Object> { const classes = [styles.account_input_group]; - if(this.state.isActive) { + if (this.state.isActive) { classes.push(styles.account_input_group__active); } - switch(this.props.account.status) { - case 'logging in': - classes.push(styles.account_input_group__inactive); - break; - case 'failed': - classes.push(styles.account_input_group__error); - break; + switch (this.props.account.status) { + case 'logging in': + classes.push(styles.account_input_group__inactive); + break; + case 'failed': + classes.push(styles.account_input_group__error); + break; } return classes; @@ -217,7 +231,7 @@ export default class Login extends Component<LoginPropTypes, State> { const { status } = this.props.account; const classes = [styles.input_button]; - if(status === 'logging in') { + if (status === 'logging in') { classes.push(styles.input_button__invisible); } @@ -230,11 +244,11 @@ export default class Login extends Component<LoginPropTypes, State> { const { accountToken, status } = this.props.account; const classes = [styles.input_arrow]; - if(accountToken && accountToken.length > 0) { + if (accountToken && accountToken.length > 0) { classes.push(styles.input_arrow__active); } - if(status === 'logging in') { + if (status === 'logging in') { classes.push(styles.input_arrow__invisible); } @@ -247,9 +261,11 @@ export default class Login extends Component<LoginPropTypes, State> { } _shouldShowAccountHistory(props: LoginPropTypes) { - return this._shouldEnableAccountInput(props) && + return ( + this._shouldEnableAccountInput(props) && this.state.isActive && - props.account.accountHistory.length > 0; + props.account.accountHistory.length > 0 + ); } _shouldShowLoginForm() { @@ -261,7 +277,7 @@ export default class Login extends Component<LoginPropTypes, State> { return (status === 'none' || status === 'failed') && !this._shouldShowAccountHistory(props); } - _getFooterAnimation(toValue: number){ + _getFooterAnimation(toValue: number) { return Animated.timing(this.state.animatedFooterValue, { toValue: toValue, easing: Animated.Easing.InOut(), @@ -271,10 +287,10 @@ export default class Login extends Component<LoginPropTypes, State> { } _onFooterLayout = (layout) => { - this.setState({footerHeight: layout.height}); - } + this.setState({ footerHeight: layout.height }); + }; - _getLoginButtonAnimation(toValue: number){ + _getLoginButtonAnimation(toValue: number) { return Animated.timing(this.state.animatedLoginButtonValue, { toValue: toValue, easing: Animated.Easing.Linear(), @@ -286,7 +302,7 @@ export default class Login extends Component<LoginPropTypes, State> { _onSelectAccountFromHistory = (accountToken) => { this.props.onAccountTokenChange(accountToken); this.props.onLogin(accountToken); - } + }; _createLoginForm() { const { accountHistory, accountToken } = this.props.account; @@ -295,50 +311,68 @@ export default class Login extends Component<LoginPropTypes, State> { // do not refactor this into instance method, // it has to be new function each time to be called on each render const autoFocusOnFailure = (input) => { - if(this.props.account.status === 'failed' && input) { + if (this.props.account.status === 'failed' && input) { input.focus(); } }; - return <View> - <Text style={ styles.subtitle }>{ this._formSubtitle() }</Text> - <View style={ this._accountInputGroupStyles() }> - <View style={ styles.account_input_backdrop}> - <AccountInput style={styles.account_input_textfield} - type="text" - placeholder="0000 0000 0000 0000" - placeholderTextColor={colors.blue40} - onFocus={ this._onFocus } - onBlur={ this._onBlur } - onChange={ this._onInputChange } - onEnter={ this._onLogin } - value={ accountToken || '' } - disabled={ !this._shouldEnableAccountInput(this.props) } - autoFocus={ true } - ref={ autoFocusOnFailure } - testName='AccountInput'/> - <Animated.View style={this._accountInputButtonStyles()} onPress={ this._onLogin } testName='account-input-button'> - <Img style={this._accountInputArrowStyles()} source='icon-arrow' height={16} width={24} tintColor='currentColor' /> - </Animated.View> + return ( + <View> + <Text style={styles.subtitle}>{this._formSubtitle()}</Text> + <View style={this._accountInputGroupStyles()}> + <View style={styles.account_input_backdrop}> + <AccountInput + style={styles.account_input_textfield} + type="text" + placeholder="0000 0000 0000 0000" + placeholderTextColor={colors.blue40} + onFocus={this._onFocus} + onBlur={this._onBlur} + onChange={this._onInputChange} + onEnter={this._onLogin} + value={accountToken || ''} + disabled={!this._shouldEnableAccountInput(this.props)} + autoFocus={true} + ref={autoFocusOnFailure} + testName="AccountInput" + /> + <Animated.View + style={this._accountInputButtonStyles()} + onPress={this._onLogin} + testName="account-input-button"> + <Img + style={this._accountInputArrowStyles()} + source="icon-arrow" + height={16} + width={24} + tintColor="currentColor" + /> + </Animated.View> + </View> + <Accordion height={this._shouldShowAccountHistory(this.props) ? 'auto' : 0}> + { + <AccountDropdown + items={accountHistory.slice().reverse()} + onSelect={this._onSelectAccountFromHistory} + onRemove={this.props.onRemoveAccountTokenFromHistory} + /> + } + </Accordion> </View> - <Accordion height={ this._shouldShowAccountHistory(this.props) ? 'auto' : 0 }> - { <AccountDropdown - items={ accountHistory.slice().reverse() } - onSelect={ this._onSelectAccountFromHistory } - onRemove={ this.props.onRemoveAccountTokenFromHistory } /> } - </Accordion> </View> - </View>; + ); } _createFooter() { - return <View> - <Text style={ styles.login_footer__prompt}>{ 'Don\'t have an account number?' }</Text> - <BlueButton onPress={ this._onCreateAccount }> - <Label>Create account</Label> - <Img source='icon-extLink' height={16} width={16} /> - </BlueButton> - </View>; + return ( + <View> + <Text style={styles.login_footer__prompt}>{"Don't have an account number?"}</Text> + <BlueButton onPress={this._onCreateAccount}> + <Label>Create account</Label> + <Img source="icon-extLink" height={16} width={16} /> + </BlueButton> + </View> + ); } } @@ -353,13 +387,15 @@ class AccountDropdown extends React.Component<AccountDropdownProps> { const uniqueItems = [...new Set(this.props.items)]; return ( <View> - { uniqueItems.map(token => ( - <AccountDropdownItem key={ token } - value={ token } - label={ formatAccount(token) } - onSelect={ this.props.onSelect } - onRemove={ this.props.onRemove } /> - )) } + {uniqueItems.map((token) => ( + <AccountDropdownItem + key={token} + value={token} + label={formatAccount(token)} + onSelect={this.props.onSelect} + onRemove={this.props.onRemove} + /> + ))} </View> ); } @@ -374,19 +410,29 @@ type AccountDropdownItemProps = { class AccountDropdownItem extends React.Component<AccountDropdownItemProps> { render() { - return (<View> - <View style={ styles.account_dropdown__spacer }/> - <CellButton style={ styles.account_dropdown__item } cellHoverStyle={ styles.account_dropdown__item_hover }> - <Label style={styles.account_dropdown__label} cellHoverStyle={ styles.account_dropdown__label_hover } onPress={ () => this.props.onSelect(this.props.value) }> - { this.props.label } - </Label> - <Img style={styles.account_dropdown__remove} - cellHoverStyle={ styles.account_dropdown__remove_cell_hover } - hoverStyle={ styles.account_dropdown__remove_hover } - source='icon-close-sml' - height={16} width={16} - onPress={ () => this.props.onRemove(this.props.value) }/> - </CellButton> - </View>); + return ( + <View> + <View style={styles.account_dropdown__spacer} /> + <CellButton + style={styles.account_dropdown__item} + cellHoverStyle={styles.account_dropdown__item_hover}> + <Label + style={styles.account_dropdown__label} + cellHoverStyle={styles.account_dropdown__label_hover} + onPress={() => this.props.onSelect(this.props.value)}> + {this.props.label} + </Label> + <Img + style={styles.account_dropdown__remove} + cellHoverStyle={styles.account_dropdown__remove_cell_hover} + hoverStyle={styles.account_dropdown__remove_hover} + source="icon-close-sml" + height={16} + width={16} + onPress={() => this.props.onRemove(this.props.value)} + /> + </CellButton> + </View> + ); } } |
