Skip to content

Commit

Permalink
fix: clean and refactor Profile Plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
jsnwesson committed Oct 17, 2023
1 parent 661374f commit 5e65c5f
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 164 deletions.
89 changes: 4 additions & 85 deletions src/profile/ProfilePluginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,16 @@ import { faTwitter, faFacebook, faLinkedin } from '@fortawesome/free-brands-svg-
import {
ActionRow, Avatar, Card, Hyperlink, Icon,
} from '@edx/paragon';
import { HistoryEdu, LocationOn, VerifiedUser } from '@edx/paragon/icons';
import { HistoryEdu, VerifiedUser } from '@edx/paragon/icons';

import get from 'lodash.get';

import Country from './forms/Country';
import PluginCountry from './forms/PluginCountry';
import { Plugin } from '../../plugins';

// Actions
import {
fetchProfile,
saveProfile,
saveProfilePhoto,
deleteProfilePhoto,
openForm,
closeForm,
updateDraft,
} from './data/actions';

// Components
Expand Down Expand Up @@ -67,52 +61,16 @@ const platformDisplayInfo = {
};

class ProfilePluginPage extends React.Component {
constructor(props, context) {
super(props, context);

this.handleSaveProfilePhoto = this.handleSaveProfilePhoto.bind(this);
this.handleDeleteProfilePhoto = this.handleDeleteProfilePhoto.bind(this);
this.handleClose = this.handleClose.bind(this);
this.handleOpen = this.handleOpen.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.handleChange = this.handleChange.bind(this);
}

componentDidMount() {
this.props.fetchProfile(this.props.params.username);
}

handleSaveProfilePhoto(formData) {
this.props.saveProfilePhoto(this.context.authenticatedUser.username, formData);
}

handleDeleteProfilePhoto() {
this.props.deleteProfilePhoto(this.context.authenticatedUser.username);
}

handleClose(formId) {
this.props.closeForm(formId);
}

handleOpen(formId) {
this.props.openForm(formId);
}

handleSubmit(formId) {
this.props.saveProfile(formId, this.context.authenticatedUser.username);
}

handleChange(name, value) {
this.props.updateDraft(name, value);
}

renderContent() {
const {
profileImage,
country,
levelOfEducation,
socialLinks,
visibilityCountry,
isLoadingProfile,
dateJoined,
intl,
Expand All @@ -122,13 +80,6 @@ class ProfilePluginPage extends React.Component {
return <PageLoading srMessage={this.props.intl.formatMessage(messages['profile.loading'])} />;
}

const commonFormProps = {
openHandler: this.handleOpen,
closeHandler: this.handleClose,
submitHandler: this.handleSubmit,
changeHandler: this.handleChange,
};

return (
<Plugin fallbackComponent={<Fallback />}>
<Card className="mb-2">
Expand Down Expand Up @@ -156,19 +107,16 @@ class ProfilePluginPage extends React.Component {
)
}
/>
<Card.Section className="text-center" muted="true">
<Card.Section className="text-center" muted>
<Avatar
size="xl"
className="profile-plugin-avatar"
src={profileImage.src}
alt="Profile image"
/>
<h1 className="h2 mb-0 font-weight-bold">{this.props.params.username}</h1>
<Country
<PluginCountry
country={country}
visibilityCountry={visibilityCountry}
formId="country"
{...commonFormProps}
/>
</Card.Section>
<Card.Footer className="p-0">
Expand Down Expand Up @@ -222,46 +170,27 @@ ProfilePluginPage.propTypes = {
// Account data
dateJoined: PropTypes.string,

// Bio form data
bio: PropTypes.string,
yearOfBirth: PropTypes.number,
visibilityBio: PropTypes.string.isRequired,

// Country form data
country: PropTypes.string,
visibilityCountry: PropTypes.string.isRequired,

// Education form data
levelOfEducation: PropTypes.string,
visibilityLevelOfEducation: PropTypes.string.isRequired,

// Name form data
name: PropTypes.string,
visibilityName: PropTypes.string.isRequired,

// Social links form data
socialLinks: PropTypes.arrayOf(PropTypes.shape({
platform: PropTypes.string,
socialLink: PropTypes.string,
})),
visibilitySocialLinks: PropTypes.string.isRequired,

// Other data we need
profileImage: PropTypes.shape({
src: PropTypes.string,
isDefault: PropTypes.bool,
}),
saveState: PropTypes.oneOf([null, 'pending', 'complete', 'error']),
isLoadingProfile: PropTypes.bool.isRequired,

// Actions
fetchProfile: PropTypes.func.isRequired,
saveProfile: PropTypes.func.isRequired,
saveProfilePhoto: PropTypes.func.isRequired,
deleteProfilePhoto: PropTypes.func.isRequired,
openForm: PropTypes.func.isRequired,
closeForm: PropTypes.func.isRequired,
updateDraft: PropTypes.func.isRequired,

// Router
params: PropTypes.shape({
Expand All @@ -273,26 +202,16 @@ ProfilePluginPage.propTypes = {
};

ProfilePluginPage.defaultProps = {
saveState: null,
profileImage: {},
name: null,
yearOfBirth: null,
levelOfEducation: null,
country: null,
socialLinks: [],
bio: null,
dateJoined: null,
};

export default connect(
profilePageSelector,
{
fetchProfile,
saveProfilePhoto,
deleteProfilePhoto,
saveProfile,
openForm,
closeForm,
updateDraft,
},
)(injectIntl(withParams(ProfilePluginPage)));
156 changes: 77 additions & 79 deletions src/profile/forms/Country.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Form, Icon } from '@edx/paragon';
import { LocationOn } from '@edx/paragon/icons';
import { Form } from '@edx/paragon';

import messages from './Country.messages';

Expand Down Expand Up @@ -61,83 +60,82 @@ class Country extends React.Component {
} = this.props;

return (
// <SwitchContent
// className="mb-5"
// expression={editMode}
// cases={{
// editing: (
// <div role="dialog" aria-labelledby={`${formId}-label`}>
// <form onSubmit={this.handleSubmit}>
// <Form.Group
// controlId={formId}
// isInvalid={error !== null}
// >
// <label className="edit-section-header" htmlFor={formId}>
// {intl.formatMessage(messages['profile.country.label'])}
// </label>
// <select
// data-hj-suppress
// className="form-control"
// type="select"
// id={formId}
// name={formId}
// value={country}
// onChange={this.handleChange}
// >
// <option value="">&nbsp;</option>
// {sortedCountries.map(({ code, name }) => (
// <option key={code} value={code}>{name}</option>
// ))}
// </select>
// {error !== null && (
// <Form.Control.Feedback hasIcon={false}>
// {error}
// </Form.Control.Feedback>
// )}
// </Form.Group>
// <FormControls
// visibilityId="visibilityCountry"
// saveState={saveState}
// visibility={visibilityCountry}
// cancelHandler={this.handleClose}
// changeHandler={this.handleChange}
// />
// </form>
// </div>
// ),
// editable: (
// <>
// <EditableItemHeader
// content={intl.formatMessage(messages['profile.country.label'])}
// showEditButton
// onClickEdit={this.handleOpen}
// showVisibility={visibilityCountry !== null}
// visibility={visibilityCountry}
// />
// <p data-hj-suppress className="h5">{countryMessages[country]}</p>
// </>
// ),
// empty: (
// <>
// <EditableItemHeader
// content={intl.formatMessage(messages['profile.country.label'])}
// />
// <EmptyContent onClick={this.handleOpen}>
// {intl.formatMessage(messages['profile.country.empty'])}
// </EmptyContent>
// </>
// ),
// static: (
<div className="pgn-icons-cell-horizontal">
{/* <EditableItemHeader
content={intl.formatMessage(messages['profile.country.label'])}
/> */}
<Icon src={LocationOn} />
<p className="h5 mt-1 ml-1">{countryMessages[country]}</p>
</div>
// ),
// }}
// />
<SwitchContent
className="mb-5"
expression={editMode}
cases={{
editing: (
<div role="dialog" aria-labelledby={`${formId}-label`}>
<form onSubmit={this.handleSubmit}>
<Form.Group
controlId={formId}
isInvalid={error !== null}
>
<label className="edit-section-header" htmlFor={formId}>
{intl.formatMessage(messages['profile.country.label'])}
</label>
<select
data-hj-suppress
className="form-control"
type="select"
id={formId}
name={formId}
value={country}
onChange={this.handleChange}
>
<option value="">&nbsp;</option>
{sortedCountries.map(({ code, name }) => (
<option key={code} value={code}>{name}</option>
))}
</select>
{error !== null && (
<Form.Control.Feedback hasIcon={false}>
{error}
</Form.Control.Feedback>
)}
</Form.Group>
<FormControls
visibilityId="visibilityCountry"
saveState={saveState}
visibility={visibilityCountry}
cancelHandler={this.handleClose}
changeHandler={this.handleChange}
/>
</form>
</div>
),
editable: (
<>
<EditableItemHeader
content={intl.formatMessage(messages['profile.country.label'])}
showEditButton
onClickEdit={this.handleOpen}
showVisibility={visibilityCountry !== null}
visibility={visibilityCountry}
/>
<p data-hj-suppress className="h5">{countryMessages[country]}</p>
</>
),
empty: (
<>
<EditableItemHeader
content={intl.formatMessage(messages['profile.country.label'])}
/>
<EmptyContent onClick={this.handleOpen}>
{intl.formatMessage(messages['profile.country.empty'])}
</EmptyContent>
</>
),
static: (
<>
<EditableItemHeader
content={intl.formatMessage(messages['profile.country.label'])}
/>
<p data-hj-suppress className="h5">{countryMessages[country]}</p>
</>
),
}}
/>
);
}
}
Expand Down
40 changes: 40 additions & 0 deletions src/profile/forms/PluginCountry.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { injectIntl } from '@edx/frontend-platform/i18n';
import { Icon } from '@edx/paragon';
import { LocationOn } from '@edx/paragon/icons';

// Selectors
import { countrySelector } from '../data/selectors';

// eslint-disable-next-line react/prefer-stateless-function
class PluginCountry extends React.Component {
render() {
const {
country,
countryMessages,
} = this.props;

return (
<div className="pgn-icons-cell-horizontal">
<Icon src={LocationOn} />
<p className="h5 mt-1 ml-1">{countryMessages[country]}</p>
</div>
);
}
}

PluginCountry.propTypes = {
country: PropTypes.string,
countryMessages: PropTypes.objectOf(PropTypes.string).isRequired,
};

PluginCountry.defaultProps = {
country: null,
};

export default connect(
countrySelector,
{},
)(injectIntl(PluginCountry));

0 comments on commit 5e65c5f

Please sign in to comment.