mirror of
https://github.com/kingomarnajjar/flex-template-web.git
synced 2026-07-28 20:53:24 +10:00
Merge pull request #430 from sharetribe/contactdetailspage
Contactdetailspage
This commit is contained in:
commit
cf1937c203
15 changed files with 447 additions and 13 deletions
|
|
@ -34,7 +34,7 @@
|
|||
"redux-thunk": "^2.2.0",
|
||||
"sanitize.css": "^5.0.0",
|
||||
"sharetribe-scripts": "0.9.2",
|
||||
"sharetribe-sdk": "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#0bc2a2e82be2c5eadbc22e511a750a2a91dc0fd5",
|
||||
"sharetribe-sdk": "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#2c7f3d323c5e7a7c4c93ef38962c236859b83bab",
|
||||
"source-map-support": "^0.4.15",
|
||||
"url": "^0.11.0"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -36,10 +36,11 @@
|
|||
.contentWrapper {
|
||||
|
||||
/* Expand to the full remaining width of the viewport */
|
||||
flex: 1;
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
padding: 24px;
|
||||
|
||||
@media (--viewportLarge) {
|
||||
padding: 118px 15vw 82px 82px;
|
||||
|
|
|
|||
120
src/containers/ContactDetailsForm/ContactDetailsForm.css
Normal file
120
src/containers/ContactDetailsForm/ContactDetailsForm.css
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
:root {
|
||||
|
||||
--infoTextStyles: {
|
||||
@apply --marketplaceH4FontStyles;
|
||||
color: var(--successColor);
|
||||
|
||||
display: inline-block;
|
||||
padding-left: 18px;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top 7px left;
|
||||
|
||||
margin-top: 11px;
|
||||
margin-bottom: 0;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 14px;
|
||||
margin-bottom: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.root {}
|
||||
|
||||
.emailSection {
|
||||
margin-top: 16px;
|
||||
margin-bottom: 46px;
|
||||
padding-top: 6px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-bottom: 56px;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmChangesSection {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-bottom: 60px;
|
||||
padding: 0;
|
||||
|
||||
@media (--viewportLarge) {
|
||||
padding: 4px 0 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
.emailVerified {
|
||||
@apply --infoTextStyles;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M6.52 9.098c-.163.188-.397.3-.646.31h-.032c-.238 0-.466-.094-.635-.263L2.783 6.732c-.353-.35-.354-.92-.003-1.273.35-.353.92-.354 1.272-.004L5.794 7.19l4.59-5.278C9.287.738 7.73 0 6 0 2.686 0 0 2.686 0 6c0 3.313 2.686 6 6 6 3.313 0 6-2.687 6-6 0-.91-.21-1.772-.573-2.545L6.52 9.098z" fill="%232ECC71" fill-rule="evenodd"/></svg>');
|
||||
}
|
||||
|
||||
.emailUnverified {
|
||||
@apply --infoTextStyles;
|
||||
color: var(--matterColorAnti);
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M6.52 9.098c-.163.188-.397.3-.646.31h-.032c-.238 0-.466-.094-.635-.263L2.783 6.732c-.353-.35-.354-.92-.003-1.273.35-.353.92-.354 1.272-.004L5.794 7.19l4.59-5.278C9.287.738 7.73 0 6 0 2.686 0 0 2.686 0 6c0 3.313 2.686 6 6 6 3.313 0 6-2.687 6-6 0-.91-.21-1.772-.573-2.545L6.52 9.098z" fill="%23F00" fill-rule="evenodd"/></svg>');
|
||||
}
|
||||
|
||||
.pendingEmailUnverified {
|
||||
@apply --infoTextStyles;
|
||||
color: var(--failColor);
|
||||
width: 100%;
|
||||
background-image: url('data:image/svg+xml;utf8,<svg width="12" height="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M6.52 9.098c-.163.188-.397.3-.646.31h-.032c-.238 0-.466-.094-.635-.263L2.783 6.732c-.353-.35-.354-.92-.003-1.273.35-.353.92-.354 1.272-.004L5.794 7.19l4.59-5.278C9.287.738 7.73 0 6 0 2.686 0 0 2.686 0 6c0 3.313 2.686 6 6 6 3.313 0 6-2.687 6-6 0-.91-.21-1.772-.573-2.545L6.52 9.098z" fill="%23F00" fill-rule="evenodd"/></svg>');
|
||||
}
|
||||
|
||||
.checkInbox {
|
||||
color: var(--matterColor);
|
||||
}
|
||||
|
||||
.emailStyle {
|
||||
font-weight: var(--fontWeightBold);
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.helperLink {
|
||||
color: var(--matterColor);
|
||||
border-bottom: solid 1px var(--matterColor);
|
||||
line-height: 20px;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmChangesTitle {
|
||||
/* Font */
|
||||
color: var(--matterColorAnti);
|
||||
|
||||
margin-top: 0;
|
||||
margin-bottom: 13px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 14px;
|
||||
}
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 0;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
}
|
||||
|
||||
.confirmChangesInfo {
|
||||
margin-top: 0;
|
||||
margin-bottom: 37px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-bottom: 46px;
|
||||
}
|
||||
}
|
||||
|
||||
.bottomWrapper {
|
||||
margin-top: 46px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
178
src/containers/ContactDetailsForm/ContactDetailsForm.js
Normal file
178
src/containers/ContactDetailsForm/ContactDetailsForm.js
Normal file
|
|
@ -0,0 +1,178 @@
|
|||
import React, { PropTypes } from 'react';
|
||||
import { compose } from 'redux';
|
||||
import { FormattedMessage, injectIntl, intlShape } from 'react-intl';
|
||||
import { reduxForm, propTypes as formPropTypes } from 'redux-form';
|
||||
import classNames from 'classnames';
|
||||
import * as validators from '../../util/validators';
|
||||
import { ensureCurrentUser } from '../../util/data';
|
||||
import { PrimaryButton, TextInputField } from '../../components';
|
||||
|
||||
import css from './ContactDetailsForm.css';
|
||||
|
||||
const ContactDetailsFormComponent = props => {
|
||||
const {
|
||||
rootClassName,
|
||||
className,
|
||||
currentUser,
|
||||
form,
|
||||
handleSubmit,
|
||||
submitting,
|
||||
inProgress,
|
||||
intl,
|
||||
invalid,
|
||||
onResendVerificationEmail,
|
||||
pristine,
|
||||
} = props;
|
||||
|
||||
const user = ensureCurrentUser(currentUser);
|
||||
|
||||
if (!user.id) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// email
|
||||
const emailLabel = intl.formatMessage({
|
||||
id: 'ContactDetailsForm.emailLabel',
|
||||
});
|
||||
|
||||
const { email, emailVerified, pendingEmail } = user.attributes;
|
||||
const emailPlaceholder = email || '';
|
||||
|
||||
const emailRequiredMessage = intl.formatMessage({
|
||||
id: 'ContactDetailsForm.emailRequired',
|
||||
});
|
||||
const emailRequired = validators.required(emailRequiredMessage);
|
||||
|
||||
// Email status info: unverified, verified and pending email (aka changed unverified email)
|
||||
let emailVerifiedInfo = null;
|
||||
|
||||
if (emailVerified && !pendingEmail && pristine) {
|
||||
// Current email is verified and there's no pending unverified email
|
||||
emailVerifiedInfo = (
|
||||
<span className={css.emailVerified}>
|
||||
<FormattedMessage id="ContactDetailsForm.emailVerified" />
|
||||
</span>
|
||||
);
|
||||
} else if (!emailVerified && !pendingEmail) {
|
||||
// Current email is unverified. This is the email given in sign up form
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
const resendEmailLink = (
|
||||
<span className={css.helperLink} onClick={onResendVerificationEmail} role="button">
|
||||
<FormattedMessage id="ContactDetailsForm.resendEmailVerificationText" />
|
||||
</span>
|
||||
);
|
||||
/* eslint-enable jsx-a11y/no-static-element-interactions */
|
||||
|
||||
emailVerifiedInfo = (
|
||||
<span className={css.emailUnverified}>
|
||||
<FormattedMessage id="ContactDetailsForm.emailUnverified" values={{ resendEmailLink }} />
|
||||
</span>
|
||||
);
|
||||
} else if (pendingEmail) {
|
||||
// Current email has been tried to change, but the new address is not yet verified
|
||||
|
||||
const pendingEmailStyled = <span className={css.emailStyle}>{pendingEmail}</span>;
|
||||
const pendingEmailCheckInbox = (
|
||||
<span className={css.checkInbox}>
|
||||
<FormattedMessage id="ContactDetailsForm.pendingEmailCheckInbox" values={{ pendingEmail: pendingEmailStyled}} />
|
||||
</span>
|
||||
);
|
||||
|
||||
/* eslint-disable jsx-a11y/no-static-element-interactions */
|
||||
const resendPendingEmailLink = (
|
||||
<span className={css.helperLink} onClick={onResendVerificationEmail} role="button">
|
||||
<FormattedMessage id="ContactDetailsForm.resendEmailVerificationText" />
|
||||
</span>
|
||||
);
|
||||
/* eslint-enable jsx-a11y/no-static-element-interactions */
|
||||
|
||||
emailVerifiedInfo = (
|
||||
<span className={css.pendingEmailUnverified}>
|
||||
<FormattedMessage
|
||||
id="ContactDetailsForm.pendingEmailUnverified"
|
||||
values={{ pendingEmailCheckInbox, resendPendingEmailLink }}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
// password
|
||||
const passwordLabel = intl.formatMessage({
|
||||
id: 'ContactDetailsForm.passwordLabel',
|
||||
});
|
||||
const passwordPlaceholder = intl.formatMessage({
|
||||
id: 'ContactDetailsForm.passwordPlaceholder',
|
||||
});
|
||||
const passwordRequiredMessage = intl.formatMessage({
|
||||
id: 'ContactDetailsForm.passwordRequired',
|
||||
});
|
||||
const passwordRequired = validators.required(passwordRequiredMessage);
|
||||
|
||||
const classes = classNames(rootClassName || css.root, className);
|
||||
const submitDisabled = invalid || submitting || inProgress;
|
||||
|
||||
return (
|
||||
<form className={classes} onSubmit={handleSubmit}>
|
||||
<div className={css.emailSection}>
|
||||
<TextInputField
|
||||
type="email"
|
||||
name="email"
|
||||
id={`${form}.email`}
|
||||
label={emailLabel}
|
||||
placeholder={emailPlaceholder}
|
||||
validate={emailRequired}
|
||||
/>
|
||||
{emailVerifiedInfo}
|
||||
</div>
|
||||
|
||||
<div className={css.confirmChangesSection}>
|
||||
<h3 className={css.confirmChangesTitle}>
|
||||
<FormattedMessage id="ContactDetailsForm.confirmChangesTitle" />
|
||||
</h3>
|
||||
<p className={css.confirmChangesInfo}>
|
||||
<FormattedMessage id="ContactDetailsForm.confirmChangesInfo" />
|
||||
</p>
|
||||
|
||||
<TextInputField
|
||||
className={css.password}
|
||||
type="password"
|
||||
name="currentPassword"
|
||||
id={`${form}.currentPassword`}
|
||||
label={passwordLabel}
|
||||
placeholder={passwordPlaceholder}
|
||||
validate={passwordRequired}
|
||||
/>
|
||||
</div>
|
||||
<div className={css.bottomWrapper}>
|
||||
<PrimaryButton className={css.submitButton} type="submit" disabled={submitDisabled}>
|
||||
<FormattedMessage id="ContactDetailsForm.saveChanges" />
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
ContactDetailsFormComponent.defaultProps = {
|
||||
rootClassName: null,
|
||||
className: null,
|
||||
inProgress: false,
|
||||
};
|
||||
|
||||
const { bool, func, string } = PropTypes;
|
||||
|
||||
ContactDetailsFormComponent.propTypes = {
|
||||
...formPropTypes,
|
||||
rootClassName: string,
|
||||
className: string,
|
||||
inProgress: bool,
|
||||
intl: intlShape.isRequired,
|
||||
onResendVerificationEmail: func.isRequired,
|
||||
};
|
||||
|
||||
const defaultFormName = 'ContactDetailsForm';
|
||||
|
||||
const ContactDetailsForm = compose(reduxForm({ form: defaultFormName }), injectIntl)(
|
||||
ContactDetailsFormComponent
|
||||
);
|
||||
|
||||
export default ContactDetailsForm;
|
||||
|
|
@ -1,5 +1,18 @@
|
|||
@import '../../marketplace.css';
|
||||
|
||||
.content {
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin: 32px auto 0 auto;
|
||||
max-width: 564px;
|
||||
}
|
||||
|
||||
@media (--viewportLarge) {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.tabs {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
@ -13,7 +26,7 @@
|
|||
@media (--viewportLarge) {
|
||||
min-height: auto;
|
||||
flex-direction: column;
|
||||
margin-top: 4px;
|
||||
margin-top: 28px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -31,3 +44,13 @@
|
|||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
margin-top: 4px;
|
||||
margin-bottom: 19px;
|
||||
|
||||
@media (--viewportMedium) {
|
||||
margin-top: 2px;
|
||||
margin-bottom: 31px;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
56
src/containers/ContactDetailsPage/ContactDetailsPage.duck.js
Normal file
56
src/containers/ContactDetailsPage/ContactDetailsPage.duck.js
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
import { currentUserShowSuccess } from '../../ducks/user.duck';
|
||||
|
||||
// ================ Action types ================ //
|
||||
|
||||
export const CHANGE_EMAIL_REQUEST = 'app/ContactDetailsPage/CHANGE_EMAIL_REQUEST';
|
||||
export const CHANGE_EMAIL_SUCCESS = 'app/ContactDetailsPage/CHANGE_EMAIL_SUCCESS';
|
||||
export const CHANGE_EMAIL_ERROR = 'app/ContactDetailsPage/CHANGE_EMAIL_ERROR';
|
||||
|
||||
// ================ Reducer ================ //
|
||||
|
||||
const initialState = {
|
||||
changeEmailError: null,
|
||||
changeEmailInProgress: false,
|
||||
};
|
||||
|
||||
export default function reducer(state = initialState, action = {}) {
|
||||
const { type, payload } = action;
|
||||
switch (type) {
|
||||
case CHANGE_EMAIL_REQUEST:
|
||||
return { ...state, changeEmailInProgress: true, changeEmailError: null };
|
||||
case CHANGE_EMAIL_SUCCESS:
|
||||
return { ...state, changeEmailInProgress: false };
|
||||
case CHANGE_EMAIL_ERROR:
|
||||
return { ...state, changeEmailInProgress: false, changeEmailError: payload };
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
// ================ Action creators ================ //
|
||||
|
||||
export const changeEmailRequest = () => ({ type: CHANGE_EMAIL_REQUEST });
|
||||
export const changeEmailSuccess = () => ({ type: CHANGE_EMAIL_SUCCESS });
|
||||
export const changeEmailError = error => ({
|
||||
type: CHANGE_EMAIL_ERROR,
|
||||
payload: error,
|
||||
error: true,
|
||||
});
|
||||
|
||||
// ================ Thunks ================ //
|
||||
|
||||
export const changeEmail = params =>
|
||||
(dispatch, getState, sdk) => {
|
||||
dispatch(changeEmailRequest());
|
||||
const { email, currentPassword } = params;
|
||||
|
||||
return sdk.currentUser
|
||||
.changeEmail({ email, currentPassword }, { expand: true })
|
||||
.then(response => {
|
||||
const currentUser = response.data.data;
|
||||
dispatch(changeEmailSuccess());
|
||||
dispatch(currentUserShowSuccess(currentUser));
|
||||
})
|
||||
.catch(e => dispatch(changeEmailError(e)));
|
||||
};
|
||||
|
|
@ -4,7 +4,8 @@ import { connect } from 'react-redux';
|
|||
import { withRouter } from 'react-router-dom';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import * as propTypes from '../../util/propTypes';
|
||||
import { sendVerificationEmail } from '../../ducks/user.duck';
|
||||
import { ensureCurrentUser } from '../../util/data';
|
||||
import { fetchCurrentUser, sendVerificationEmail } from '../../ducks/user.duck';
|
||||
import { logout, authenticationInProgress } from '../../ducks/Auth.duck';
|
||||
import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck';
|
||||
import {
|
||||
|
|
@ -17,7 +18,9 @@ import {
|
|||
TopbarWrapper,
|
||||
UserNav,
|
||||
} from '../../components';
|
||||
import { ContactDetailsForm } from '../../containers';
|
||||
|
||||
import { changeEmail } from './ContactDetailsPage.duck';
|
||||
import css from './ContactDetailsPage.css';
|
||||
|
||||
export const ContactDetailsPageComponent = props => {
|
||||
|
|
@ -37,6 +40,7 @@ export const ContactDetailsPageComponent = props => {
|
|||
sendVerificationEmailInProgress,
|
||||
sendVerificationEmailError,
|
||||
onResendVerificationEmail,
|
||||
onSubmitChangeEmail,
|
||||
} = props;
|
||||
|
||||
const tabs = [
|
||||
|
|
@ -56,6 +60,19 @@ export const ContactDetailsPageComponent = props => {
|
|||
},
|
||||
];
|
||||
|
||||
const user = ensureCurrentUser(currentUser);
|
||||
const email = user.attributes.email || '';
|
||||
const changeEmailForm = user.id
|
||||
? <ContactDetailsForm
|
||||
className={css.form}
|
||||
initialValues={{ email }}
|
||||
currentUser={currentUser}
|
||||
onResendVerificationEmail={onResendVerificationEmail}
|
||||
onSubmit={onSubmitChangeEmail}
|
||||
inProgress={authInProgress}
|
||||
/>
|
||||
: null;
|
||||
|
||||
return (
|
||||
<PageLayout authInfoError={authInfoError} logoutError={logoutError} title="Contact details">
|
||||
<LayoutSideNavigation>
|
||||
|
|
@ -82,7 +99,12 @@ export const ContactDetailsPageComponent = props => {
|
|||
<TabNav rootClassName={css.tabs} tabRootClassName={css.tab} tabs={tabs} />
|
||||
</SideNavWrapper>
|
||||
<ContentWrapper>
|
||||
Main content
|
||||
<div className={css.content}>
|
||||
<h1 className={css.title}>
|
||||
<FormattedMessage id="ContactDetailsPage.title" />
|
||||
</h1>
|
||||
{changeEmailForm}
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</LayoutSideNavigation>
|
||||
</PageLayout>
|
||||
|
|
@ -111,6 +133,7 @@ ContactDetailsPageComponent.propTypes = {
|
|||
notificationCount: number,
|
||||
onLogout: func.isRequired,
|
||||
onManageDisableScrolling: func.isRequired,
|
||||
onSubmitChangeEmail: func.isRequired,
|
||||
sendVerificationEmailInProgress: bool.isRequired,
|
||||
sendVerificationEmailError: instanceOf(Error),
|
||||
onResendVerificationEmail: func.isRequired,
|
||||
|
|
@ -154,10 +177,16 @@ const mapDispatchToProps = dispatch => ({
|
|||
onManageDisableScrolling: (componentId, disableScrolling) =>
|
||||
dispatch(manageDisableScrolling(componentId, disableScrolling)),
|
||||
onResendVerificationEmail: () => dispatch(sendVerificationEmail()),
|
||||
onSubmitChangeEmail: values => dispatch(changeEmail(values)),
|
||||
});
|
||||
|
||||
const ContactDetailsPage = compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(
|
||||
ContactDetailsPageComponent
|
||||
);
|
||||
|
||||
ContactDetailsPage.loadData = () => {
|
||||
// Since verify email happens in separate tab, current user's data might be updated
|
||||
return fetchCurrentUser();
|
||||
};
|
||||
|
||||
export default ContactDetailsPage;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ describe('ContactDetailsPage', () => {
|
|||
onManageDisableScrolling={noop}
|
||||
sendVerificationEmailInProgress={false}
|
||||
onResendVerificationEmail={noop}
|
||||
onSubmitChangeEmail={noop}
|
||||
/>
|
||||
);
|
||||
expect(tree).toMatchSnapshot();
|
||||
|
|
|
|||
|
|
@ -72,7 +72,13 @@ exports[`ContactDetailsPage matches snapshot 1`] = `
|
|||
<ContentWrapper
|
||||
className={null}
|
||||
rootClassName={null}>
|
||||
Main content
|
||||
<div>
|
||||
<h1>
|
||||
<FormattedMessage
|
||||
id="ContactDetailsPage.title"
|
||||
values={Object {}} />
|
||||
</h1>
|
||||
</div>
|
||||
</ContentWrapper>
|
||||
</LayoutSideNavigation>
|
||||
</withRouter(PageLayout)>
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ const EmailVerificationFormComponent = props => {
|
|||
verificationError,
|
||||
} = props;
|
||||
|
||||
const email = <strong>{currentUser.attributes.email}</strong>;
|
||||
const name = currentUser.attributes.profile.firstName;
|
||||
const { email, emailVerified, pendingEmail, profile } = currentUser.attributes;
|
||||
const emailToVerify = <strong>{pendingEmail || email}</strong>;
|
||||
const name = profile.firstName;
|
||||
|
||||
const errorMessage = (
|
||||
<div className={css.error}>
|
||||
|
|
@ -37,7 +38,10 @@ const EmailVerificationFormComponent = props => {
|
|||
</h1>
|
||||
|
||||
<p className={css.modalMessage}>
|
||||
<FormattedMessage id="EmailVerificationForm.finishAccountSetup" values={{ email }} />
|
||||
<FormattedMessage
|
||||
id="EmailVerificationForm.finishAccountSetup"
|
||||
values={{ email: emailToVerify }}
|
||||
/>
|
||||
</p>
|
||||
|
||||
{verificationError ? errorMessage : null}
|
||||
|
|
@ -82,7 +86,7 @@ const EmailVerificationFormComponent = props => {
|
|||
</div>
|
||||
);
|
||||
|
||||
return currentUser.attributes.emailVerified ? alreadyVerified : verifyEmail;
|
||||
return emailVerified && !pendingEmail ? alreadyVerified : verifyEmail;
|
||||
};
|
||||
|
||||
EmailVerificationFormComponent.defaultProps = {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ import {
|
|||
UserNav,
|
||||
} from '../../components';
|
||||
|
||||
|
||||
import css from './PasswordChangePage.css';
|
||||
|
||||
export const PasswordChangePageComponent = props => {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import AuthenticationPage from './AuthenticationPage/AuthenticationPage';
|
|||
import BookingDatesForm from './BookingDatesForm/BookingDatesForm';
|
||||
import ChangeAccountPasswordForm from './ChangeAccountPasswordForm/ChangeAccountPasswordForm';
|
||||
import CheckoutPage from './CheckoutPage/CheckoutPage';
|
||||
import ContactDetailsForm from './ContactDetailsForm/ContactDetailsForm';
|
||||
import ContactDetailsPage from './ContactDetailsPage/ContactDetailsPage';
|
||||
import EditListingDescriptionForm from './EditListingDescriptionForm/EditListingDescriptionForm';
|
||||
import EditListingLocationForm from './EditListingLocationForm/EditListingLocationForm';
|
||||
|
|
@ -41,6 +42,7 @@ export {
|
|||
BookingDatesForm,
|
||||
ChangeAccountPasswordForm,
|
||||
CheckoutPage,
|
||||
ContactDetailsForm,
|
||||
ContactDetailsPage,
|
||||
EditListingDescriptionForm,
|
||||
EditListingLocationForm,
|
||||
|
|
|
|||
|
|
@ -239,6 +239,7 @@ const routesConfiguration = [
|
|||
exact: true,
|
||||
name: 'ContactDetailsPage',
|
||||
component: props => <ContactDetailsPage {...props} />,
|
||||
loadData: params => ContactDetailsPage.loadData(params),
|
||||
},
|
||||
{
|
||||
path: '/account/change-password',
|
||||
|
|
|
|||
|
|
@ -48,8 +48,22 @@
|
|||
"CheckoutPage.priceBreakdownTitle": "Booking breakdown",
|
||||
"CheckoutPage.speculateTransactionError": "Failed to fetch breakdown information.",
|
||||
"CheckoutPage.title": "Book {listingTitle}",
|
||||
"ContactDetailsForm.confirmChangesInfo": "To change your email, you need to enter your current password.",
|
||||
"ContactDetailsForm.confirmChangesTitle": "Confirm your changes",
|
||||
"ContactDetailsForm.emailLabel": "Your email",
|
||||
"ContactDetailsForm.emailRequired": "This field is required",
|
||||
"ContactDetailsForm.emailUnverified": "You haven't verified your email yet. {resendEmailLink}",
|
||||
"ContactDetailsForm.emailVerified": "Your email is verified.",
|
||||
"ContactDetailsForm.passwordLabel": "Current password",
|
||||
"ContactDetailsForm.passwordPlaceholder": "Enter your current password…",
|
||||
"ContactDetailsForm.passwordRequired": "This field is required",
|
||||
"ContactDetailsForm.pendingEmailCheckInbox": "Check your inbox to verify {pendingEmail} now.",
|
||||
"ContactDetailsForm.pendingEmailUnverified": "You have changed your email address but haven’t verified the new address yet. {pendingEmailCheckInbox} {resendPendingEmailLink}",
|
||||
"ContactDetailsForm.resendEmailVerificationText": "Resend verification email.",
|
||||
"ContactDetailsForm.saveChanges": "Save changes",
|
||||
"ContactDetailsPage.emailTabTitle": "Email",
|
||||
"ContactDetailsPage.passwordTabTitle": "Password",
|
||||
"ContactDetailsPage.title": "Email settings",
|
||||
"DateInput.clearDate": "Clear Date",
|
||||
"DateInput.closeDatePicker": "Close",
|
||||
"DateInput.defaultPlaceholder": "Date input",
|
||||
|
|
|
|||
|
|
@ -6128,9 +6128,9 @@ sharetribe-scripts@0.9.2:
|
|||
optionalDependencies:
|
||||
fsevents "1.0.17"
|
||||
|
||||
"sharetribe-sdk@git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#0bc2a2e82be2c5eadbc22e511a750a2a91dc0fd5":
|
||||
"sharetribe-sdk@git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#2c7f3d323c5e7a7c4c93ef38962c236859b83bab":
|
||||
version "0.0.1"
|
||||
resolved "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#0bc2a2e82be2c5eadbc22e511a750a2a91dc0fd5"
|
||||
resolved "git+ssh://git@github.com/sharetribe/sharetribe-sdk-js#2c7f3d323c5e7a7c4c93ef38962c236859b83bab"
|
||||
dependencies:
|
||||
axios "^0.15.3"
|
||||
js-cookie "^2.1.3"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue