// - Import react components import React, { Component } from 'react' import { findDOMNode } from 'react-dom' import { connect } from 'react-redux' import { NavLink } from 'react-router-dom' import PropTypes from 'prop-types' import moment from 'moment/moment' import Linkify from 'react-linkify' import Popover from '@material-ui/core/Popover' import { getTranslate, getActiveLanguage } from 'react-localize-redux' import {Map} from 'immutable' import { Comment } from 'core/domain/comments' // - Import material UI libraries import Divider from '@material-ui/core/Divider' import Paper from '@material-ui/core/Paper' import Button from '@material-ui/core/Button' import { grey } from '@material-ui/core/colors' import IconButton from '@material-ui/core/IconButton' import MoreVertIcon from '@material-ui/icons/MoreVert' import ListItemText from '@material-ui/core/ListItemText' import ListItemSecondaryAction from '@material-ui/core/ListItemSecondaryAction' import ListItem from '@material-ui/core/ListItem' import List from '@material-ui/core/List' import ListItemIcon from '@material-ui/core/ListItemIcon' import MenuList from '@material-ui/core/MenuList' import MenuItem from '@material-ui/core/MenuItem' import TextField from '@material-ui/core/TextField' import { withStyles } from '@material-ui/core/styles' import { Manager, Target, Popper } from 'react-popper' import { Card, CardActions, CardHeader, CardMedia, CardContent } from '@material-ui/core' import Grow from '@material-ui/core/Grow' import ClickAwayListener from '@material-ui/core/ClickAwayListener' import classNames from 'classnames' // - Import app components import UserAvatar from 'components/userAvatar' // - Import API // - Import actions import * as commentActions from 'store/actions/commentActions' import * as userActions from 'store/actions/userActions' import { ICommentComponentProps } from './ICommentComponentProps' import { ICommentComponentState } from './ICommentComponentState' const styles = (theme: any) => ({ textField: { fontWeight: 400, fontSize: '14px' }, header: { padding: '2px 3px 3px 10px' }, popperOpen: { zIndex: 11 }, popperClose: { pointerEvents: 'none', zIndex: 0 }, iconButton: { top: 0, display: 'flex', right: 4, flexDirection: 'row-reverse', position: 'absolute' }, commentBody: { color: 'black', fontWeight: 400, fontSize: '12px', height: '100%', border: 'none', width: '100%', outline: 'none', resize: 'none' }, rightIconMenuItem: { fontSize: 12, fontWeight: 300, paddingLeft: 6, paddingRight: 6, paddingTop: 0, paddingBottom: 0 }, moreIcon: { width: '0.6em', height: '0.6em' } }) /** * Create component class */ export class CommentComponent extends Component { static propTypes = { /** * Comment object */ comment: PropTypes.object, /** * If it's true the post owner is the logged in user which this post be long to the comment */ isPostOwner: PropTypes.bool, /** * If it's true the comment is disable to write */ disableComments: PropTypes.bool } /** * Fields */ buttonMenu = null /** * DOM styles * * * @memberof CommentComponent */ styles = { author: { fontSize: '10px', paddingRight: '10px', fontWeight: 400, color: 'rgba(0,0,0,0.87)', textOverflow: 'ellipsis', overflow: 'hidden' }, textarea: { fontWeight: 400, fontSize: '14px', border: 'none', width: '100%', outline: 'none', resize: 'none' }, cancel: { float: 'right', clear: 'both', zIndex: 5, margin: '0px 5px 5px 0px', fontWeight: 400 } } /** * Fields * * @type {*} * @memberof CommentComponent */ textareaRef: any divCommentRef: any inputText: any divComment: any /** * Component constructor * @param {object} props is an object properties of component */ constructor (props: ICommentComponentProps) { super(props) this.textareaRef = (i: any) => { this.inputText = i } this.divCommentRef = (i: any) => { this.divComment = i } // Defaul state this.state = { /** * Comment text */ text: this.props.comment.text!, /** * Comment text to match edit with new comment that is edited */ initialText: this.props.comment.text!, /** * If comment text dosn't take any change it will be true */ editDisabled: true, /** * If it's true the post owner is the logged in user which this post be long to the comment */ isPostOwner: false, /** * The anchor of comment menu element */ openMenu: false, /** * Anchor element */ anchorEl: null } // Binding functions to `this` this.handleDelete = this.handleDelete.bind(this) this.handleUpdateComment = this.handleUpdateComment.bind(this) this.handleOnChange = this.handleOnChange.bind(this) this.handleCancelEdit = this.handleCancelEdit.bind(this) this.handleEditComment = this.handleEditComment.bind(this) } /** * Handle show edit comment * @param {event} evt is an event passed by clicking on edit button */ handleEditComment = (evt: any) => { this.setState({openMenu: false}) this.props.openEditor!() } /** * Handle cancel edit * @param {event} evt is an event passed by clicking on cancel button */ handleCancelEdit = (evt: any) => { this.setState({ text: this.state.initialText! }) this.props.closeEditor!() } /** * Handle edit comment * @param {event} evt is an event passed by clicking on post button */ handleUpdateComment = (evt: any) => { const { comment } = this.props comment.text = this.state.text this.props.update!(comment) this.setState({ initialText: this.state.text }) } /** * When comment text changed * @param {event} evt is an event passed by change comment text callback funciton * @param {string} data is the comment text which user writes */ handleOnChange = (evt: any) => { const data = evt.target.value if (data.length === 0 || data.trim() === '' || data.trim() === this.state.initialText) { this.setState({ text: data, editDisabled: true }) } else { this.setState({ text: data, editDisabled: false }) } } /** * Delete a comment * @param {event} evt an event passed by click on delete comment * @param {string} id comment identifire * @param {string} postId post identifier which comment belong to */ handleDelete = (evt: any, id?: string | null, postId?: string) => { this.props.delete!(id, postId) } /** * Handle comment menu */ handleCommentMenu = (event: any) => { this.setState({ openMenu: true, anchorEl: findDOMNode(this.buttonMenu!), }) } /** * Handle close request for comment menu */ handleCloseCommentMenu = () => { this.setState({ openMenu: false }) } componentWillMount () { const { commentOwner } = this.props if (!this.props.isCommentOwner && !commentOwner) { this.props.getUserInfo!() } } /** * Reneder component DOM * @return {react element} return the DOM which rendered by component */ render () { /** * Comment object from props */ const { comment, classes, fullName, avatar, translate , editorStatus} = this.props const { openMenu, anchorEl } = this.state const rightIconMenu = ( <> { this.buttonMenu = node }} aria-owns={openMenu! ? 'comment-menu' : ''} aria-haspopup='true' onClick={this.handleCommentMenu} > {/* */} {translate!('comment.replyButton')} {this.props.isCommentOwner ? ({translate!('comment.editButton')}) : ''} {(this.props.isCommentOwner || this.props.isPostOwner) ? ( this.handleDelete(evt, comment.id, comment.postId)}>{translate!('comment.deleteButton')}) : ''} ) const Author = () => (
{comment.userDisplayName}{moment.unix(comment.creationDate!).fromNow()}
) const { userId } = comment const commentBody = (
{ editorStatus ? :
{this.state.text}
}
) return (
} subheader={commentBody} avatar={} action={(!this.props.isCommentOwner && !this.props.isPostOwner && this.props.disableComments) || editorStatus ? '' : rightIconMenu} >
) } } /** * Map dispatch to props * @param {func} dispatch is the function to dispatch action to reducers * @param {object} ownProps is the props belong to component * @return {object} props of component */ const mapDispatchToProps = (dispatch: any, ownProps: ICommentComponentProps) => { return { delete: (id: string | null, postId: string) => dispatch(commentActions.dbDeleteComment(id, postId)), update: (comment: Comment) => { dispatch(commentActions.dbUpdateComment(comment)) }, openEditor: () => dispatch(commentActions.openCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })), closeEditor: () => dispatch(commentActions.closeCommentEditor({ id: ownProps.comment.id, postId: ownProps.comment.postId })), getUserInfo: () => dispatch(userActions.dbGetUserInfoByUserId(ownProps.comment.userId!, '')) } } /** * Map state to props * @param {object} state is the obeject from redux store * @param {object} ownProps is the props belong to component * @return {object} props of component */ const mapStateToProps = (state: any, ownProps: ICommentComponentProps) => { const commentOwnerId = ownProps.comment.userId const uid = state.getIn(['authorize', 'uid']) const avatar = ownProps.comment.userAvatar const fullName = ownProps.comment.userDisplayName return { translate: getTranslate(state.get('locale')), uid: uid, isCommentOwner: (uid === commentOwnerId), commentOwner: state.getIn(['user', 'info', commentOwnerId]), avatar, fullName } } // - Connect component to redux store export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles as any)(CommentComponent as any) as any)