Files
frontend-app-profile/src/components/UserProfile/index.jsx
2019-02-22 15:09:34 -05:00

290 lines
8.0 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import { Container, Row, Col } from 'reactstrap';
import ProfileAvatar from './ProfileAvatar';
import FullName from './FullName';
import UserLocation from './UserLocation';
import Education from './Education';
import SocialLinks from './SocialLinks';
import Bio from './Bio';
import MyCertificates from './MyCertificates';
class UserProfile extends React.Component {
constructor(props) {
super(props);
this.state = {
fullName: { value: null, visibility: null },
userLocation: { value: null, visibility: null },
education: { value: null, visibility: null },
bio: { value: null, visibility: null },
socialLinks: { value: null, visibility: null },
};
this.onCancel = this.onCancel.bind(this);
this.onEdit = this.onEdit.bind(this);
this.onSave = this.onSave.bind(this);
this.onSaveProfilePhoto = this.onSaveProfilePhoto.bind(this);
this.onDeleteProfilePhoto = this.onDeleteProfilePhoto.bind(this);
this.onChange = this.onChange.bind(this);
this.onVisibilityChange = this.onVisibilityChange.bind(this);
}
componentDidMount() {
this.props.fetchProfile(this.props.match.params.username);
}
onCancel() {
this.props.closeEditableField(this.props.currentlyEditingField);
}
onEdit(fieldName) {
this.props.openEditableField(fieldName);
}
onSave(fieldName, value, visibility) {
const {
value: fieldValue,
visibility: fieldVisibility,
} = this.state[fieldName];
const valueToSave = value != null ? value : fieldValue;
const visibilityToSave = visibility != null ? visibility : fieldVisibility;
if (valueToSave != null) {
this.props.saveProfile(
this.props.username,
{
[fieldName]: valueToSave,
},
fieldName,
);
}
if (visibilityToSave != null) {
this.props.savePreferences(
this.props.username,
{
visibility: {
[fieldName]: visibilityToSave,
},
},
);
}
if (valueToSave == null && visibilityToSave == null) {
this.onCancel();
}
}
onSaveProfilePhoto(formData) {
this.props.saveProfilePhoto(this.props.username, formData);
}
onDeleteProfilePhoto() {
this.props.deleteProfilePhoto(this.props.username);
}
onChange(fieldName, value) {
this.setState({
[fieldName]: {
value,
visibility: this.state[fieldName].visibility,
},
});
}
onVisibilityChange(fieldName, visibility) {
this.setState({
[fieldName]: {
value: this.state[fieldName].value,
visibility,
},
});
}
render() {
const {
saveState,
error,
profileImage,
username,
fullName,
userLocation,
bio,
education,
socialLinks,
certificates,
isCurrentUserProfile,
} = this.props;
const commonProps = {
onSave: this.onSave,
onEdit: this.onEdit,
onCancel: this.onCancel,
onChange: this.onChange,
onVisibilityChange: this.onVisibilityChange,
saveState,
error,
};
const getMode = (name) => {
// If the prop doesn't exist, that means it hasn't been set (for the current user's profile)
// or is being hidden from us (for other users' profiles)
const propExists = this.props[name] != null && this.props[name].length > 0;
// If this isn't the current user's profile...
if (!isCurrentUserProfile) {
// then there are only two options: static or nothing.
// We use 'null' as a return value because the consumers of
// getMode render nothing at all on a mode of null.
return propExists ? 'static' : null;
}
// Otherwise, if this is the current user's profile...
if (name === this.props.currentlyEditingField) {
return 'editing';
}
if (!propExists) {
return 'empty';
}
return 'editable';
};
const getVisibility = name => this.props.visibility[name];
return (
<div className="profile-page">
<div className="bg-banner bg-program-micro-masters d-none d-md-block p-relative" />
<Container fluid>
<Row>
<Col md={4} lg={3}>
<div className="d-flex align-items-center d-md-block mt-4 mt-md-0">
<ProfileAvatar
className="mb-md-3"
src={profileImage}
onSave={this.onSaveProfilePhoto}
onDelete={this.onDeleteProfilePhoto}
savePhotoState={this.props.savePhotoState}
/>
<div>
<h2 className="mb-0">{username}</h2>
<p className="mb-0">Member since 2017</p>
</div>
</div>
</Col>
</Row>
<Row>
<Col xs={{ order: 2 }} md={{ size: 4, order: 1 }} lg={3} className="mt-md-4">
<FullName
fullName={fullName}
visibility={getVisibility('fullName')}
editMode={getMode('fullName')}
{...commonProps}
/>
<UserLocation
userLocation={userLocation}
visibility={getVisibility('userLocation')}
editMode={getMode('userLocation')}
{...commonProps}
/>
<Education
education={education}
visibility={getVisibility('education')}
editMode={getMode('education')}
{...commonProps}
/>
<SocialLinks
socialLinks={socialLinks}
visibility={getVisibility('socialLinks')}
editMode={getMode('socialLinks')}
{...commonProps}
/>
</Col>
<Col xs={{ order: 1 }} md={{ size: 8, order: 2 }} lg={{ size: 8, offset: 1 }} className="mt-4 mt-md-n5">
<Bio
bio={bio}
visibility={getVisibility('bio')}
editMode={getMode('bio')}
{...commonProps}
/>
<MyCertificates
certificates={certificates}
visibility={getVisibility('certificates')}
editMode={getMode('certificates')}
{...commonProps}
/>
</Col>
</Row>
</Container>
</div>
);
}
}
export default UserProfile;
UserProfile.propTypes = {
currentlyEditingField: PropTypes.string,
saveState: PropTypes.oneOf([null, 'pending', 'complete', 'error']),
savePhotoState: PropTypes.oneOf([null, 'pending', 'complete', 'error']),
error: PropTypes.string,
isCurrentUserProfile: PropTypes.bool.isRequired,
profileImage: PropTypes.string,
fullName: PropTypes.string,
username: PropTypes.string,
userLocation: PropTypes.string,
education: PropTypes.string,
socialLinks: PropTypes.arrayOf(PropTypes.shape({
platform: PropTypes.string,
socialLink: PropTypes.string,
})),
aboutMe: PropTypes.string,
bio: PropTypes.string,
certificates: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string,
})),
fetchProfile: PropTypes.func.isRequired,
saveProfile: PropTypes.func.isRequired,
saveProfilePhoto: PropTypes.func.isRequired,
deleteProfilePhoto: PropTypes.func.isRequired,
openEditableField: PropTypes.func.isRequired,
closeEditableField: PropTypes.func.isRequired,
savePreferences: PropTypes.func.isRequired,
match: PropTypes.shape({
params: PropTypes.shape({
username: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
accountPrivacy: PropTypes.string,
visibility: PropTypes.object, // eslint-disable-line
};
UserProfile.defaultProps = {
currentlyEditingField: null,
saveState: null,
savePhotoState: null,
error: null,
profileImage: null,
fullName: null,
username: null,
userLocation: null,
education: null,
socialLinks: [],
aboutMe: null,
bio: null,
certificates: null,
accountPrivacy: null,
visibility: {}, // eslint-disable-line
};