Add basic profile editor
This commit is contained in:
parent
6db6793b8b
commit
f2b1305ce9
5 changed files with 133 additions and 4 deletions
|
@ -25,7 +25,6 @@ export function fetchMe() {
|
||||||
|
|
||||||
api(getState).get('/api/v1/accounts/verify_credentials').then(response => {
|
api(getState).get('/api/v1/accounts/verify_credentials').then(response => {
|
||||||
dispatch(fetchMeSuccess(response.data));
|
dispatch(fetchMeSuccess(response.data));
|
||||||
dispatch(importFetchedAccount(response.data));
|
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
dispatch(fetchMeFail(error));
|
dispatch(fetchMeFail(error));
|
||||||
});
|
});
|
||||||
|
@ -34,6 +33,7 @@ export function fetchMe() {
|
||||||
|
|
||||||
export function patchMe(params) {
|
export function patchMe(params) {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
dispatch(patchMeRequest());
|
||||||
return api(getState)
|
return api(getState)
|
||||||
.patch('/api/v1/accounts/update_credentials', params)
|
.patch('/api/v1/accounts/update_credentials', params)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
@ -51,9 +51,12 @@ export function fetchMeRequest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function fetchMeSuccess(me) {
|
export function fetchMeSuccess(me) {
|
||||||
return {
|
return (dispatch, getState) => {
|
||||||
type: ME_FETCH_SUCCESS,
|
dispatch(importFetchedAccount(me));
|
||||||
me,
|
dispatch({
|
||||||
|
type: ME_FETCH_SUCCESS,
|
||||||
|
me,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
87
app/gabsocial/features/edit_profile/index.js
Normal file
87
app/gabsocial/features/edit_profile/index.js
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { connect } from 'react-redux';
|
||||||
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import Column from '../ui/components/column';
|
||||||
|
import {
|
||||||
|
SimpleForm,
|
||||||
|
FieldsGroup,
|
||||||
|
TextInput,
|
||||||
|
} from 'gabsocial/features/forms';
|
||||||
|
import { patchMe } from 'gabsocial/actions/me';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
heading: { id: 'column.edit_profile', defaultMessage: 'Edit profile' },
|
||||||
|
});
|
||||||
|
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
const me = state.get('me');
|
||||||
|
return {
|
||||||
|
account: state.getIn(['accounts', me]),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default @connect(mapStateToProps)
|
||||||
|
@injectIntl
|
||||||
|
class EditProfile extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
dispatch: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
account: ImmutablePropTypes.map,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = { isLoading: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormData = (form) => {
|
||||||
|
return Object.fromEntries(
|
||||||
|
new FormData(form).entries()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = (event) => {
|
||||||
|
const { dispatch } = this.props;
|
||||||
|
const formData = this.getFormData(event.target);
|
||||||
|
dispatch(patchMe(formData)).then(() => {
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
}).catch((error) => {
|
||||||
|
this.setState({ isLoading: false });
|
||||||
|
});
|
||||||
|
this.setState({ isLoading: true });
|
||||||
|
event.preventDefault();
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { account, intl } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Column icon='users' heading={intl.formatMessage(messages.heading)} backBtnSlim>
|
||||||
|
<SimpleForm onSubmit={this.handleSubmit}>
|
||||||
|
<fieldset disabled={this.state.isLoading}>
|
||||||
|
<FieldsGroup>
|
||||||
|
<TextInput
|
||||||
|
label='Display name'
|
||||||
|
name='display_name'
|
||||||
|
defaultValue={account.get('display_name')}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
label='Bio'
|
||||||
|
name='note'
|
||||||
|
defaultValue={account.get('bio')}
|
||||||
|
/>
|
||||||
|
</FieldsGroup>
|
||||||
|
</fieldset>
|
||||||
|
<div className='actions'>
|
||||||
|
<button name='button' type='submit' className='btn button button-primary'>Save changes</button>
|
||||||
|
</div>
|
||||||
|
</SimpleForm>
|
||||||
|
</Column>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -184,3 +184,36 @@ export class SelectDropdown extends ImmutablePureComponent {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TextInput extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
label: PropTypes.string,
|
||||||
|
name: PropTypes.string,
|
||||||
|
defaultValue: PropTypes.string,
|
||||||
|
maxLength: PropTypes.number,
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { label, name, defaultValue, maxLength } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='input with_label string optional'>
|
||||||
|
<div className='label_input'>
|
||||||
|
<label className='string optional' htmlFor={name}>{label}</label>
|
||||||
|
<div className='label_input__wrapper'>
|
||||||
|
<input
|
||||||
|
maxlength={maxLength}
|
||||||
|
className='string optional'
|
||||||
|
size={maxLength}
|
||||||
|
type='text'
|
||||||
|
defaultValue={defaultValue}
|
||||||
|
name={name}
|
||||||
|
id={name}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ import {
|
||||||
// GroupEdit,
|
// GroupEdit,
|
||||||
LoginPage,
|
LoginPage,
|
||||||
Preferences,
|
Preferences,
|
||||||
|
EditProfile,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
|
|
||||||
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
// Dummy import, to make sure that <Status /> ends up in the application bundle.
|
||||||
|
@ -236,6 +237,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
||||||
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
|
<WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} componentParams={{ shouldUpdateScroll: this.shouldUpdateScroll }} />
|
||||||
|
|
||||||
<WrappedRoute path='/settings/preferences' layout={LAYOUT.DEFAULT} component={Preferences} content={children} />
|
<WrappedRoute path='/settings/preferences' layout={LAYOUT.DEFAULT} component={Preferences} content={children} />
|
||||||
|
<WrappedRoute path='/settings/profile' layout={LAYOUT.DEFAULT} component={EditProfile} content={children} />
|
||||||
|
|
||||||
<WrappedRoute layout={LAYOUT.EMPTY} component={GenericNotFound} content={children} />
|
<WrappedRoute layout={LAYOUT.EMPTY} component={GenericNotFound} content={children} />
|
||||||
</Switch>
|
</Switch>
|
||||||
|
|
|
@ -165,3 +165,7 @@ export function LoginPage() {
|
||||||
export function Preferences() {
|
export function Preferences() {
|
||||||
return import(/* webpackChunkName: "features/preferences" */'../../preferences');
|
return import(/* webpackChunkName: "features/preferences" */'../../preferences');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function EditProfile() {
|
||||||
|
return import(/* webpackChunkName: "features/edit_profile" */'../../edit_profile');
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue