group edit ui

This commit is contained in:
2458773093 2019-07-17 21:56:06 +03:00
parent db5a85a657
commit 6104e45d18
9 changed files with 206 additions and 2 deletions

View File

@ -62,6 +62,41 @@ export const createFail = error => ({
error,
});
export const update = (groupId, title, description, coverImage, routerHistory) => (dispatch, getState) => {
if (!me) return;
dispatch(updateRequest());
const formData = new FormData();
formData.append('title', title);
formData.append('description', description);
if (coverImage !== null) {
formData.append('cover_image', coverImage);
}
api(getState).put(`/api/v1/groups/${groupId}`, formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
dispatch(updateSuccess(data));
routerHistory.push(`/groups/${data.id}`);
}).catch(err => dispatch(updateFail(err)));
};
export const updateRequest = id => ({
type: GROUP_UPDATE_REQUEST,
id,
});
export const updateSuccess = group => ({
type: GROUP_UPDATE_SUCCESS,
group,
});
export const updateFail = error => ({
type: GROUP_UPDATE_FAIL,
error,
});
export const changeValue = (field, value) => ({
type: GROUP_EDITOR_VALUE_CHANGE,
field,

View File

@ -0,0 +1,148 @@
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { changeValue, submit, setUp } from '../../../actions/group_editor';
import IconButton from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl';
import LoadingIndicator from '../../../components/loading_indicator';
import Column from '../../../components/column';
const messages = defineMessages({
heading: { id: 'groups.edit.heading', defaultMessage: 'Edit group' },
title: { id: 'groups.form.title', defaultMessage: 'Title' },
description: { id: 'groups.form.description', defaultMessage: 'Description' },
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Cover Image' },
update: { id: 'groups.form.update', defaultMessage: 'Update group' },
});
const mapStateToProps = (state, props) => ({
group: state.getIn(['groups', props.params.id]),
title: state.getIn(['group_editor', 'title']),
description: state.getIn(['group_editor', 'description']),
coverImage: state.getIn(['group_editor', 'coverImage']),
disabled: state.getIn(['group_editor', 'isSubmitting']),
});
const mapDispatchToProps = dispatch => ({
onTitleChange: value => dispatch(changeValue('title', value)),
onDescriptionChange: value => dispatch(changeValue('description', value)),
onCoverImageChange: value => dispatch(changeValue('coverImage', value)),
onSubmit: routerHistory => dispatch(submit(routerHistory)),
setUp: group => dispatch(setUp(group)),
});
export default @connect(mapStateToProps, mapDispatchToProps)
@injectIntl
class Edit extends React.PureComponent {
static contextTypes = {
router: PropTypes.object
}
static propTypes = {
group: ImmutablePropTypes.map,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired,
coverImage: PropTypes.object,
disabled: PropTypes.bool,
intl: PropTypes.object.isRequired,
onTitleChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
};
componentWillMount(nextProps) {
if (this.props.group) {
this.props.setUp(this.props.group);
}
}
componentWillReceiveProps(nextProps) {
if (!this.props.group && nextProps.group) {
this.props.setUp(nextProps.group);
}
}
handleTitleChange = e => {
this.props.onTitleChange(e.target.value);
}
handleDescriptionChange = e => {
this.props.onDescriptionChange(e.target.value);
}
handleCoverImageChange = e => {
this.props.onCoverImageChange(e.target.files[0]);
}
handleSubmit = e => {
e.preventDefault();
this.props.onSubmit(this.context.router.history);
}
handleClick = () => {
this.props.onSubmit(this.context.router.history);
}
render () {
const { group, title, description, coverImage, disabled, intl } = this.props;
if (typeof group === 'undefined') {
return (
<Column>
<LoadingIndicator />
</Column>
);
} else if (group === false) {
return (
<Column>
<MissingIndicator />
</Column>
);
}
return (
<form className='column-inline-form' onSubmit={this.handleSubmit}>
<h2>{intl.formatMessage(messages.heading)}</h2>
<label>
<input
className='setting-text'
value={title}
disabled={disabled}
onChange={this.handleTitleChange}
placeholder={intl.formatMessage(messages.title)}
/>
</label>
<label>
<input
className='setting-text'
value={description}
disabled={disabled}
onChange={this.handleDescriptionChange}
placeholder={intl.formatMessage(messages.description)}
/>
</label>
<label>
<input
type='file'
className='setting-text'
disabled={disabled}
onChange={this.handleCoverImageChange}
placeholder={intl.formatMessage(messages.coverImage)}
/>
</label>
<IconButton
disabled={disabled}
icon='plus'
title={title}
onClick={this.handleClick}
/>
</form>
);
}
}

View File

@ -49,8 +49,8 @@ class Groups extends ImmutablePureComponent {
return (
<div>
<div className="group-column-header">
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
<div className="group-column-header__cta"><Link to="/groups/create">{intl.formatMessage(messages.create)}</Link></div>
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
<div className="column-header__wrapper">
<h1 className="column-header">

View File

@ -10,7 +10,8 @@ import DropdownMenuContainer from '../../../../containers/dropdown_menu_containe
const messages = defineMessages({
join: { id: 'groups.join', defaultMessage: 'Join group' },
leave: { id: 'groups.leave', defaultMessage: 'Leave group' },
removed_accounts: { id: 'groups.removed_accounts', defaultMessage: 'Removed Accounts' }
removed_accounts: { id: 'groups.removed_accounts', defaultMessage: 'Removed Accounts' },
edit: { id: 'groups.edit', defaultMessage: 'Edit' }
});
export default @injectIntl
@ -42,6 +43,7 @@ class Header extends ImmutablePureComponent {
const { group, intl } = this.props;
const menu = [
{ text: intl.formatMessage(messages.edit), to: `/groups/${group.get('id')}/edit` },
{ text: intl.formatMessage(messages.removed_accounts), to: `/groups/${group.get('id')}/removed_accounts` },
];

View File

@ -58,6 +58,7 @@ import {
GroupMembers,
GroupRemovedAccounts,
GroupCreate,
GroupEdit,
} from './util/async-components';
import { me, meUsername } from '../../initial_state';
import { previewState as previewMediaState } from './components/media_modal';
@ -180,6 +181,7 @@ class SwitchingColumnsArea extends React.PureComponent {
<WrappedRoute path='/groups/browse/admin' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'admin' }} />
<WrappedRoute path='/groups/:id/members' page={GroupPage} component={GroupMembers} content={children} />
<WrappedRoute path='/groups/:id/removed_accounts' page={GroupPage} component={GroupRemovedAccounts} content={children} />
<WrappedRoute path='/groups/:id/edit' page={GroupPage} component={GroupEdit} content={children} />
<WrappedRoute path='/groups/:id' page={GroupPage} component={GroupTimeline} content={children} />
<WrappedRoute path='/tags/:id' component={HashtagTimeline} content={children} />

View File

@ -46,6 +46,10 @@ export function GroupCreate () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/create');
}
export function GroupEdit () {
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/edit');
}
export function Groups () {
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
}

View File

@ -28,6 +28,7 @@ export default function groupEditorReducer(state = initialState, action) {
return state.withMutations(map => {
map.set('groupId', action.group.get('id'));
map.set('title', action.group.get('title'));
map.set('description', action.group.get('description'));
map.set('isSubmitting', false);
});
case GROUP_EDITOR_VALUE_CHANGE:

View File

@ -3,6 +3,7 @@ import {
GROUP_FETCH_FAIL,
GROUPS_FETCH_SUCCESS,
} from '../actions/groups';
import { GROUP_UPDATE_SUCCESS } from '../actions/group_editor';
import { Map as ImmutableMap, fromJS } from 'immutable';
const initialState = ImmutableMap();
@ -20,6 +21,7 @@ const normalizeGroups = (state, groups) => {
export default function groups(state = initialState, action) {
switch(action.type) {
case GROUP_FETCH_SUCCESS:
case GROUP_UPDATE_SUCCESS:
return normalizeGroup(state, action.group);
case GROUPS_FETCH_SUCCESS:
return normalizeGroups(state, action.groups);

View File

@ -10,6 +10,16 @@ $height: 80px;
font-size: 20px;
font-weight: bold;
}
.group-column-header__cta {
float: right;
padding: 15px;
font-size: 17px;
a {
color: $primary-text-color;
}
}
}
.group-card-list {