Commit ebfd8893 authored by NGUYEN DINH Quoc-Huy's avatar NGUYEN DINH Quoc-Huy
Browse files

Cross-posts for full post pages + refactor for post index pages

parent 6f2e82c1
......@@ -10,12 +10,10 @@ import Voting from 'app/components/elements/Voting';
import Reblog from 'app/components/elements/Reblog';
import MarkdownViewer from 'app/components/cards/MarkdownViewer';
import ReplyEditor from 'app/components/elements/ReplyEditor';
import { immutableAccessor } from 'app/utils/Accessors';
import { extractBodySummary } from 'app/utils/ExtractContent';
import Tag from 'app/components/elements/Tag';
import TagList from 'app/components/elements/TagList';
import Author from 'app/components/elements/Author';
import { parsePayoutAmount } from 'app/utils/ParsersAndFormatters';
import DMCAList from 'app/utils/DMCAList';
import ShareMenu from 'app/components/elements/ShareMenu';
import MuteButton from 'app/components/elements/MuteButton';
......@@ -28,8 +26,9 @@ import userIllegalContent from 'app/utils/userIllegalContent';
import ImageUserBlockList from 'app/utils/ImageUserBlockList';
import LoadingIndicator from 'app/components/elements/LoadingIndicator';
import { allowDelete } from 'app/utils/StateFunctions';
import ContentEditedWrapper from '../elements/ContentEditedWrapper';
import { Role } from 'app/utils/Community';
import UserNames from 'app/components/elements/UserNames';
import ContentEditedWrapper from '../elements/ContentEditedWrapper';
function TimeAuthorCategory({ post }) {
return (
......@@ -43,17 +42,28 @@ function TimeAuthorCategory({ post }) {
}
function TimeAuthorCategoryLarge({ post }) {
const crossPostedBy = post.get('cross_posted_by');
let author = post.get('author');
let created = post.get('created');
let updated = post.get('updated');
if (crossPostedBy) {
author = post.get('cross_post_author');
created = post.get('cross_post_created');
updated = post.get('cross_post_updated');
}
return (
<span className="PostFull__time_author_category_large vcard">
<Userpic account={post.get('author')} />
<Userpic account={author} />
<div className="right-side">
<Author post={post} showAffiliation />
<Author post={post} showAffiliation resolveCrossPost />
{tt('g.in')} <Tag post={post} />
{''}
<TimeAgoWrapper date={post.get('created')} />{' '}
<TimeAgoWrapper date={created} />{' '}
<ContentEditedWrapper
createDate={post.get('created')}
updateDate={post.get('updated')}
createDate={created}
updateDate={updated}
/>
</div>
</span>
......@@ -77,7 +87,6 @@ class PostFull extends React.Component {
constructor(props) {
super(props);
const { post } = this.props;
this.fbShare = this.fbShare.bind(this);
this.twitterShare = this.twitterShare.bind(this);
......@@ -249,14 +258,54 @@ class PostFull extends React.Component {
} = this;
if (!post) return null;
const content = post.toJS();
const { author, permlink, parent_author, parent_permlink } = content;
const {
author,
permlink,
parent_author,
parent_permlink,
community_title,
cross_posted_by,
cross_post_author: crossPostAuthor,
cross_post_permlink: crossPostPermlink,
cross_post_category: crossPostCategory,
} = content;
const { category, title } = content;
const link = `/${category}/@${author}/${permlink}`;
let crossPostedBy = cross_posted_by;
if (crossPostedBy) {
crossPostedBy = (
<div className="articles__crosspost">
<p className="articles__crosspost-text">
<span className="articles__crosspost-icon">
<Icon name="reblog" />
</span>
<UserNames names={[author]} />{' '}
{tt('postsummary_jsx.crossposted')}{' '}
<Link
to={`${crossPostCategory}/@${crossPostAuthor}/${
crossPostPermlink
}`}
>
this post
</Link>{' '}
{tt('g.in')}{' '}
<Link to={`/created/${community}`}>
{community_title}
</Link>{' '}
<TimeAgoWrapper date={post.get('created')} />
</p>
<hr />
</div>
);
}
if (process.env.BROWSER && title)
document.title = title + '' + APP_NAME;
let content_body = post.get('body');
let content_body = crossPostedBy
? post.get('cross_post_body')
: post.get('body');
const bDMCAStop = DMCAList.includes(link);
const bIllegalContentUser = userIllegalContent.includes(author);
if (bDMCAStop) {
......@@ -353,14 +402,17 @@ class PostFull extends React.Component {
const isReply = post.get('depth') > 0;
let post_header = (
<h1 className="entry-title">
{post.get('title')}
{full_power && (
<span title={tt('g.powered_up_100')}>
<Icon name="hivepower" />
</span>
)}
</h1>
<div>
{crossPostedBy}
<h1 className="entry-title">
{post.get('title')}
{full_power && (
<span title={tt('g.powered_up_100')}>
<Icon name="hivepower" />
</span>
)}
</h1>
</div>
);
if (isReply) {
......
......@@ -117,10 +117,10 @@ class PostSummary extends React.Component {
const showReblog = !isReply;
const full_power = post.get('percent_steem_dollars') === 0;
const author = post.get('author');
const permlink = post.get('permlink');
const category = post.get('category');
const post_url = `/${category}/@${author}/${permlink}`;
let author = post.get('author');
let permlink = post.get('permlink');
let category = post.get('category');
let post_url = `/${category}/@${author}/${permlink}`;
const summary = extractBodySummary(post.get('body'), isReply);
const content_body = (
......@@ -138,14 +138,24 @@ class PostSummary extends React.Component {
</h2>
);
const summaryAuthor = crossPostedBy
? post.get('cross_post_author')
: post.get('author');
// New Post Summary heading
const summary_header = (
<div className="articles__summary-header">
<div className="user">
{!isNsfw ? (
<div className="user__col user__col--left">
<a className="user__link" href={'/@' + author}>
<Userpic account={author} size={SIZE_SMALL} />
<a
className="user__link"
href={`/@${summaryAuthor}`}
>
<Userpic
account={summaryAuthor}
size={SIZE_SMALL}
/>
</a>
</div>
) : null}
......@@ -155,6 +165,7 @@ class PostSummary extends React.Component {
post={post}
follow={false}
hideEditor={true}
resolveCrossPost
/>
</span>
......
/* eslint react/prop-types: 0 */
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import ReactDOM from 'react-dom';
import { Link } from 'react-router';
import tt from 'counterpart';
import { List } from 'immutable';
import ReactDOM, { findDOMNode } from 'react-dom';
import Overlay from 'react-overlays/lib/Overlay';
import shouldComponentUpdate from 'app/utils/shouldComponentUpdate';
import Icon from 'app/components/elements/Icon';
import { Link } from 'react-router';
import AuthorDropdown from '../AuthorDropdown';
import Reputation from 'app/components/elements/Reputation';
import AffiliationMap from 'app/utils/AffiliationMap';
import tt from 'counterpart';
import Overlay from 'react-overlays/lib/Overlay';
import { findDOMNode } from 'react-dom';
import UserTitle from 'app/components/elements/UserTitle';
import { Role } from 'app/utils/Community';
import { List } from 'immutable';
import AuthorDropdown from '../AuthorDropdown';
const { string, bool, number } = PropTypes;
......@@ -37,6 +36,9 @@ class Author extends React.Component {
role: string,
title: string,
community: string,
crossPostedBy: string,
crossPostAuthor: string,
resolveCrossPost: bool,
};
static defaultProps = {
follow: true,
......@@ -45,6 +47,9 @@ class Author extends React.Component {
role: '',
title: '',
community: '',
crossPostedBy: null,
crossPostAuthor: null,
resolveCrossPost: true,
};
constructor(...args) {
......@@ -98,6 +103,7 @@ class Author extends React.Component {
};
shouldComponentUpdate = shouldComponentUpdate(this, 'Author');
render() {
const {
author,
......@@ -107,7 +113,6 @@ class Author extends React.Component {
mute,
showAffiliation,
blacklists,
community,
permlink,
role,
......@@ -202,21 +207,30 @@ class Author extends React.Component {
}
}
import { connect } from 'react-redux';
export default connect((state, props) => {
const { post } = props;
const { post, resolveCrossPost } = props;
const blacklists = post.get('blacklists', List()).toJS();
const crossPostedBy = post.get('cross_posted_by');
let author = post.get('author');
let authorRep = post.get('author_reputation');
if (resolveCrossPost && crossPostedBy) {
author = post.get('cross_post_author');
authorRep = post.get('cross_post_author_reputation');
}
return {
follow: typeof props.follow === 'undefined' ? true : props.follow,
mute: typeof props.mute === 'undefined' ? props.follow : props.mute,
username: state.user.getIn(['current', 'username']),
authorRep: post.get('author_reputation'),
author: post.get('author'),
authorRep,
author,
community: post.get('community'), // UserTitle
permlink: post.get('permlink'), // UserTitle
role: post.get('author_role'), // UserTitle
title: post.get('author_title'), // UserTitle
blacklists: blacklists.length > 0 ? blacklists : null,
crossPostedBy: post.get('cross_posted_by'),
crossPostAuthor: post.get('cross_post_author'),
};
})(Author);
......@@ -72,11 +72,17 @@ export default class Reblog extends React.Component {
render() {
const state = this.state.active ? 'active' : 'inactive';
const loading = this.state.loading ? ' loading' : '';
const { author, permlink } = this.props;
return (
<span
className={'Reblog__button Reblog__button-' + state + loading}
>
<a href="#" onClick={this.reblog} title={tt('g.reblog')}>
<a
href="#"
onClick={this.reblog}
title={`${tt('g.reblog')} @${author}/${permlink}`}
>
<Icon name="reblog" />
</a>
</span>
......
......@@ -2,8 +2,15 @@ import React from 'react';
import { Link } from 'react-router';
const Tag = ({ post }) => {
const tag = post.get('category');
const name = post.get('community_title', '#' + tag);
const crossPostedBy = post.get('cross_posted_by');
let tag = post.get('category');
let name = post.get('community_title', '#' + tag);
if (crossPostedBy) {
tag = post.get('cross_post_category');
name = post.get('cross_post_community_title', '#' + tag);
}
return (
<Link to={`/trending/${tag}`} key={tag}>
{name}
......
......@@ -122,7 +122,6 @@ class Post extends React.Component {
</div>
);
} else {
console.log('post', post, content);
postBody = <PostFull post={post} cont={content} />;
}
......
......@@ -575,6 +575,7 @@
"reblogged": "reblogged",
"reblogged_by": "Reblogged by",
"crossposted": "cross-posted",
"crossposted_from": "Cross-posted from",
"reveal_it": "Reveal this post",
"adjust_your": "adjust your",
"display_preferences": "display preferences",
......
......@@ -78,52 +78,31 @@ export async function getStateAsync(url, observer, ssr = false) {
return cleansed;
}
async function loadThread(account, permlink) {
const author = account.slice(1);
const content = await callBridge('get_discussion', { author, permlink });
return { content };
}
async function loadPosts(sort, tag, observer) {
const account = tag && tag[0] == '@' ? tag.slice(1) : null;
let posts;
if (account) {
const params = { sort, account, observer };
posts = await callBridge('get_account_posts', params);
} else {
const params = { sort, tag, observer };
posts = await callBridge('get_ranked_posts', params);
}
async function fetchCrossPosts(posts, observer) {
const crossPostRegex = /^This is a cross post of \[@(.*?)\/(.*?)\]\(\/.*?@.*?\/.*?\) by @.*?\.<br><br>\.\.\./;
const crossPostPromises = [];
let content = {};
let keys = [];
for (let idx in posts) {
if (posts.hasOwnProperty(idx)) {
const post = posts[idx];
const crossPostMatches = crossPostRegex.exec(post.body);
if (crossPostMatches) {
const [, crossPostAuthor, crossPostPermlink] = crossPostMatches;
const crossPostParams = {
author: crossPostAuthor,
permlink: crossPostPermlink,
observer,
};
crossPostPromises.push(callBridge('get_post', crossPostParams));
post.cross_post_author = crossPostAuthor;
post.cross_post_permlink = crossPostPermlink;
post.cross_posted_by = post.author;
post.cross_post_key = `${crossPostAuthor}/${crossPostPermlink}`;
}
const key = post['author'] + '/' + post['permlink'];
content[key] = post;
keys.push(key);
const post = posts[idx];
const crossPostMatches = crossPostRegex.exec(post.body);
if (crossPostMatches) {
const [, crossPostAuthor, crossPostPermlink] = crossPostMatches;
const crossPostParams = {
author: crossPostAuthor,
permlink: crossPostPermlink,
observer,
};
crossPostPromises.push(callBridge('get_post', crossPostParams));
post.cross_post_key = `${crossPostAuthor}/${crossPostPermlink}`;
}
const key = post['author'] + '/' + post['permlink'];
content[key] = post;
keys.push(key);
}
const crossPosts = {};
......@@ -135,27 +114,106 @@ async function loadPosts(sort, tag, observer) {
if (response.state === 'resolved') {
const crossPost = response.value;
const key = crossPost['author'] + '/' + crossPost['permlink'];
crossPosts[key] = crossPost;
const crossPostKey = `${crossPost.author}/${
crossPost.permlink
}`;
crossPosts[crossPostKey] = crossPost;
} else {
console.error('cross post error', response);
}
}
resolve(crossPosts);
} catch (error) {
console.error('Failed fetching cross posts', error.message);
}
return {
content,
keys,
crossPosts,
};
}
function augmentContentWithCrossPost(post, crossPost) {
if (!crossPost) {
return post;
}
const fieldsToAugment = [
'body',
'author',
'permlink',
'author_reputation',
'created',
'category',
'community',
'community_title',
'json_metadata',
'updated',
];
for (let fi = 0; fi < fieldsToAugment.length; fi += 1) {
const fieldToRewrite = fieldsToAugment[fi];
if (crossPost.hasOwnProperty(fieldToRewrite)) {
post[`cross_post_${fieldToRewrite}`] = crossPost[fieldToRewrite];
}
}
post.cross_posted_by = post.author;
return post;
}
async function loadThread(account, permlink) {
const author = account.slice(1);
const content = await callBridge('get_discussion', { author, permlink });
if (content) {
const {
content: preppedContent,
keys,
crossPosts,
} = await fetchCrossPosts([Object.values(content)[0]], author);
if (crossPosts) {
const crossPostKey = content[keys[0]].cross_post_key;
content[keys[0]] = preppedContent[keys[0]];
content[keys[0]] = augmentContentWithCrossPost(
content[keys[0]],
crossPosts[crossPostKey]
);
}
}
return { content };
}
async function loadPosts(sort, tag, observer) {
const account = tag && tag[0] == '@' ? tag.slice(1) : null;
let posts;
if (account) {
const params = { sort, account, observer };
posts = await callBridge('get_account_posts', params);
} else {
const params = { sort, tag, observer };
posts = await callBridge('get_ranked_posts', params);
}
const { content, keys, crossPosts } = await fetchCrossPosts(
posts,
observer
);
if (Object.keys(crossPosts).length > 0) {
for (let ki = 0; ki < keys.length; ki += 1) {
const contentKey = keys[ki];
const post = content[contentKey];
let post = content[contentKey];
if (post.hasOwnProperty('cross_post_key')) {
post.body = crossPosts[post.cross_post_key].body;
post.cross_post_category =
crossPosts[post.cross_post_key].category;
post = augmentContentWithCrossPost(
post,
crossPosts[post.cross_post_key]
);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment