Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add community creation validation and post creation #293

Merged
merged 1 commit into from May 16, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/client/Wrapper.js
Expand Up @@ -222,6 +222,9 @@ export default class Wrapper extends React.PureComponent {
case 'grow':
this.props.history.push('/grow');
break;
case 'create-community':
this.props.history.push('/create-community');
break;
case 'news':
this.props.history.push('/trending');
break;
Expand Down
238 changes: 217 additions & 21 deletions src/client/community/CreateCommunity.js
@@ -1,30 +1,208 @@
import React from 'react';
import { connect } from 'react-redux';
import { injectIntl } from 'react-intl';
import _ from 'lodash';
import PropTypes from 'prop-types';
import { message, Collapse, Button, List, Form, Input } from 'antd';
import ReactMarkdown from 'react-markdown';
import { message, Collapse, Button, List, Input } from 'antd';
import steemAPI from '../steemAPI';
import { getAuthenticatedUser, getIsEditorLoading, getUpvoteSetting } from '../reducers';
import Action from '../components/Button/Action';
import { notify } from '../app/Notification/notificationActions';
import { createPost } from '../post/Write/editorActions';
import * as community from '../helpers/community';

const version = require('../../../package.json').version;

@injectIntl
@connect(
state => ({
user: getAuthenticatedUser(state),
postCreationLoading: getIsEditorLoading(state),
upvote: getUpvoteSetting(state),
}),
{
notify,
createPost,
},
)
@Form.create()
class CreateCommunity extends React.Component {
static propTypes = {
postCreationLoading: PropTypes.bool.isRequired,
upvote: PropTypes.bool.isRequired,
user: PropTypes.shape().isRequired,
intl: PropTypes.shape().isRequired,
community: PropTypes.string,
form: PropTypes.shape().isRequired,
notify: PropTypes.func.isRequired,
createPost: PropTypes.func.isRequired,
};

static defaultProps = {
community: '',
currentInputValue: '',
visible: false,
};

static minAccountLength = 3;
static maxAccountLength = 16;

constructor(props) {
super(props);
// bind the component's methods so that it can be called within render() using this.displayComingSoon()
this.displayComingSoon = this.displayComingSoon.bind(this);
// bind the component's methods so that it can be called within render() using this.method()
this.validateCommunity = this.validateCommunity.bind(this);
this.handleCreatePost = this.handleCreatePost.bind(this);
}

/*
* Display a coming soon message when user clicks on any "Click Here" button
* Validate inputted community name
*/
displayComingSoon = () => {
message.success('Coming soon!', 3);
validateCommunity = (rule, value, callback) => {
const { intl } = this.props;

if (!value) {
callback();
return;
}

// prefix the community name with 'ulog-'
const ulogSubTag = 'ulog-' + value;

// if subtag is less than min length
if (ulogSubTag.length < CreateCommunity.minAccountLength) {
callback([
new Error(
intl.formatMessage(
{
id: 'subtag_too_short',
defaultMessage: 'Ulog subtag {subtag} is too short.',
},
{
subtag: ulogSubTag,
},
),
),
]);
return;
}

// if subtag is more than max length
if (ulogSubTag.length > CreateCommunity.maxAccountLength) {
callback([
new Error(
intl.formatMessage(
{
id: 'subtag_too_long',
defaultMessage: 'Ulog subtag {subtag} is too long.',
},
{
subtag: ulogSubTag,
},
),
),
]);
return;
}

// check if subtag already exists by using get_discussions API
steemAPI.sendAsync('get_discussions_by_created', [{ tag: ulogSubTag, limit: 1 }]).then(result => {
// if no posts already exists, return without error
if (result.length === 0) {
callback();
} else {
callback([
new Error(
intl.formatMessage(
{
id: 'community_error_found_tag',
defaultMessage: "Ulog community {subtag} already exists. Please try another one.",
},
{
subtag: ulogSubTag,
},
),
),
]);
}
});
};

/*
* Helper function to generate post data
*/
getQuickPostData = () => {
const { form } = this.props;
const postBody = "";
const community = form.getFieldValue('community');
const ulogSubTag = "ulog-" + community;
const postTitle = `A New Ulog Community - ${ulogSubTag} - Has Been Created!`;
const tags = [ulogSubTag];
const data = {
body: postBody,
title: postTitle,
reward: '50',
author: this.props.user.name,
parentAuthor: '',
lastUpdated: Date.now(),
upvote: this.props.upvote,
};

const metaData = {
community: 'ulogs',
app: `ulogs/${version}`,
format: 'markdown',
tags,
};

data.parentPermlink = ulogSubTag;
data.permlink = _.kebabCase(postTitle);
data.jsonMetadata = metaData;

return data;
};

/*
* Post creation handler when "Create Community" is clicked
*/
handleCreatePost = (e) => {
e.preventDefault();

const { form } = this.props;
// validate form fields
form.validateFieldsAndScroll((err, values) => {
// If no error, continue to submit community creation (create a post)
if (!err) {
const community = values.community;
const ulogSubTag = "ulog-" + community;

if (_.isEmpty(ulogSubTag)) {
this.props.notify(
this.props.intl.formatMessage({
id: 'community_error_empty_name',
defaultMessage: 'Community name cannot be empty.',
}),
'error',
);
return;
}
const data = this.getQuickPostData();
this.props.createPost(data);
}
});
};

render() {
// for the 'About Ulog' style
const { intl, postCreationLoading } = this.props;
const { getFieldDecorator } = this.props.form;

// Style for the 'About' description
const customPanelStyle = {
marginBottom: 5,
overflow: 'hidden',
};

// style for the different grow sections
// Style for the sections
const customCardStyle = {
marginBottom: '10px',
marginTop: '10px',
Expand All @@ -37,14 +215,12 @@ class CreateCommunity extends React.Component {
<h2 style={{ color: 'purple', textAlign: 'center' }}>Create A Ulog-Community</h2>
<Collapse defaultActiveKey={['1']}>
<Collapse.Panel header="About Communities" key="1" style={customPanelStyle}>
<p>
<ReactMarkdown source={community.aboutCommunities} />
</p>
<ReactMarkdown source={community.aboutCommunities} />
</Collapse.Panel>
</Collapse>

<Collapse defaultActiveKey={['1']}>
<Collapse.Panel showArrow={false} key="1">
<Collapse.Panel showArrow={false} key="1" disabled>
<List itemLayout="vertical" size="large">
<List.Item
key="Create A Ulog-Community"
Expand All @@ -53,16 +229,36 @@ class CreateCommunity extends React.Component {
<div style={customCardStyle}>
<ReactMarkdown source={community.createCommunity} />
</div>
<Input type="text" placeholder="Names should be a maximum of 19 characters, only alphabets, no special characters." allowClear />
<Button
type="primary"
onClick={this.displayComingSoon}
style={{ marginTop: '10px' }}
>
Create Now
</Button>
<Form onSubmit={this.handleCreatePost}>
<Form.Item>
{getFieldDecorator('community', {
rules: [
{
required: true,
message: intl.formatMessage({
id: 'community_error_empty',
defaultMessage: 'Community is required.',
}),
},
{ validator: this.validateCommunity },
],
})(
<Input
type="text"
placeholder="Names should be a maximum of 19 characters, only alphabets, no special characters."
/>
)}
</Form.Item>
<Action
primary
type="submit"
loading={postCreationLoading}
disabled={postCreationLoading}
>
{postCreationLoading ? "Creating Community..." : "Create Now"}
</Action>
</Form>
</List.Item>

</List>
</Collapse.Panel>
</Collapse>
Expand Down
3 changes: 3 additions & 0 deletions src/client/components/Navigation/Topnav.js
Expand Up @@ -264,6 +264,9 @@ class Topnav extends React.Component {
<PopoverMenuItem key="grow">
<FormattedMessage id="grow" defaultMessage="Grow"/>
</PopoverMenuItem>
<PopoverMenuItem key="create-community">
<FormattedMessage id="create-community" defaultMessage="Create Community"/>
</PopoverMenuItem>
<PopoverMenuItem key="get-certified">
<FormattedMessage id="get_certified" defaultMessage='Get "Certified"'/>
</PopoverMenuItem>
Expand Down