-
Notifications
You must be signed in to change notification settings - Fork 3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Error modal when signin from expired magic link #15505
Changes from 18 commits
9de436b
4571bc2
4dfdcf0
7911733
abcf1f9
42dbf4b
7483f9a
ffb52ea
61a15e8
b601db1
fdca7c1
9af3f8a
2ec71ac
3497d94
ab1911a
7c4cd9a
61e702e
c63438a
177b9d2
a8ceaca
7632b8e
b8f6cb4
939d507
3b66d81
6900b03
73aa412
02c753d
c84620d
e191d90
a6fee31
4393c6f
c2ac666
7266f07
8e95a5f
2ff6376
6a80fe5
5354ea4
c3ec252
ae59b49
76abf00
13460c8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import React, {PureComponent} from 'react'; | ||
import {View} from 'react-native'; | ||
import colors from '../../styles/colors'; | ||
import styles from '../../styles/styles'; | ||
import Icon from '../Icon'; | ||
import withLocalize, {withLocalizePropTypes} from '../withLocalize'; | ||
import Text from '../Text'; | ||
import * as Expensicons from '../Icon/Expensicons'; | ||
import * as Illustrations from '../Icon/Illustrations'; | ||
import variables from '../../styles/variables'; | ||
|
||
const propTypes = { | ||
|
||
cristipaval marked this conversation as resolved.
Show resolved
Hide resolved
|
||
...withLocalizePropTypes, | ||
}; | ||
|
||
class AbracadabraModal extends PureComponent { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB but this should be a functional component w/ memo, which is typically what we do for components that don't have state or use lifecycle methods. |
||
render() { | ||
return ( | ||
<View style={styles.deeplinkWrapperContainer}> | ||
<View style={styles.deeplinkWrapperMessage}> | ||
<View style={styles.mb2}> | ||
<Icon | ||
width={variables.modalTopIconWidth} | ||
height={variables.modalTopBigIconHeight} | ||
src={Illustrations.Abracadabra} | ||
/> | ||
</View> | ||
<Text style={[styles.textHeadline, styles.textXXLarge, styles.textAlignCenter]}> | ||
{this.props.translate('validateCodeModal.successfulSignInTitle')} | ||
</Text> | ||
<View style={[styles.mt2, styles.mb2]}> | ||
<Text style={[styles.fontSizeNormal, styles.textAlignCenter]}> | ||
{this.props.translate('validateCodeModal.successfulSignInDescription')} | ||
</Text> | ||
</View> | ||
</View> | ||
<View style={styles.deeplinkWrapperFooter}> | ||
<Icon | ||
width={variables.modalWordmarkWidth} | ||
height={variables.modalWordmarkHeight} | ||
fill={colors.green} | ||
src={Expensicons.ExpensifyWordmark} | ||
/> | ||
</View> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
AbracadabraModal.propTypes = propTypes; | ||
export default withLocalize(AbracadabraModal); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import React, {PureComponent} from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import {withOnyx} from 'react-native-onyx'; | ||
import _, {compose} from 'underscore'; | ||
import lodashGet from 'lodash/get'; | ||
import {View} from 'react-native'; | ||
import colors from '../../styles/colors'; | ||
import styles from '../../styles/styles'; | ||
import Icon from '../Icon'; | ||
import withLocalize, {withLocalizePropTypes} from '../withLocalize'; | ||
import Text from '../Text'; | ||
import * as Expensicons from '../Icon/Expensicons'; | ||
import * as Illustrations from '../Icon/Illustrations'; | ||
import variables from '../../styles/variables'; | ||
import TextLink from '../TextLink'; | ||
import ONYXKEYS from '../../ONYXKEYS'; | ||
import * as ErrorUtils from '../../libs/ErrorUtils'; | ||
|
||
const propTypes = { | ||
|
||
cristipaval marked this conversation as resolved.
Show resolved
Hide resolved
|
||
/** Whether the user can a new validate code from the current page */ | ||
shouldShowRequestCodeLink: PropTypes.bool, | ||
|
||
/** Callback to be called when user clicks the request code link */ | ||
onRequestCodeClick: PropTypes.func, | ||
|
||
...withLocalizePropTypes, | ||
}; | ||
|
||
const defaultProps = { | ||
shouldShowRequestCodeLink: false, | ||
onRequestCodeClick: () => {}, | ||
}; | ||
|
||
class ExpiredValidateCodeModal extends PureComponent { | ||
render() { | ||
const codeRequestedMessage = lodashGet(this.props, 'account.message', null); | ||
const accountErrors = lodashGet(this.props, 'account.errors', {}); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. NAB but I think we can simplify this part as
|
||
let codeRequestedErrors; | ||
if (_.keys(accountErrors).length > 1) { | ||
codeRequestedErrors = ErrorUtils.getLatestErrorMessage(this.props.account); | ||
} | ||
return ( | ||
<View style={styles.deeplinkWrapperContainer}> | ||
<View style={styles.deeplinkWrapperMessage}> | ||
<View style={styles.mb2}> | ||
<Icon | ||
width={variables.modalTopIconWidth} | ||
height={variables.modalTopIconHeight} | ||
src={Illustrations.ToddBehindCloud} | ||
/> | ||
</View> | ||
<Text style={[styles.textHeadline, styles.textXXLarge, styles.textAlignCenter]}> | ||
{this.props.translate('validateCodeModal.expiredCodeTitle')} | ||
</Text> | ||
<View style={[styles.mt2, styles.mb2]}> | ||
<Text style={[styles.fontSizeNormal, styles.textAlignCenter]}> | ||
{this.props.translate('validateCodeModal.expiredCodeDescription')} | ||
{this.props.shouldShowRequestCodeLink && !codeRequestedMessage | ||
&& ( | ||
<> | ||
<br /> | ||
{this.props.translate('validateCodeModal.requestNewCode')} | ||
{' '} | ||
<TextLink onPress={this.props.onRequestCodeClick}> | ||
{this.props.translate('validateCodeModal.requestNewCodeLink')} | ||
</TextLink> | ||
! | ||
</> | ||
)} | ||
</Text> | ||
{this.props.shouldShowRequestCodeLink && codeRequestedErrors | ||
&& ( | ||
<Text style={[styles.textDanger, styles.validateCodeMessage]}> | ||
<br /> | ||
<br /> | ||
|
||
{codeRequestedErrors} | ||
|
||
cristipaval marked this conversation as resolved.
Show resolved
Hide resolved
|
||
</Text> | ||
)} | ||
{this.props.shouldShowRequestCodeLink && codeRequestedMessage | ||
&& ( | ||
<Text style={styles.validateCodeMessage}> | ||
<br /> | ||
<br /> | ||
{codeRequestedMessage} | ||
</Text> | ||
)} | ||
</View> | ||
</View> | ||
<View style={styles.deeplinkWrapperFooter}> | ||
<Icon | ||
width={variables.modalWordmarkWidth} | ||
height={variables.modalWordmarkHeight} | ||
fill={colors.green} | ||
src={Expensicons.ExpensifyWordmark} | ||
/> | ||
</View> | ||
</View> | ||
); | ||
} | ||
} | ||
|
||
ExpiredValidateCodeModal.propTypes = propTypes; | ||
ExpiredValidateCodeModal.defaultProps = defaultProps; | ||
export default compose( | ||
withLocalize, | ||
withOnyx({ | ||
account: {key: ONYXKEYS.ACCOUNT}, | ||
}), | ||
)(ExpiredValidateCodeModal); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file is almost exactly the same as
TfaRequiredModal
, and has only minimal differences with the other two components in this directory. I think it would be valuable to DRY these up by creating aValidateCodeModalLayout
component, and use it in the other components you've created here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey @roryabraham ! Thanks for the review! I do agree that we can dry up the code here. I spent a lot of time on this PR due to that challenge that I was facing (
componentDidMount
being called twice). I created components for each state just to simplify the code inVaidateLoginPage
. But now it looks like I ended up having duplicate code. Now that I solved the aforementioned challenge, I totally do agree I can reuse the same component for multiple states. I created this follow-up issue for your suggested refactor.