From 6104e45d18114e1bbddac70454d66ca010895503 Mon Sep 17 00:00:00 2001 From: 2458773093 <2458773093@protonmail.com> Date: Wed, 17 Jul 2019 21:56:06 +0300 Subject: [PATCH] group edit ui --- .../gabsocial/actions/group_editor.js | 35 +++++ .../gabsocial/features/groups/edit/index.js | 148 ++++++++++++++++++ .../gabsocial/features/groups/index/index.js | 2 +- .../groups/timeline/components/header.js | 4 +- app/javascript/gabsocial/features/ui/index.js | 2 + .../features/ui/util/async-components.js | 4 + .../gabsocial/reducers/group_editor.js | 1 + app/javascript/gabsocial/reducers/groups.js | 2 + .../gabsocial/components/group-card.scss | 10 ++ 9 files changed, 206 insertions(+), 2 deletions(-) create mode 100644 app/javascript/gabsocial/features/groups/edit/index.js diff --git a/app/javascript/gabsocial/actions/group_editor.js b/app/javascript/gabsocial/actions/group_editor.js index eda9dc52..e464c1c6 100644 --- a/app/javascript/gabsocial/actions/group_editor.js +++ b/app/javascript/gabsocial/actions/group_editor.js @@ -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, diff --git a/app/javascript/gabsocial/features/groups/edit/index.js b/app/javascript/gabsocial/features/groups/edit/index.js new file mode 100644 index 00000000..7f55a824 --- /dev/null +++ b/app/javascript/gabsocial/features/groups/edit/index.js @@ -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 ( + + + + ); + } else if (group === false) { + return ( + + + + ); + } + + return ( +
+

{intl.formatMessage(messages.heading)}

+ + + + + + + + + + ); + } + +} diff --git a/app/javascript/gabsocial/features/groups/index/index.js b/app/javascript/gabsocial/features/groups/index/index.js index c375b892..8374cae2 100644 --- a/app/javascript/gabsocial/features/groups/index/index.js +++ b/app/javascript/gabsocial/features/groups/index/index.js @@ -49,8 +49,8 @@ class Groups extends ImmutablePureComponent { return (
-
{intl.formatMessage(messages.heading)}
{intl.formatMessage(messages.create)}
+
{intl.formatMessage(messages.heading)}

diff --git a/app/javascript/gabsocial/features/groups/timeline/components/header.js b/app/javascript/gabsocial/features/groups/timeline/components/header.js index 58d2cf2f..9691fca3 100644 --- a/app/javascript/gabsocial/features/groups/timeline/components/header.js +++ b/app/javascript/gabsocial/features/groups/timeline/components/header.js @@ -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` }, ]; diff --git a/app/javascript/gabsocial/features/ui/index.js b/app/javascript/gabsocial/features/ui/index.js index 3c47de7f..d9d55dac 100644 --- a/app/javascript/gabsocial/features/ui/index.js +++ b/app/javascript/gabsocial/features/ui/index.js @@ -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 { + diff --git a/app/javascript/gabsocial/features/ui/util/async-components.js b/app/javascript/gabsocial/features/ui/util/async-components.js index 1aa0af28..40f75d7e 100644 --- a/app/javascript/gabsocial/features/ui/util/async-components.js +++ b/app/javascript/gabsocial/features/ui/util/async-components.js @@ -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'); } diff --git a/app/javascript/gabsocial/reducers/group_editor.js b/app/javascript/gabsocial/reducers/group_editor.js index 054eedd8..c0f3cef8 100644 --- a/app/javascript/gabsocial/reducers/group_editor.js +++ b/app/javascript/gabsocial/reducers/group_editor.js @@ -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: diff --git a/app/javascript/gabsocial/reducers/groups.js b/app/javascript/gabsocial/reducers/groups.js index 7ce12931..a8b8be23 100644 --- a/app/javascript/gabsocial/reducers/groups.js +++ b/app/javascript/gabsocial/reducers/groups.js @@ -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); diff --git a/app/javascript/styles/gabsocial/components/group-card.scss b/app/javascript/styles/gabsocial/components/group-card.scss index 32727bb1..799432ac 100644 --- a/app/javascript/styles/gabsocial/components/group-card.scss +++ b/app/javascript/styles/gabsocial/components/group-card.scss @@ -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 {