-
Notifications
You must be signed in to change notification settings - Fork 945
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #846 from sharetribe/extract-missing-information-m…
…odal Extract missing information modal
- Loading branch information
Showing
8 changed files
with
311 additions
and
191 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
import React from 'react'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import { isTooManyEmailVerificationRequestsError } from '../../util/errors'; | ||
import { IconEmailAttention, InlineTextButton, NamedLink } from '../../components'; | ||
|
||
import css from './ModalMissingInformation.css'; | ||
|
||
const EmailReminder = props => { | ||
const { | ||
className, | ||
user, | ||
sendVerificationEmailInProgress, | ||
sendVerificationEmailError, | ||
onResendVerificationEmail, | ||
} = props; | ||
|
||
const email = user.id ? <span className={css.email}>{user.attributes.email}</span> : ''; | ||
|
||
const resendEmailLink = ( | ||
<InlineTextButton className={css.helperLink} onClick={onResendVerificationEmail}> | ||
<FormattedMessage id="ModalMissingInformation.resendEmailLinkText" /> | ||
</InlineTextButton> | ||
); | ||
|
||
const fixEmailLink = ( | ||
<NamedLink className={css.helperLink} name="ContactDetailsPage"> | ||
<FormattedMessage id="ModalMissingInformation.fixEmailLinkText" /> | ||
</NamedLink> | ||
); | ||
|
||
const resendErrorTranslationId = isTooManyEmailVerificationRequestsError( | ||
sendVerificationEmailError | ||
) | ||
? 'ModalMissingInformation.resendFailedTooManyRequests' | ||
: 'ModalMissingInformation.resendFailed'; | ||
const resendErrorMessage = sendVerificationEmailError ? ( | ||
<p className={css.error}> | ||
<FormattedMessage id={resendErrorTranslationId} /> | ||
</p> | ||
) : null; | ||
|
||
return ( | ||
<div className={className}> | ||
<IconEmailAttention className={css.modalIcon} /> | ||
<p className={css.modalTitle}> | ||
<FormattedMessage id="ModalMissingInformation.verifyEmailTitle" /> | ||
</p> | ||
<p className={css.modalMessage}> | ||
<FormattedMessage id="ModalMissingInformation.verifyEmailText" /> | ||
</p> | ||
<p className={css.modalMessage}> | ||
<FormattedMessage id="ModalMissingInformation.checkInbox" values={{ email }} /> | ||
</p> | ||
{resendErrorMessage} | ||
|
||
<div className={css.bottomWrapper}> | ||
<p className={css.helperText}> | ||
{sendVerificationEmailInProgress ? ( | ||
<FormattedMessage id="ModalMissingInformation.sendingEmail" /> | ||
) : ( | ||
<FormattedMessage | ||
id="ModalMissingInformation.resendEmail" | ||
values={{ resendEmailLink }} | ||
/> | ||
)} | ||
</p> | ||
<p className={css.helperText}> | ||
<FormattedMessage id="ModalMissingInformation.fixEmail" values={{ fixEmailLink }} /> | ||
</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default EmailReminder; |
3 changes: 3 additions & 0 deletions
3
src/components/ModalMissingInformation/ModalMissingInformation.css
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.root { | ||
/* Adding empty .root class to enforce className overwrite */ | ||
} |
171 changes: 171 additions & 0 deletions
171
src/components/ModalMissingInformation/ModalMissingInformation.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import React, { Component } from 'react'; | ||
import { bool, func, string } from 'prop-types'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import classNames from 'classnames'; | ||
import routeConfiguration from '../../routeConfiguration'; | ||
import { ensureCurrentUser } from '../../util/data'; | ||
import { propTypes } from '../../util/types'; | ||
import { pathByRouteName } from '../../util/routes'; | ||
import { Modal } from '../../components'; | ||
|
||
import EmailReminder from './EmailReminder'; | ||
import StripeAccountReminder from './StripeAccountReminder'; | ||
import css from './ModalMissingInformation.css'; | ||
|
||
const MISSING_INFORMATION_MODAL_WHITELIST = [ | ||
'LoginPage', | ||
'SignupPage', | ||
'ContactDetailsPage', | ||
'EmailVerificationPage', | ||
'PasswordResetPage', | ||
'PayoutPreferencesPage', | ||
]; | ||
|
||
const EMAIL_VERIFICATION = 'EMAIL_VERIFICATION'; | ||
const STRIPE_ACCOUNT = 'STRIPE_ACCOUNT'; | ||
|
||
class ModalMissingInformation extends Component { | ||
constructor(props) { | ||
super(props); | ||
|
||
this.state = { | ||
showMissingInformationReminder: null, | ||
hasSeenMissingInformationReminder: false, | ||
}; | ||
this.handleMissingInformationReminder = this.handleMissingInformationReminder.bind(this); | ||
} | ||
|
||
componentWillReceiveProps(nextProps) { | ||
const { currentUser, currentUserHasListings, currentUserHasOrders, location } = nextProps; | ||
const user = ensureCurrentUser(currentUser); | ||
this.handleMissingInformationReminder( | ||
user, | ||
currentUserHasListings, | ||
currentUserHasOrders, | ||
location | ||
); | ||
} | ||
|
||
handleMissingInformationReminder( | ||
currentUser, | ||
currentUserHasListings, | ||
currentUserHasOrders, | ||
newLocation | ||
) { | ||
const routes = routeConfiguration(); | ||
const whitelistedPaths = MISSING_INFORMATION_MODAL_WHITELIST.map(page => | ||
pathByRouteName(page, routes) | ||
); | ||
|
||
// Is the current page whitelisted? | ||
const isPageWhitelisted = whitelistedPaths.includes(newLocation.pathname); | ||
|
||
// Track if path changes inside Page level component | ||
const pathChanged = newLocation.pathname !== this.props.location.pathname; | ||
const notRemindedYet = | ||
!this.state.showMissingInformationReminder && !this.state.hasSeenMissingInformationReminder; | ||
|
||
// Is the reminder already shown on current page | ||
const showOnPathChange = notRemindedYet || pathChanged; | ||
|
||
if (!isPageWhitelisted && showOnPathChange) { | ||
// Emails are sent when order is initiated | ||
// Customer is likely to get email soon when she books something | ||
// Provider email should work - she should get an email when someone books a listing | ||
const hasOrders = currentUserHasOrders === true; | ||
const hasListingsOrOrders = currentUserHasListings || hasOrders; | ||
|
||
const emailUnverified = !!currentUser.id && !currentUser.attributes.emailVerified; | ||
const emailVerificationNeeded = hasListingsOrOrders && emailUnverified; | ||
|
||
const stripeAccountMissing = !!currentUser.id && !currentUser.attributes.stripeConnected; | ||
const stripeAccountNeeded = currentUserHasListings && stripeAccountMissing; | ||
|
||
// Show reminder | ||
if (emailVerificationNeeded) { | ||
this.setState({ showMissingInformationReminder: EMAIL_VERIFICATION }); | ||
} else if (stripeAccountNeeded) { | ||
this.setState({ showMissingInformationReminder: STRIPE_ACCOUNT }); | ||
} | ||
} | ||
} | ||
|
||
render() { | ||
const { | ||
rootClassName, | ||
className, | ||
containerClassName, | ||
currentUser, | ||
sendVerificationEmailInProgress, | ||
sendVerificationEmailError, | ||
onManageDisableScrolling, | ||
onResendVerificationEmail, | ||
} = this.props; | ||
|
||
const user = ensureCurrentUser(currentUser); | ||
const classes = classNames(rootClassName || css.root, className); | ||
|
||
let content = null; | ||
|
||
const currentUserLoaded = user && user.id; | ||
if (currentUserLoaded) { | ||
if (this.state.showMissingInformationReminder === EMAIL_VERIFICATION) { | ||
content = ( | ||
<EmailReminder | ||
className={classes} | ||
user={user} | ||
onResendVerificationEmail={onResendVerificationEmail} | ||
sendVerificationEmailInProgress={sendVerificationEmailInProgress} | ||
sendVerificationEmailError={sendVerificationEmailError} | ||
/> | ||
); | ||
} else if (this.state.showMissingInformationReminder === STRIPE_ACCOUNT) { | ||
content = <StripeAccountReminder className={classes} />; | ||
} | ||
} | ||
|
||
const closeButtonMessage = ( | ||
<FormattedMessage id="ModalMissingInformation.closeVerifyEmailReminder" /> | ||
); | ||
|
||
return ( | ||
<Modal | ||
id="MissingInformationReminder" | ||
containerClassName={containerClassName} | ||
isOpen={!!this.state.showMissingInformationReminder} | ||
onClose={() => { | ||
this.setState({ | ||
showMissingInformationReminder: null, | ||
hasSeenMissingInformationReminder: true, | ||
}); | ||
}} | ||
onManageDisableScrolling={onManageDisableScrolling} | ||
closeButtonMessage={closeButtonMessage} | ||
> | ||
{content} | ||
</Modal> | ||
); | ||
} | ||
} | ||
|
||
ModalMissingInformation.defaultProps = { | ||
className: null, | ||
rootClassName: null, | ||
currentUser: null, | ||
}; | ||
|
||
ModalMissingInformation.propTypes = { | ||
id: string.isRequired, | ||
className: string, | ||
rootClassName: string, | ||
containerClassName: string, | ||
|
||
currentUser: propTypes.currentUser, | ||
onManageDisableScrolling: func.isRequired, | ||
sendVerificationEmailError: propTypes.error, | ||
sendVerificationEmailInProgress: bool.isRequired, | ||
}; | ||
|
||
ModalMissingInformation.displayName = 'ModalMissingInformation'; | ||
|
||
export default ModalMissingInformation; |
27 changes: 27 additions & 0 deletions
27
src/components/ModalMissingInformation/StripeAccountReminder.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
import React from 'react'; | ||
import { FormattedMessage } from 'react-intl'; | ||
import { NamedLink } from '../../components'; | ||
|
||
import css from './ModalMissingInformation.css'; | ||
|
||
const StripeAccountReminder = props => { | ||
const { className } = props; | ||
|
||
return ( | ||
<div className={className}> | ||
<p className={css.modalTitle}> | ||
<FormattedMessage id="ModalMissingInformation.missingStripeAccountTitle" /> | ||
</p> | ||
<p className={css.modalMessage}> | ||
<FormattedMessage id="ModalMissingInformation.missingStripeAccountText" /> | ||
</p> | ||
<div className={css.bottomWrapper}> | ||
<NamedLink className={css.reminderModalLinkButton} name="PayoutPreferencesPage"> | ||
<FormattedMessage id="ModalMissingInformation.gotoPaymentSettings" /> | ||
</NamedLink> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default StripeAccountReminder; |
Oops, something went wrong.