From 6bb7529ffd5c0e6dd548d8f8a86f6147b9090b17 Mon Sep 17 00:00:00 2001 From: Mustafa Buyukcelebi Date: Mon, 9 Dec 2019 17:36:07 +0300 Subject: [PATCH] Reverted comment render system --- src/components/comment/view/commentView.js | 5 +- .../container/commentsDisplayContainer.js | 25 --- src/components/commentsDisplay/index.js | 5 +- .../view/commentsDisplayView.js | 102 ++++----- .../postElements/body/view/commentBodyView.js | 195 ++++++++++++++++++ src/components/postElements/index.js | 3 +- 6 files changed, 244 insertions(+), 91 deletions(-) delete mode 100644 src/components/commentsDisplay/container/commentsDisplayContainer.js create mode 100644 src/components/postElements/body/view/commentBodyView.js diff --git a/src/components/comment/view/commentView.js b/src/components/comment/view/commentView.js index e11d11eb3..64bffe94b 100644 --- a/src/components/comment/view/commentView.js +++ b/src/components/comment/view/commentView.js @@ -8,7 +8,7 @@ import { getTimeFromNow } from '../../../utils/time'; // Constants // Components -import { PostBody, PostHeaderDescription } from '../../postElements'; +import { CommentBody, PostHeaderDescription } from '../../postElements'; import { Upvote } from '../../upvote'; import { IconButton } from '../../iconButton'; import { Comments } from '../../comments'; @@ -63,8 +63,7 @@ const CommentView = ({ isHideImage={isHideImage} /> - props name here description here Value Type Here - * - */ - -class CommentsContainer extends PureComponent { - constructor(props) { - super(props); - this.state = {}; - } - - // Component Life Cycle Functions - // Component Functions - - render() { - return ; - } -} - -export default CommentsContainer; diff --git a/src/components/commentsDisplay/index.js b/src/components/commentsDisplay/index.js index acd9f7c92..12ea174d6 100644 --- a/src/components/commentsDisplay/index.js +++ b/src/components/commentsDisplay/index.js @@ -1,5 +1,4 @@ -import CommentsDisplayView from './view/commentsDisplayView'; -import CommentsDisplay from './container/commentsDisplayContainer'; +import CommentsDisplay from './view/commentsDisplayView'; -export { CommentsDisplayView, CommentsDisplay }; +export { CommentsDisplay }; export default CommentsDisplay; diff --git a/src/components/commentsDisplay/view/commentsDisplayView.js b/src/components/commentsDisplay/view/commentsDisplayView.js index 9370cfb29..f92bf1c58 100644 --- a/src/components/commentsDisplay/view/commentsDisplayView.js +++ b/src/components/commentsDisplay/view/commentsDisplayView.js @@ -1,4 +1,4 @@ -import React, { PureComponent, Fragment } from 'react'; +import React, { useState, Fragment } from 'react'; import { View } from 'react-native'; import { injectIntl } from 'react-intl'; @@ -10,67 +10,51 @@ import COMMENT_FILTER, { VALUE } from '../../../constants/options/comment'; // Styles import styles from './commentDisplayStyles'; -class CommentsDisplayView extends PureComponent { - /* Props - * ------------------------------------------------ - * @prop { type } name - Description.... - */ +const CommentsDisplayView = ({ + author, + commentCount, + fetchPost, + intl, + permlink, + mainAuthor, + handleOnVotersPress, +}) => { + const [selectedFilter, setSelectedFilter] = useState(null); + const [selectedOptionIndex, setSelectedOptionIndex] = useState(0); - constructor(props) { - super(props); - this.state = { - selectedFilter: null, - selectedOptionIndex: 0, - }; - } - - // Component Life Cycles - - // Component Functions - _handleOnDropdownSelect = (option, index) => { - this.setState({ selectedFilter: option, selectedOptionIndex: index }); + const _handleOnDropdownSelect = (option, index) => { + setSelectedFilter(option); + setSelectedOptionIndex(index); }; - render() { - const { - author, - commentCount, - fetchPost, - intl, - permlink, - mainAuthor, - handleOnVotersPress, - } = this.props; - const { selectedFilter, selectedOptionIndex } = this.state; - return ( - - {commentCount > 0 && ( - - intl.formatMessage({ id: `comment_filter.${val}` }))} - defaultText={intl.formatMessage({ id: `comment_filter.${VALUE[0]}` })} - onDropdownSelect={selectedIndex => - this._handleOnDropdownSelect(COMMENT_FILTER[selectedIndex], selectedIndex) - } - selectedOptionIndex={selectedOptionIndex} + return ( + + {commentCount > 0 && ( + + intl.formatMessage({ id: `comment_filter.${val}` }))} + defaultText={intl.formatMessage({ id: `comment_filter.${VALUE[0]}` })} + onDropdownSelect={selectedIndex => + _handleOnDropdownSelect(COMMENT_FILTER[selectedIndex], selectedIndex) + } + selectedOptionIndex={selectedOptionIndex} + /> + + - - - - - )} - - ); - } -} + + + )} + + ); +}; export default injectIntl(CommentsDisplayView); diff --git a/src/components/postElements/body/view/commentBodyView.js b/src/components/postElements/body/view/commentBodyView.js new file mode 100644 index 000000000..6d30b0ba9 --- /dev/null +++ b/src/components/postElements/body/view/commentBodyView.js @@ -0,0 +1,195 @@ +import React, { Fragment } from 'react'; +import { Dimensions, Linking, Alert, TouchableOpacity, Text } from 'react-native'; +import { withNavigation } from 'react-navigation'; +import { useIntl, injectIntl } from 'react-intl'; +import HTML from 'react-native-render-html'; +import { getParentsTagsRecursively } from 'react-native-render-html/src/HTMLUtils'; + +// Constants +import { default as ROUTES } from '../../../../constants/routeNames'; + +// Styles +import styles from './postBodyStyles'; + +const WIDTH = Dimensions.get('window').width; + +const CommentBody = ({ + navigation, + body, + textSelectable = true, + handleOnUserPress, + handleOnPostPress, +}) => { + const intl = useIntl(); + + const _handleOnLinkPress = (href, hrefAtr) => { + if (hrefAtr.class === 'markdown-author-link') { + if (!handleOnUserPress) { + _handleOnUserPress(hrefAtr['data-author']); + } else { + handleOnUserPress(hrefAtr['data-author']); + } + } else if (hrefAtr.class === 'markdown-post-link') { + if (!handleOnPostPress) { + _handleOnPostPress(hrefAtr['data-permlink'], hrefAtr['data-author']); + } else { + handleOnPostPress(hrefAtr['data-permlink']); + } + } else { + _handleBrowserLink(href); + } + }; + + const _handleBrowserLink = async url => { + if (!url) { + return; + } + + Linking.canOpenURL(url).then(supported => { + if (supported) { + Linking.openURL(url); + } else { + Alert.alert(intl.formatMessage({ id: 'alert.failed_to_open' })); + } + }); + }; + + const _handleOnPostPress = (permlink, author) => { + if (permlink) { + navigation.navigate({ + routeName: ROUTES.SCREENS.POST, + params: { + author, + permlink, + }, + key: permlink, + }); + } + }; + + const _handleOnUserPress = username => { + if (username) { + navigation.navigate({ + routeName: ROUTES.SCREENS.PROFILE, + params: { + username, + }, + key: username, + }); + } else { + Alert.alert('Opss!', 'Wrong link.'); + } + }; + + const _hasParentTag = (node, name) => { + if (!node.parent) { + return false; + } + + if (node.name === name) { + return true; + } + + return _hasParentTag(node.parent, name); + }; + + const _alterNode = node => { + if (node.name === 'img') { + node.attribs.style = 'text-align: center;'; + if (_hasParentTag(node, 'td')) { + node.attribs.style = `max-width: ${WIDTH / 2 - 20}px; `; + } + } + + if (node.name === 'div' && node.attribs && node.attribs.class) { + const _className = node.attribs.class; + + if (_className === 'pull-right') { + node.attribs.style = 'text-align: right; align-self: flex-end;'; + } + + if (_className === 'pull-left') { + node.attribs.style = 'text-align: left; align-self: flex-start;'; + } + + if (_className === 'text-justify') { + node.attribs.style = 'text-align: justify; text-justify: inter-word; letter-spacing: 0px;'; + } + + if (_className === 'phishy') { + node.attribs.style = 'color: red'; + } + } + }; + + const _alterData = node => { + if ( + node.type === 'text' && + node.data.includes('markdown-author-link') && + node.parent && + getParentsTagsRecursively(node.parent).includes('code') + ) { + return node.data.replace(/<[^>]*>/g, ''); + } + }; + + const _customRenderer = { + a: (htmlAttribs, children, convertedCSSStyles, passProps) => { + if (passProps.parentWrapper === 'Text') { + return ( + _handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > + {children} + + ); + } + return ( + _handleOnLinkPress(htmlAttribs['data-href'], htmlAttribs)} + > + {children} + + ); + }, + br: (htmlAttribs, children, passProps) => { + return {'\n'}; + }, + }; + + const _initialDimensions = { width: WIDTH - 50, height: 80 }; + + return ( + + _handleOnLinkPress(evt, href, hrefAtr)} + containerStyle={styles.commentContainer} + textSelectable={textSelectable} + tagsStyles={{ img: { height: 120 } }} + ignoredTags={['script']} + debug={false} + staticContentMaxWidth={WIDTH - 33} + imagesInitialDimensions={_initialDimensions} + baseFontStyle={styles.text} + imagesMaxWidth={WIDTH - 50} + alterNode={_alterNode} + alterData={_alterData} + renderers={_customRenderer} + /> + + ); +}; + +const areEqual = (prevProps, nextProps) => { + if (prevProps.body !== nextProps.body) { + return true; + } + return false; +}; + +export default React.memo(injectIntl(withNavigation(CommentBody)), areEqual); diff --git a/src/components/postElements/index.js b/src/components/postElements/index.js index ca31a7834..5c6a9ef53 100644 --- a/src/components/postElements/index.js +++ b/src/components/postElements/index.js @@ -1,5 +1,6 @@ import PostHeaderDescription from './headerDescription/view/postHeaderDescription'; import PostBody from './body/view/postBodyView'; +import CommentBody from './body/view/commentBodyView'; import Tags from './tags/view/tagsView'; -export { PostHeaderDescription, PostBody, Tags }; +export { PostHeaderDescription, PostBody, Tags, CommentBody };