Skip to content

Commit

Permalink
Merge pull request #295 from surpassinggoogle/develop
Browse files Browse the repository at this point in the history
Add The Ability To Create Prospective Ulog-communities
  • Loading branch information
surpassinggoogle committed May 18, 2019
2 parents b325ab7 + efdd449 commit 2feb58e
Show file tree
Hide file tree
Showing 11 changed files with 365 additions and 8 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
.save
*.css.map
*.css
*.DS_Store

# Created by .ignore support plugin (hsz.mobi)
### Node template
Expand Down
3 changes: 3 additions & 0 deletions src/client/Wrapper.js
Original file line number Diff line number Diff line change
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
6 changes: 0 additions & 6 deletions src/client/app/Sidebar/RightSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,6 @@ export default class RightSidebar extends React.Component {
}
}
const isWitnessVoted = checkVote();
const { category } = match.params;
const displayUlogCaption =
category &&
category.match(
/^(ulog-quotes|ulog-howto|ulog-diy|ulog-surpassinggoogle|teardrops|untalented|ulog-ned|ulography|ulog-gratefulvibes|ulog-resolutions|ulog-memes|ulog-blocktrades|ulog-showerthoughts|ulog-snookmademedoit|ulog-utopian|ulog-thejohalfiles|ulogifs|ulog-surfyogi|ulog-bobbylee|ulog-stellabelle|ulog-sweetsssj|ulog-dimimp|ulog-teamsteem|ulog-kusknee|ulog-papapepper|ulog-steemjet)$/,
);

return (
<div>
Expand Down
272 changes: 272 additions & 0 deletions src/client/community/CreateCommunity.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,272 @@
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 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.method()
this.validateCommunity = this.validateCommunity.bind(this);
this.handleCreatePost = this.handleCreatePost.bind(this);
}

/*
* Validate inputted community name
*/
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() {
const { intl, postCreationLoading } = this.props;
const { getFieldDecorator } = this.props.form;

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

// Style for the sections
const customCardStyle = {
marginBottom: '10px',
marginTop: '10px',
};

return (
<div className="shifted">
<div className="container">
<div className="center" style={{ marginBottom: '50px' }}>
<h2 style={{ color: 'purple', textAlign: 'center' }}>Create A Ulog-Community</h2>
<Collapse defaultActiveKey={['1']}>
<Collapse.Panel header="About Communities" key="1" style={customPanelStyle}>
<ReactMarkdown source={community.aboutCommunities} />
</Collapse.Panel>
</Collapse>

<Collapse defaultActiveKey={['1']}>
<Collapse.Panel showArrow={false} key="1" disabled>
<List itemLayout="vertical" size="large">
<List.Item
key="Create A Ulog-Community"
>
<h3>Create A Ulog-Community</h3>
<div style={customCardStyle}>
<ReactMarkdown source={community.createCommunity} />
</div>
<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>
</div>
</div>
</div>
);
}
}

export default CreateCommunity;
3 changes: 3 additions & 0 deletions src/client/components/Navigation/Topnav.js
Original file line number Diff line number Diff line change
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
3 changes: 3 additions & 0 deletions src/client/components/Sidebar/FeedSidebar.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import CryptoTrendingCharts from './CryptoTrendingCharts';
import ChatBar from '../../components/Sidebar/ChatBar';
import UlogGamesExchanges from '../../components/Sidebar/UlogGamesExchanges';
import UlogCaption from '../../feed/UlogCaption';
import UlogGenericCaption from '../../feed/UlogGenericCaption';

@connect(
state => ({
Expand Down Expand Up @@ -52,11 +53,13 @@ class FeedSidebar extends React.Component {
tag.match(
/^(ulog-quotes|ulog-howto|ulog-diy|ulog-surpassinggoogle|teardrops|untalented|ulog-ned|ulography|ulog-gratefulvibes|ulog-resolutions|ulog-memes|ulog-blocktrades|ulog-showerthoughts|ulog-snookmademedoit|ulog-utopian|ulog-thejohalfiles|ulogifs|ulog-surfyogi|ulog-bobbylee|ulog-stellabelle|ulog-sweetsssj|ulog-dimimp|ulog-teamsteem|ulog-kusknee|ulog-papapepper|ulog-steemjet)$/,
);
const isStartsWithUlog = tag && tag.startsWith('ulog-');
return (
<div>
{!_.isEmpty(currentCrypto) && <CryptoTrendingCharts cryptos={[currentTag]} />}
<React.Fragment>
{displayUlogCaption && <UlogCaption category={tag} />}
{(!displayUlogCaption && isStartsWithUlog) && <UlogGenericCaption category={tag} />}
<OverseeingUloggers authenticatedUser={authenticatedUser} />
<UlogGamesExchanges isFetchingFollowingList={false} />
<ChatBar isFetchingFollowingList={false} authenticated={authenticated} />
Expand Down
4 changes: 2 additions & 2 deletions src/client/feed/Page.js
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,8 @@ class Page extends React.Component {
) : (
<HeroBannerContainer />
)}
{displayUlogCaption && <UlogsBanner category={category} />}
{(!displayUlogCaption && isStartsWithUlog) && <UlogsBanner category={category} />}
{(authenticated && displayUlogCaption) && <UlogsBanner category={category} />}
{(authenticated && !displayUlogCaption && isStartsWithUlog) && <UlogsBanner category={category} />}
<MainMenu />
<div className="shifted">
<div className="feed-layout container">
Expand Down
52 changes: 52 additions & 0 deletions src/client/feed/UlogGenericCaption.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/* eslint-disable react/no-unescaped-entities */

import React from 'react';
import PropTypes from 'prop-types';
import { Collapse, Button, Icon } from 'antd';
import { injectIntl, FormattedMessage } from 'react-intl';
import ReactMarkdown from 'react-markdown';
import { generic } from '../helpers/ulogCaptions';

@injectIntl
class UlogGenericCaption extends React.Component {
static propTypes = {
category: PropTypes.string.isRequired,
};

constructor(props) {
super(props);
}

render() {
const category = this.props.category;
const about = `About #${category}`;

return (
<div className="ulog-quotes">
<Collapse defaultActiveKey={['1']}>
<Collapse.Panel header={about} key="1">
<ReactMarkdown source={generic} />
<div
style={{
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
marginTop: '10px',
}}
>
<Button
type={'primary'}
href='/main-editor'
>
<FormattedMessage id="post_now" defaultMessage="Post now" />
</Button>
</div>
</Collapse.Panel>
</Collapse>
</div>
);
}
}

export default UlogGenericCaption;
Loading

0 comments on commit 2feb58e

Please sign in to comment.