ProfileSettingsPage with form

This commit is contained in:
Vesa Luusua 2017-09-08 01:24:30 +03:00
parent 76cb0ac551
commit d9e7dbe2c9
6 changed files with 121 additions and 28 deletions

View file

@ -0,0 +1,14 @@
@import '../../marketplace.css';
.root {
background-color: var(--matterColorLight);
}
.content {
width: calc(100% - 48px);
margin: 12px 24px;
@media (--viewportMedium) {
max-width: 565px;
margin: 89px auto;
}
}

View file

@ -2,26 +2,33 @@ import React, { PropTypes } from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
import { FormattedMessage } from 'react-intl';
import * as propTypes from '../../util/propTypes';
import { ensureCurrentUser } from '../../util/data';
import { logout, authenticationInProgress } from '../../ducks/Auth.duck';
import { manageDisableScrolling, isScrollingDisabled } from '../../ducks/UI.duck';
import { requestImageUpload } from './ProfileSettingsPage.duck';
import { clearUpdatedForm, updateProfile, uploadImage } from './ProfileSettingsPage.duck';
import { PageLayout, Topbar, UserNav } from '../../components';
import { ProfileSettingsForm } from '../../containers';
const ACCEPT_IMAGES = 'image/*';
import css from './ProfileSettingsPage.css';
const onImageUploadHandler = (event, fn) => {
const file = event.target.files[0];
const onImageUploadHandler = (values, fn) => {
const { id, imageId, file } = values;
if (file) {
fn({ id: `${file.name}_${Date.now()}`, file })
.then(response => {
console.log('Response:', response);
})
.catch(error => {
console.log('Error:', error);
});
fn({ id, imageId, file });
}
}
};
const onSubmit = (values, fn) => {
const { firstName, lastName, profileImage } = values;
const name = { firstName, lastName };
const updatedValues = profileImage.imageId
? { ...name, profileImageId: profileImage.imageId }
: name;
fn(updatedValues);
};
export const ProfileSettingsPageComponent = props => {
const {
@ -30,18 +37,48 @@ export const ProfileSettingsPageComponent = props => {
currentUser,
currentUserHasListings,
history,
image,
isAuthenticated,
location,
logoutError,
notificationCount,
onChange,
onImageUpload,
onLogout,
onManageDisableScrolling,
onUpdateProfile,
scrollingDisabled,
updateInProgress,
updateProfileError,
uploadImageError,
uploadInProgress,
} = props;
const user = ensureCurrentUser(currentUser);
const { firstName, lastName } = user.attributes.profile;
const profileImage = image || { imageId: user.profileImage.id };
const profileSettingsForm = user.id
? <ProfileSettingsForm
className={css.form}
currentUser={currentUser}
initialValues={{ firstName, lastName, profileImage }}
profileImage={profileImage}
onImageUpload={e => onImageUploadHandler(e, onImageUpload)}
uploadInProgress={uploadInProgress}
updateInProgress={updateInProgress}
uploadImageError={uploadImageError}
updateProfileError={updateProfileError}
onSubmit={values => {
onSubmit({ ...values, profileImage }, onUpdateProfile);
}}
onChange={onChange}
/>
: null;
return (
<PageLayout
className={css.root}
authInfoError={authInfoError}
logoutError={logoutError}
title="Profile settings"
@ -60,16 +97,11 @@ export const ProfileSettingsPageComponent = props => {
onManageDisableScrolling={onManageDisableScrolling}
/>
<UserNav selectedPageName="ProfileSettingsPage" />
<label htmlFor="EditListingPhotosForm.AddImages">Add profile image</label>
<input
id="EditListingPhotosForm.AddImages"
accept={ACCEPT_IMAGES}
name="addImage"
onChange={(e) => onImageUploadHandler(e, onImageUpload)}
type="file"
disabled={false}
/>
<div className={css.content}>
<h1><FormattedMessage id="ProfileSettingsPage.title" /></h1>
{profileSettingsForm}
</div>
</PageLayout>
);
};
@ -79,9 +111,12 @@ ProfileSettingsPageComponent.defaultProps = {
currentUser: null,
logoutError: null,
notificationCount: 0,
uploadImageError: null,
updateProfileError: null,
image: null,
};
const { bool, func, instanceOf, number, object, shape } = PropTypes;
const { bool, func, instanceOf, number, object, shape, string } = PropTypes;
ProfileSettingsPageComponent.propTypes = {
authInfoError: instanceOf(Error),
@ -89,12 +124,23 @@ ProfileSettingsPageComponent.propTypes = {
currentUser: propTypes.currentUser,
currentUserHasListings: bool.isRequired,
isAuthenticated: bool.isRequired,
image: shape({
id: string,
imageId: propTypes.uuid,
file: instanceOf(File),
}),
logoutError: instanceOf(Error),
notificationCount: number,
onChange: func.isRequired,
onImageUpload: func.isRequired,
onLogout: func.isRequired,
onManageDisableScrolling: func.isRequired,
onUpdateProfile: func.isRequired,
scrollingDisabled: bool.isRequired,
updateInProgress: bool.isRequired,
updateProfileError: instanceOf(Error),
uploadImageError: instanceOf(Error),
uploadInProgress: bool.isRequired,
// from withRouter
history: shape({
@ -112,23 +158,37 @@ const mapStateToProps = state => {
currentUserHasListings,
currentUserNotificationCount: notificationCount,
} = state.user;
const {
image,
uploadImageError,
uploadInProgress,
updateInProgress,
updateProfileError,
} = state.ProfileSettingsPage;
return {
authInfoError,
authInProgress: authenticationInProgress(state),
currentUser,
currentUserHasListings,
currentUserNotificationCount: notificationCount,
image,
isAuthenticated,
logoutError,
scrollingDisabled: isScrollingDisabled(state),
updateInProgress,
updateProfileError,
uploadImageError,
uploadInProgress,
};
};
const mapDispatchToProps = dispatch => ({
onImageUpload: data => dispatch(requestImageUpload(data)),
onChange: () => dispatch(clearUpdatedForm()),
onImageUpload: data => dispatch(uploadImage(data)),
onLogout: historyPush => dispatch(logout(historyPush)),
onManageDisableScrolling: (componentId, disableScrolling) =>
dispatch(manageDisableScrolling(componentId, disableScrolling)),
onUpdateProfile: data => dispatch(updateProfile(data)),
});
const ProfileSettingsPage = compose(connect(mapStateToProps, mapDispatchToProps), withRouter)(

View file

@ -8,15 +8,20 @@ describe('ContactDetailsPage', () => {
it('matches snapshot', () => {
const tree = renderShallow(
<ProfileSettingsPageComponent
params={{ displayName: 'my-shop' }}
history={{ push: noop }}
location={{ search: '' }}
scrollingDisabled={false}
authInProgress={false}
currentUserHasListings={false}
history={{ push: noop }}
isAuthenticated={false}
location={{ search: '' }}
onChange={noop}
onImageUpload={noop}
onLogout={noop}
onManageDisableScrolling={noop}
onUpdateProfile={noop}
params={{ displayName: 'my-shop' }}
scrollingDisabled={false}
updateInProgress={false}
uploadInProgress={false}
/>
);
expect(tree).toMatchSnapshot();

View file

@ -2,9 +2,11 @@ exports[`ContactDetailsPage matches snapshot 1`] = `
<withRouter(PageLayout)
authInfoError={null}
logoutError={null}
scrollingDisabled={false}
title="Profile settings">
<Topbar
authInProgress={false}
currentPage="ProfileSettingsPage"
currentUser={null}
currentUserHasListings={false}
history={
@ -21,5 +23,16 @@ exports[`ContactDetailsPage matches snapshot 1`] = `
notificationCount={0}
onLogout={[Function]}
onManageDisableScrolling={[Function]} />
<UserNav
className={null}
rootClassName={null}
selectedPageName="ProfileSettingsPage" />
<div>
<h1>
<FormattedMessage
id="ProfileSettingsPage.title"
values={Object {}} />
</h1>
</div>
</withRouter(PageLayout)>
`;

View file

@ -267,6 +267,7 @@
"ProfileSettingsForm.updateProfileFailed": "Whoopsie, something went wrong - please try again.",
"ProfileSettingsForm.yourName": "Your name",
"ProfileSettingsForm.yourProfilePicture": "Your profile picture",
"ProfileSettingsPage.title": "Profile settings",
"ResponsiveImage.noImage": "No image",
"SaleDetailsPanel.bookingBreakdownTitle": "Booking breakdown",
"SaleDetailsPanel.listingAcceptedTitle": "Woohoo! You accepted a request from {customerName} for {listingLink}",

View file

@ -160,6 +160,6 @@ export const ensureUser = user => {
* @param {Object} current user entity object, which is to be ensured agains null values
*/
export const ensureCurrentUser = user => {
const empty = { id: null, type: 'current-user', attributes: { profile: {} } };
const empty = { id: null, type: 'current-user', attributes: { profile: {} }, profileImage: {} };
return { ...empty, ...user };
};