import React from 'react' import PropTypes from 'prop-types' import { connect } from 'react-redux' import { NavLink } from 'react-router-dom' import { defineMessages, injectIntl, FormattedMessage } from 'react-intl' import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePureComponent from 'react-immutable-pure-component' import { favorite, unfavorite, repost, unrepost, } from '../actions/interactions' import { replyCompose } from '../actions/compose' import { openModal } from '../actions/modal' import { openPopover } from '../actions/popover' import { makeGetStatus } from '../selectors' import { CX, MODAL_BOOST, } from '../constants' import { me, boostModal } from '../initial_state' import Avatar from './avatar' import Button from './button' import CommentHeader from './comment_header' import StatusContent from './status_content' import StatusMedia from './status_media' import { defaultMediaVisibility } from './status' import Text from './text' class Comment extends ImmutablePureComponent { static contextTypes = { router: PropTypes.object, } state = { showMedia: defaultMediaVisibility(this.props.status), statusId: undefined, height: undefined, } handleClick = () => { // } handleOnReply = () => { this.props.onReply(this.props.status, this.context.router) } handleOnFavorite = () => { this.props.onFavorite(this.props.status) } handleOnRepost = () => { this.props.onRepost(this.props.status) } handleOnOpenStatusOptions = () => { this.props.onOpenStatusOptions(this.moreNode, this.props.status) } handleToggleMediaVisibility = () => { this.setState({ showMedia: !this.state.showMedia }) } handleOnThreadMouseEnter = (event) => { if (event.target) { const threadKey = event.target.getAttribute('data-threader-indent') const elems = document.querySelectorAll(`[data-threader-indent="${threadKey}"]`) elems.forEach((elem) => elem.classList.add('thread-hovering')) } } handleOnThreadMouseLeave = (event) => { if (event.target) { const threadKey = event.target.getAttribute('data-threader-indent') const elems = document.querySelectorAll(`[data-threader-indent="${threadKey}"]`) elems.forEach((elem) => elem.classList.remove('thread-hovering')) } } handleOnThreadClick = (event) => { // : todo : } setMoreNode = (c) => { this.moreNode = c } setContainerNode = (c) => { this.containerNode = c if (this.props.isHighlighted && this.containerNode) { this.containerNode.scrollIntoView({ behavior: 'smooth' }); } } render() { const { indent, intl, status, isHidden, isHighlighted, isDetached, ancestorAccountId, } = this.props if (!status) return null if (isHidden) { return (
{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])} {status.get('content')}
) } const style = { paddingLeft: `${indent * 38}px`, } const containerClasses = CX({ d: 1, px15: 1, pt5: !isDetached, pt10: isDetached, pb5: isDetached, borderBottom1PX: isDetached, borderColorSecondary: isDetached, }) const contentClasses = CX({ d: 1, px10: 1, pt5: 1, pb10: 1, radiusSmall: 1, bgSubtle: !isHighlighted, highlightedComment: isHighlighted, }) return (
{ indent > 0 &&
{Array.apply(null, { length: indent }).map((_, i) => ( ))}
}
) } } class CommentButton extends React.PureComponent { render() { const { onClick, title } = this.props return ( ) } } CommentButton.propTypes = { onClick: PropTypes.func.isRequired, title: PropTypes.string.isRequired, } const messages = defineMessages({ reply: { id: 'status.reply', defaultMessage: 'Reply' }, repost: { id: 'status.repost', defaultMessage: 'Repost' }, unrepost: { id: 'status.unrepost', defaultMessage: 'Unrepost' }, like: { id: 'status.like', defaultMessage: 'Like' }, unlike: { id: 'status.unlike', defaultMessage: 'Unlike' }, }) const makeMapStateToProps = (state, props) => ({ status: makeGetStatus()(state, props) }) const mapDispatchToProps = (dispatch) => ({ onReply(status, router) { if (!me) return dispatch(openModal('UNAUTHORIZED')) dispatch((_, getState) => { const state = getState(); if (state.getIn(['compose', 'text']).trim().length !== 0) { dispatch(openModal('CONFIRM', { message: , confirm: , onConfirm: () => dispatch(replyCompose(status, router)), })) } else { dispatch(replyCompose(status, router, true)) } }) }, onFavorite(status) { if (!me) return dispatch(openModal('UNAUTHORIZED')) if (status.get('favourited')) { dispatch(unfavorite(status)) } else { dispatch(favorite(status)) } }, onRepost(status) { if (!me) return dispatch(openModal('UNAUTHORIZED')) const alreadyReposted = status.get('reblogged') if (boostModal && !alreadyReposted) { dispatch(openModal(MODAL_BOOST, { status, onRepost: () => dispatch(repost(status)), })) } else { if (alreadyReposted) { dispatch(unrepost(status)) } else { dispatch(repost(status)) } } }, onOpenStatusOptions(targetRef, status) { dispatch(openPopover('STATUS_OPTIONS', { targetRef, statusId: status.get('id'), position: 'top', })) }, onOpenLikes(status) { dispatch(openModal('STATUS_LIKES', { status })) }, onOpenReposts(status) { dispatch(openModal('STATUS_REPOSTS', { status })) }, onOpenStatusRevisionsPopover(status) { dispatch(openModal('STATUS_REVISIONS', { status, })) }, onOpenMedia (media, index) { dispatch(openModal('MEDIA', { media, index })); }, }) Comment.propTypes = { indent: PropTypes.number, intl: PropTypes.object.isRequired, ancestorAccountId: PropTypes.string.isRequired, status: ImmutablePropTypes.map.isRequired, isHidden: PropTypes.bool, isDetached: PropTypes.bool, isIntersecting: PropTypes.bool, isHighlighted: PropTypes.bool, onReply: PropTypes.func.isRequired, onFavorite: PropTypes.func.isRequired, onRepost: PropTypes.func.isRequired, onOpenStatusOptions: PropTypes.func.isRequired, onOpenLikes: PropTypes.func.isRequired, onOpenReposts: PropTypes.func.isRequired, onOpenStatusRevisionsPopover: PropTypes.func.isRequired, onOpenMedia: PropTypes.func.isRequired } export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Comment))