8c047868e3
• Added: - ProUpgradeModal to group creation action buttons and page if not pro or if not admin of edit group
405 lines
12 KiB
JavaScript
405 lines
12 KiB
JavaScript
import React from 'react'
|
||
import PropTypes from 'prop-types'
|
||
import { connect } from 'react-redux'
|
||
import ImmutablePropTypes from 'react-immutable-proptypes'
|
||
import ImmutablePureComponent from 'react-immutable-pure-component'
|
||
import { defineMessages, injectIntl } from 'react-intl'
|
||
import isObject from 'lodash.isobject'
|
||
import {
|
||
changeGroupTitle,
|
||
changeGroupDescription,
|
||
changeGroupCoverImage,
|
||
changeGroupId,
|
||
changeGroupTags,
|
||
changeGroupCategory,
|
||
changeGroupIsPrivate,
|
||
changeGroupIsVisible,
|
||
submit,
|
||
setGroup,
|
||
resetEditor,
|
||
} from '../actions/group_editor'
|
||
import {
|
||
openModal,
|
||
closeModal,
|
||
} from '../actions/modal'
|
||
import { fetchGroup } from '../actions/groups'
|
||
import { fetchGroupCategories } from '../actions/group_categories'
|
||
import { me } from '../initial_state'
|
||
import { MODAL_PRO_UPGRADE } from '../constants'
|
||
import ColumnIndicator from '../components/column_indicator'
|
||
import Button from '../components/button'
|
||
import Divider from '../components/divider'
|
||
import Input from '../components/input'
|
||
import Text from '../components/text'
|
||
import Form from '../components/form'
|
||
import Switch from '../components/switch'
|
||
import Select from '../components/select'
|
||
import Textarea from '../components/textarea'
|
||
import FileInput from '../components/file_input'
|
||
|
||
class GroupCreate extends ImmutablePureComponent {
|
||
|
||
static contextTypes = {
|
||
router: PropTypes.object
|
||
}
|
||
|
||
componentDidMount() {
|
||
const { groupId, group } = this.props
|
||
|
||
this.props.onFetchGroupCategories()
|
||
|
||
if (!group) {
|
||
if (groupId) {
|
||
this.props.onFetchGroup(groupId)
|
||
} else {
|
||
this.props.onResetEditor()
|
||
}
|
||
} else {
|
||
this.props.onSetGroup(group)
|
||
}
|
||
}
|
||
|
||
componentWillReceiveProps(nextProps) {
|
||
if (this.props.group !== nextProps.group && !!nextProps.group) {
|
||
this.props.onSetGroup(nextProps.group)
|
||
}
|
||
}
|
||
|
||
handleCoverImageChange = (e) => {
|
||
try {
|
||
this.props.onCoverImageChange(e.target.files[0])
|
||
} catch (error) {
|
||
//
|
||
}
|
||
}
|
||
|
||
handleSubmit = (e) => {
|
||
e.preventDefault()
|
||
|
||
// if not pro and not admin of group show pro upgrade modal
|
||
if (!this.props.isPro && !this.props.isAdmin) {
|
||
this.props.onOpenProUpgradeModal()
|
||
return
|
||
}
|
||
|
||
if (this.props.onClose) this.props.onClose()
|
||
this.props.onSubmit(this.context.router.history)
|
||
}
|
||
|
||
render() {
|
||
const {
|
||
group,
|
||
error,
|
||
titleValue,
|
||
descriptionValue,
|
||
coverImage,
|
||
intl,
|
||
onTitleChange,
|
||
onDescriptionChange,
|
||
onChangeGroupId,
|
||
onChangeGroupTags,
|
||
onChangeGroupCategory,
|
||
onChangeGroupIsPrivate,
|
||
onChangeGroupIsVisible,
|
||
isSubmitting,
|
||
onSubmit,
|
||
idValue,
|
||
tags,
|
||
category,
|
||
isPrivate,
|
||
isVisible,
|
||
groupId,
|
||
categories,
|
||
isAdmin,
|
||
isPro,
|
||
} = this.props
|
||
|
||
if (!group && groupId) {
|
||
return <ColumnIndicator type='loading' />
|
||
} else if ((!group && error) || (groupId && !isAdmin)) {
|
||
return <ColumnIndicator type='missing' />
|
||
} else if (!isPro && !groupId) {
|
||
return <ColumnIndicator type='error' message={(
|
||
<React.Fragment>
|
||
<Text>You must be a GabPRO member to create a group.</Text>
|
||
<Button
|
||
onClick={this.props.onOpenProUpgradeModal}
|
||
className={[_s.mt15, _s.mlAuto, _s.mrAuto].join(' ')}
|
||
>
|
||
Learn more
|
||
</Button>
|
||
</React.Fragment>
|
||
)} />
|
||
}
|
||
|
||
const memberCount = group ? group.get('member_count') : 0
|
||
const hasGroupSlug = group ? !!group.get('slug') : false
|
||
let categoriesOptions = []
|
||
if (categories) {
|
||
for (let i = 0; i < categories.count(); i++) {
|
||
const c = categories.get(i)
|
||
categoriesOptions.push({
|
||
title: c.get('text'),
|
||
value: c.get('id'),
|
||
})
|
||
}
|
||
}
|
||
|
||
return (
|
||
<Form onSubmit={onSubmit}>
|
||
<Input
|
||
id='group-title'
|
||
title={intl.formatMessage(messages.title)}
|
||
value={titleValue}
|
||
onChange={onTitleChange}
|
||
disabled={isSubmitting}
|
||
placeholder={intl.formatMessage(messages.titlePlaceholder)}
|
||
/>
|
||
|
||
<Divider isInvisible />
|
||
|
||
{
|
||
memberCount >= 50 && !hasGroupSlug &&
|
||
<React.Fragment>
|
||
<Input
|
||
id='group-id'
|
||
title={intl.formatMessage(messages.idTitle)}
|
||
value={idValue}
|
||
onChange={onChangeGroupId}
|
||
disabled={isSubmitting}
|
||
/>
|
||
<Text className={[_s.mt5, _s.pl15]} size='small' color='secondary'>
|
||
{
|
||
!!idValue &&
|
||
<b>g/{idValue} – </b>
|
||
}
|
||
{intl.formatMessage(messages.idDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
</React.Fragment>
|
||
}
|
||
|
||
<Input
|
||
id='group-tags'
|
||
title={intl.formatMessage(messages.tagsTitle)}
|
||
value={tags}
|
||
onChange={onChangeGroupTags}
|
||
disabled={isSubmitting}
|
||
/>
|
||
<Text className={[_s.mt5, _s.pl15]} size='small' color='secondary'>
|
||
{intl.formatMessage(messages.tagsDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
|
||
<div className={_s.d}>
|
||
<Text className={[_s.pl15, _s.mb10].join(' ')} size='small' weight='medium' color='secondary'>
|
||
{intl.formatMessage(messages.categoryTitle)}
|
||
</Text>
|
||
<Select
|
||
value={category}
|
||
onChange={onChangeGroupCategory}
|
||
options={categoriesOptions}
|
||
/>
|
||
<Text className={[_s.mt5, _s.pl15].join(' ')} size='small' color='secondary'>
|
||
{intl.formatMessage(messages.categoryDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
</div>
|
||
|
||
<Textarea
|
||
title={intl.formatMessage(messages.description)}
|
||
value={descriptionValue}
|
||
onChange={onDescriptionChange}
|
||
placeholder={intl.formatMessage(messages.descriptionPlaceholder)}
|
||
disabled={isSubmitting}
|
||
/>
|
||
|
||
<Divider isInvisible />
|
||
|
||
<FileInput
|
||
disabled={isSubmitting}
|
||
id='group-cover-photo'
|
||
title={intl.formatMessage(coverImage === null ? messages.coverImage : messages.coverImageChange)}
|
||
onChange={this.handleCoverImageChange}
|
||
file={group ? group.get('cover_image_url') : undefined}
|
||
width='340px'
|
||
height='145px'
|
||
isBordered
|
||
/>
|
||
<Text className={[_s.mt5, _s.pl15].join(' ')} size='small' color='secondary'>
|
||
{intl.formatMessage(messages.coverImageDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
|
||
<Switch
|
||
label={'Private'}
|
||
id='group-isprivate'
|
||
checked={isPrivate}
|
||
onChange={onChangeGroupIsPrivate}
|
||
/>
|
||
<Text className={_s.mt5} size='small' color='secondary'>
|
||
{intl.formatMessage(messages.isPrivateDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
|
||
<Switch
|
||
label={'Visible'}
|
||
id='group-isvisible'
|
||
checked={isVisible}
|
||
onChange={onChangeGroupIsVisible}
|
||
/>
|
||
<Text className={_s.mt5} size='small' color='secondary'>
|
||
{intl.formatMessage(messages.isVisibleDescription)}
|
||
</Text>
|
||
|
||
<Divider isInvisible />
|
||
|
||
<Button
|
||
isDisabled={!titleValue || !descriptionValue && !isSubmitting}
|
||
onClick={this.handleSubmit}
|
||
>
|
||
<Text color='inherit' align='center'>
|
||
{intl.formatMessage(!!group ? messages.update : messages.create)}
|
||
</Text>
|
||
</Button>
|
||
|
||
</Form>
|
||
)
|
||
}
|
||
|
||
}
|
||
|
||
|
||
const messages = defineMessages({
|
||
title: { id: 'groups.form.title', defaultMessage: 'Title' },
|
||
idTitle: { id: 'groups.form.id_title', defaultMessage: 'Unique id' },
|
||
idDescription: { id: 'groups.form.id_description', defaultMessage: 'A unique id that links to this group. (Cannot be changed)' },
|
||
tagsTitle: { id: 'groups.form.tags_title', defaultMessage: 'Tags' },
|
||
tagsDescription: { id: 'groups.form.tags_description', defaultMessage: 'Add tags seperated by commas to increase group visibility' },
|
||
categoryTitle: { id: 'groups.form.category_title', defaultMessage: 'Category' },
|
||
categoryDescription: { id: 'groups.form.category_description', defaultMessage: 'Add a general category for your group' },
|
||
description: { id: 'groups.form.description', defaultMessage: 'Enter the group description' },
|
||
coverImage: { id: 'groups.form.coverImage', defaultMessage: 'Upload a banner image' },
|
||
coverImageDescription: { id: 'groups.form.coverImage_description', defaultMessage: 'Accepted image types: .jpg, .png' },
|
||
coverImageChange: { id: 'groups.form.coverImageChange', defaultMessage: 'Banner image selected' },
|
||
create: { id: 'groups.form.create', defaultMessage: 'Create group' },
|
||
update: { id: 'groups.form.update', defaultMessage: 'Update group' },
|
||
titlePlaceholder: { id: 'groups.form.title_placeholder', defaultMessage: 'New group title...' },
|
||
descriptionPlaceholder: { id: 'groups.form.description_placeholder', defaultMessage: 'This group is about...' },
|
||
isPrivateDescription: { id: 'groups.form.is_private_description', defaultMessage: 'Only members can see group posts.' },
|
||
isVisibleDescription: { id: 'groups.form.is_visible_description', defaultMessage: 'Anyone can find a visible group in search and other places on Gab.' },
|
||
})
|
||
|
||
const mapStateToProps = (state, { params }) => {
|
||
const groupId = isObject(params) ? params['id'] : null
|
||
const group = state.getIn(['groups', groupId])
|
||
let isAdmin = false
|
||
|
||
if (groupId) {
|
||
const relationships = state.getIn(['group_relationships', groupId])
|
||
if (relationships) {
|
||
isAdmin = relationships.get('admin')
|
||
}
|
||
}
|
||
|
||
return {
|
||
group,
|
||
groupId,
|
||
isAdmin,
|
||
error: (groupId && !group) || (group && !isAdmin),
|
||
titleValue: state.getIn(['group_editor', 'title']),
|
||
descriptionValue: state.getIn(['group_editor', 'description']),
|
||
coverImage: state.getIn(['group_editor', 'coverImage']),
|
||
isSubmitting: state.getIn(['group_editor', 'isSubmitting']),
|
||
idValue: state.getIn(['group_editor', 'id']),
|
||
tags: state.getIn(['group_editor', 'tags']),
|
||
category: state.getIn(['group_editor', 'category']),
|
||
isPrivate: state.getIn(['group_editor', 'isPrivate']),
|
||
isVisible: state.getIn(['group_editor', 'isVisible']),
|
||
categories: state.getIn(['group_categories', 'items']),
|
||
isPro: state.getIn(['accounts', me, 'is_pro']),
|
||
}
|
||
}
|
||
|
||
const mapDispatchToProps = (dispatch) => ({
|
||
onTitleChange(value) {
|
||
dispatch(changeGroupTitle(value))
|
||
},
|
||
onDescriptionChange(value) {
|
||
dispatch(changeGroupDescription(value))
|
||
},
|
||
onCoverImageChange(imageData) {
|
||
dispatch(changeGroupCoverImage(imageData))
|
||
},
|
||
onChangeGroupId(value) {
|
||
dispatch(changeGroupId(value))
|
||
},
|
||
onChangeGroupTags(value) {
|
||
dispatch(changeGroupTags(value))
|
||
},
|
||
onChangeGroupCategory(e) {
|
||
dispatch(changeGroupCategory(e.target.value))
|
||
},
|
||
onChangeGroupIsPrivate(checked) {
|
||
dispatch(changeGroupIsPrivate(checked))
|
||
},
|
||
onChangeGroupIsVisible(checked) {
|
||
dispatch(changeGroupIsVisible(checked))
|
||
},
|
||
onResetEditor() {
|
||
dispatch(resetEditor())
|
||
},
|
||
onSetGroup(group) {
|
||
dispatch(setGroup(group))
|
||
},
|
||
onSubmit(routerHistory) {
|
||
dispatch(submit(routerHistory))
|
||
dispatch(closeModal())
|
||
},
|
||
onFetchGroup(groupId) {
|
||
dispatch(fetchGroup(groupId))
|
||
},
|
||
onFetchGroupCategories() {
|
||
dispatch(fetchGroupCategories())
|
||
},
|
||
onOpenProUpgradeModal() {
|
||
dispatch(openModal(MODAL_PRO_UPGRADE))
|
||
},
|
||
})
|
||
|
||
GroupCreate.propTypes = {
|
||
group: ImmutablePropTypes.map,
|
||
titleValue: PropTypes.string.isRequired,
|
||
descriptionValue: PropTypes.string.isRequired,
|
||
coverImage: PropTypes.object,
|
||
intl: PropTypes.object.isRequired,
|
||
onTitleChange: PropTypes.func.isRequired,
|
||
onDescriptionChange: PropTypes.func.isRequired,
|
||
onChangeGroupId: PropTypes.func.isRequired,
|
||
onChangeGroupTags: PropTypes.func.isRequired,
|
||
onChangeGroupCategory: PropTypes.func.isRequired,
|
||
onChangeGroupIsPrivate: PropTypes.func.isRequired,
|
||
onChangeGroupIsVisible: PropTypes.func.isRequired,
|
||
onFetchGroup: PropTypes.func.isRequired,
|
||
onFetchGroupCategories: PropTypes.func.isRequired,
|
||
onResetEditor: PropTypes.func.isRequired,
|
||
onSetGroup: PropTypes.func.isRequired,
|
||
onSubmit: PropTypes.func.isRequired,
|
||
onOpenProUpgradeModal: PropTypes.func.isRequired,
|
||
isSubmitting: PropTypes.bool,
|
||
isAdmin: PropTypes.bool,
|
||
onClose: PropTypes.func,
|
||
idValue: PropTypes.string.isRequired,
|
||
tags: PropTypes.string.isRequired,
|
||
category: PropTypes.string.isRequired,
|
||
isPrivate: PropTypes.bool.isRequired,
|
||
isVisible: PropTypes.bool.isRequired,
|
||
categories: ImmutablePropTypes.list.isRequired,
|
||
}
|
||
|
||
export default injectIntl(connect(mapStateToProps, mapDispatchToProps)(GroupCreate)) |