group creation form
This commit is contained in:
parent
62b1707a85
commit
ea1378ada7
78
app/javascript/gabsocial/actions/group_editor.js
Normal file
78
app/javascript/gabsocial/actions/group_editor.js
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
import api from '../api';
|
||||||
|
import { me } from 'gabsocial/initial_state';
|
||||||
|
|
||||||
|
export const GROUP_CREATE_REQUEST = 'GROUP_CREATE_REQUEST';
|
||||||
|
export const GROUP_CREATE_SUCCESS = 'GROUP_CREATE_SUCCESS';
|
||||||
|
export const GROUP_CREATE_FAIL = 'GROUP_CREATE_FAIL';
|
||||||
|
|
||||||
|
export const GROUP_UPDATE_REQUEST = 'GROUP_UPDATE_REQUEST';
|
||||||
|
export const GROUP_UPDATE_SUCCESS = 'GROUP_UPDATE_SUCCESS';
|
||||||
|
export const GROUP_UPDATE_FAIL = 'GROUP_UPDATE_FAIL';
|
||||||
|
|
||||||
|
export const GROUP_EDITOR_VALUE_CHANGE = 'GROUP_EDITOR_VALUE_CHANGE';
|
||||||
|
export const GROUP_EDITOR_RESET = 'GROUP_EDITOR_RESET';
|
||||||
|
export const GROUP_EDITOR_SETUP = 'GROUP_EDITOR_SETUP';
|
||||||
|
|
||||||
|
export const submit = (routerHistory) => (dispatch, getState) => {
|
||||||
|
const groupId = getState().getIn(['group_editor', 'groupId']);
|
||||||
|
const title = getState().getIn(['group_editor', 'title']);
|
||||||
|
const description = getState().getIn(['group_editor', 'description']);
|
||||||
|
const coverImage = getState().getIn(['group_editor', 'coverImage']);
|
||||||
|
|
||||||
|
if (groupId === null) {
|
||||||
|
dispatch(create(title, description, coverImage, routerHistory));
|
||||||
|
} else {
|
||||||
|
dispatch(update(groupId, title, description, coverImage, routerHistory));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const create = (title, description, coverImage, routerHistory) => (dispatch, getState) => {
|
||||||
|
if (!me) return;
|
||||||
|
|
||||||
|
dispatch(createRequest());
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('title', title);
|
||||||
|
formData.append('description', description);
|
||||||
|
debugger;
|
||||||
|
if (coverImage !== null) {
|
||||||
|
formData.append('cover_image', coverImage);
|
||||||
|
}
|
||||||
|
|
||||||
|
api(getState).post('/api/v1/groups', formData, { headers: { 'Content-Type': 'multipart/form-data' } }).then(({ data }) => {
|
||||||
|
dispatch(createSuccess(data));
|
||||||
|
routerHistory.push(`/groups/${data.id}`);
|
||||||
|
}).catch(err => dispatch(createFail(err)));
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const createRequest = id => ({
|
||||||
|
type: GROUP_CREATE_REQUEST,
|
||||||
|
id,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createSuccess = group => ({
|
||||||
|
type: GROUP_CREATE_SUCCESS,
|
||||||
|
group,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const createFail = error => ({
|
||||||
|
type: GROUP_CREATE_FAIL,
|
||||||
|
error,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const changeValue = (field, value) => ({
|
||||||
|
type: GROUP_EDITOR_VALUE_CHANGE,
|
||||||
|
field,
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const reset = () => ({
|
||||||
|
type: GROUP_EDITOR_RESET
|
||||||
|
});
|
||||||
|
|
||||||
|
export const setUp = (group) => ({
|
||||||
|
type: GROUP_EDITOR_SETUP,
|
||||||
|
group,
|
||||||
|
});
|
@ -1,78 +1,121 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists';
|
import { changeValue, submit, reset } from '../../../actions/group_editor';
|
||||||
import IconButton from '../../../components/icon_button';
|
import IconButton from '../../../components/icon_button';
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
label: { id: 'groups.new.title_placeholder', defaultMessage: 'New group title' },
|
heading: { id: 'groups.create.heading', defaultMessage: 'New group' },
|
||||||
title: { id: 'groups.new.create', defaultMessage: 'Add group' },
|
title: { id: 'groups.form.title', defaultMessage: 'Title' },
|
||||||
|
description: { id: 'groups.form.description', defaultMessage: 'Description' },
|
||||||
|
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Cover Image' },
|
||||||
|
create: { id: 'groups.form.create', defaultMessage: 'Create group' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = state => ({
|
const mapStateToProps = state => ({
|
||||||
value: state.getIn(['groupEditor', 'title']),
|
title: state.getIn(['group_editor', 'title']),
|
||||||
disabled: state.getIn(['groupEditor', 'isSubmitting']),
|
description: state.getIn(['group_editor', 'description']),
|
||||||
|
coverImage: state.getIn(['group_editor', 'coverImage']),
|
||||||
|
disabled: state.getIn(['group_editor', 'isSubmitting']),
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapDispatchToProps = dispatch => ({
|
const mapDispatchToProps = dispatch => ({
|
||||||
onChange: value => dispatch(changeListEditorTitle(value)),
|
onTitleChange: value => dispatch(changeValue('title', value)),
|
||||||
onSubmit: () => dispatch(submitListEditor(true)),
|
onDescriptionChange: value => dispatch(changeValue('description', value)),
|
||||||
|
onCoverImageChange: value => dispatch(changeValue('coverImage', value)),
|
||||||
|
onSubmit: routerHistory => dispatch(submit(routerHistory)),
|
||||||
|
reset: () => dispatch(reset()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default @connect(mapStateToProps, mapDispatchToProps)
|
export default @connect(mapStateToProps, mapDispatchToProps)
|
||||||
@injectIntl
|
@injectIntl
|
||||||
class Create extends React.PureComponent {
|
class Create extends React.PureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static contextTypes = {
|
||||||
value: PropTypes.string.isRequired,
|
router: PropTypes.object
|
||||||
disabled: PropTypes.bool,
|
}
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
onSubmit: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
handleChange = e => {
|
static propTypes = {
|
||||||
this.props.onChange(e.target.value);
|
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,
|
||||||
|
};
|
||||||
|
|
||||||
handleSubmit = e => {
|
componentWillMount() {
|
||||||
e.preventDefault();
|
this.props.reset();
|
||||||
this.props.onSubmit();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = () => {
|
handleTitleChange = e => {
|
||||||
this.props.onSubmit();
|
this.props.onTitleChange(e.target.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
handleDescriptionChange = e => {
|
||||||
const { value, disabled, intl } = this.props;
|
this.props.onDescriptionChange(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
const label = intl.formatMessage(messages.label);
|
handleCoverImageChange = e => {
|
||||||
const title = intl.formatMessage(messages.title);
|
this.props.onCoverImageChange(e.target.files[0]);
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
handleSubmit = e => {
|
||||||
<form className='column-inline-form' onSubmit={this.handleSubmit}>
|
e.preventDefault();
|
||||||
<label>
|
this.props.onSubmit(this.context.router.history);
|
||||||
<span style={{ display: 'none' }}>{label}</span>
|
}
|
||||||
|
|
||||||
<input
|
handleClick = () => {
|
||||||
className='setting-text'
|
this.props.onSubmit(this.context.router.history);
|
||||||
value={value}
|
}
|
||||||
disabled={disabled}
|
|
||||||
onChange={this.handleChange}
|
|
||||||
placeholder={label}
|
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
|
|
||||||
<IconButton
|
render () {
|
||||||
disabled={disabled}
|
const { title, description, coverImage, disabled, intl } = this.props;
|
||||||
icon='plus'
|
|
||||||
title={title}
|
return (
|
||||||
onClick={this.handleClick}
|
<form className='column-inline-form' onSubmit={this.handleSubmit}>
|
||||||
/>
|
<h2>{intl.formatMessage(messages.heading)}</h2>
|
||||||
</form>
|
|
||||||
);
|
<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>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -11,9 +11,10 @@ import GroupCard from './card';
|
|||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
heading: { id: 'column.groups', defaultMessage: 'Groups' },
|
heading: { id: 'column.groups', defaultMessage: 'Groups' },
|
||||||
tab_featured: { id: 'column.groups_tab_featured', defaultMessage: 'Featured' },
|
create: { id: 'groups.create', defaultMessage: 'Create group' },
|
||||||
tab_member: { id: 'column.groups_tab_member', defaultMessage: 'Groups you\'re in' },
|
tab_featured: { id: 'groups.tab_featured', defaultMessage: 'Featured' },
|
||||||
tab_admin: { id: 'column.groups_tab_admin', defaultMessage: 'Groups you manage' },
|
tab_member: { id: 'groups.tab_member', defaultMessage: 'Groups you\'re in' },
|
||||||
|
tab_admin: { id: 'groups.tab_admin', defaultMessage: 'Groups you manage' },
|
||||||
});
|
});
|
||||||
|
|
||||||
const mapStateToProps = (state, { activeTab }) => ({
|
const mapStateToProps = (state, { activeTab }) => ({
|
||||||
@ -49,6 +50,7 @@ class Groups extends ImmutablePureComponent {
|
|||||||
<div>
|
<div>
|
||||||
<div className="group-column-header">
|
<div className="group-column-header">
|
||||||
<div className="group-column-header__title">{intl.formatMessage(messages.heading)}</div>
|
<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="column-header__wrapper">
|
<div className="column-header__wrapper">
|
||||||
<h1 className="column-header">
|
<h1 className="column-header">
|
||||||
|
@ -57,6 +57,7 @@ import {
|
|||||||
GroupTimeline,
|
GroupTimeline,
|
||||||
GroupMembers,
|
GroupMembers,
|
||||||
GroupRemovedAccounts,
|
GroupRemovedAccounts,
|
||||||
|
GroupCreate,
|
||||||
} from './util/async-components';
|
} from './util/async-components';
|
||||||
import { me, meUsername } from '../../initial_state';
|
import { me, meUsername } from '../../initial_state';
|
||||||
import { previewState as previewMediaState } from './components/media_modal';
|
import { previewState as previewMediaState } from './components/media_modal';
|
||||||
@ -174,6 +175,7 @@ class SwitchingColumnsArea extends React.PureComponent {
|
|||||||
<WrappedRoute path='/timeline/all' exact page={HomePage} component={CommunityTimeline} content={children} />
|
<WrappedRoute path='/timeline/all' exact page={HomePage} component={CommunityTimeline} content={children} />
|
||||||
|
|
||||||
<WrappedRoute path='/groups' exact page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'featured' }} />
|
<WrappedRoute path='/groups' exact page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'featured' }} />
|
||||||
|
<WrappedRoute path='/groups/create' page={GroupsPage} component={GroupCreate} content={children} />
|
||||||
<WrappedRoute path='/groups/browse/member' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'member' }} />
|
<WrappedRoute path='/groups/browse/member' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'member' }} />
|
||||||
<WrappedRoute path='/groups/browse/admin' page={GroupsPage} component={Groups} content={children} componentParams={{ activeTab: 'admin' }} />
|
<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/members' page={GroupPage} component={GroupMembers} content={children} />
|
||||||
|
@ -42,6 +42,10 @@ export function GroupRemovedAccounts () {
|
|||||||
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts');
|
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/removed_accounts');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function GroupCreate () {
|
||||||
|
return import(/* webpackChunkName: "features/groups/timeline" */'../../groups/create');
|
||||||
|
}
|
||||||
|
|
||||||
export function Groups () {
|
export function Groups () {
|
||||||
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
|
return import(/* webpackChunkName: "features/groups/index" */'../../groups/index');
|
||||||
}
|
}
|
||||||
|
56
app/javascript/gabsocial/reducers/group_editor.js
Normal file
56
app/javascript/gabsocial/reducers/group_editor.js
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Map as ImmutableMap } from 'immutable';
|
||||||
|
import {
|
||||||
|
GROUP_CREATE_REQUEST,
|
||||||
|
GROUP_CREATE_FAIL,
|
||||||
|
GROUP_CREATE_SUCCESS,
|
||||||
|
GROUP_UPDATE_REQUEST,
|
||||||
|
GROUP_UPDATE_FAIL,
|
||||||
|
GROUP_UPDATE_SUCCESS,
|
||||||
|
GROUP_EDITOR_RESET,
|
||||||
|
GROUP_EDITOR_SETUP,
|
||||||
|
GROUP_EDITOR_VALUE_CHANGE,
|
||||||
|
} from '../actions/group_editor';
|
||||||
|
|
||||||
|
const initialState = ImmutableMap({
|
||||||
|
groupId: null,
|
||||||
|
isSubmitting: false,
|
||||||
|
isChanged: false,
|
||||||
|
title: '',
|
||||||
|
description: '',
|
||||||
|
coverImage: null,
|
||||||
|
});
|
||||||
|
|
||||||
|
export default function groupEditorReducer(state = initialState, action) {
|
||||||
|
switch(action.type) {
|
||||||
|
case GROUP_EDITOR_RESET:
|
||||||
|
return initialState;
|
||||||
|
case GROUP_EDITOR_SETUP:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('groupId', action.group.get('id'));
|
||||||
|
map.set('title', action.group.get('title'));
|
||||||
|
map.set('isSubmitting', false);
|
||||||
|
});
|
||||||
|
case GROUP_EDITOR_VALUE_CHANGE:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set(action.field, action.value);
|
||||||
|
map.set('isChanged', true);
|
||||||
|
});
|
||||||
|
case GROUP_CREATE_REQUEST:
|
||||||
|
case GROUP_UPDATE_REQUEST:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('isSubmitting', true);
|
||||||
|
map.set('isChanged', false);
|
||||||
|
});
|
||||||
|
case GROUP_CREATE_FAIL:
|
||||||
|
case GROUP_UPDATE_FAIL:
|
||||||
|
return state.set('isSubmitting', false);
|
||||||
|
case GROUP_CREATE_SUCCESS:
|
||||||
|
case GROUP_UPDATE_SUCCESS:
|
||||||
|
return state.withMutations(map => {
|
||||||
|
map.set('isSubmitting', false);
|
||||||
|
map.set('groupId', action.group.id);
|
||||||
|
});
|
||||||
|
default:
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
};
|
@ -35,6 +35,7 @@ import trends from './trends';
|
|||||||
import groups from './groups';
|
import groups from './groups';
|
||||||
import group_relationships from './group_relationships';
|
import group_relationships from './group_relationships';
|
||||||
import group_lists from './group_lists';
|
import group_lists from './group_lists';
|
||||||
|
import group_editor from './group_editor';
|
||||||
|
|
||||||
const reducers = {
|
const reducers = {
|
||||||
dropdown_menu,
|
dropdown_menu,
|
||||||
@ -73,6 +74,7 @@ const reducers = {
|
|||||||
groups,
|
groups,
|
||||||
group_relationships,
|
group_relationships,
|
||||||
group_lists,
|
group_lists,
|
||||||
|
group_editor,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default combineReducers(reducers);
|
export default combineReducers(reducers);
|
||||||
|
Loading…
Reference in New Issue
Block a user