1
0
mirror of https://github.com/haiwen/seahub.git synced 2025-08-10 19:32:25 +00:00
seahub/frontend/src/components/file-view/comment-widget/reply-item.js
Michael An 7ff4b52005
basic file support comment (#7731)
* basic file support comment

* 01 add init loading icon

* delete useless comment

* 02 delete comment tip

* update api validation

* 03 update API params

* 04 delete useless api

* 05 remove read all notification

* 06 change comment and reply permission

* 07 change docUuid to fileUuid

---------

Co-authored-by: r350178982 <32759763+r350178982@users.noreply.github.com>
2025-04-21 21:33:13 +08:00

176 lines
5.4 KiB
JavaScript

import React from 'react';
import PropTypes from 'prop-types';
import { processor } from '@seafile/seafile-editor';
import { Button, Dropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap';
import { gettext } from '../../../utils/constants';
import CommentDeletePopover from './comment-delete-popover';
const { username } = window.app.pageOptions;
const commentItemPropTypes = {
time: PropTypes.string,
item: PropTypes.object,
deleteReply: PropTypes.func,
showResolvedComment: PropTypes.bool,
editComment: PropTypes.func,
};
class ReplyItem extends React.Component {
constructor(props) {
super(props);
this.state = {
dropdownOpen: false,
html: '',
newReply: this.props.item.reply,
editable: false,
isShowDeletePopover: false,
};
}
componentWillMount() {
this.convertComment(this.props.item.reply);
}
componentWillReceiveProps(nextProps) {
this.convertComment(nextProps.item.reply);
}
toggleDropDownMenu = () => {
this.setState({
dropdownOpen: !this.state.dropdownOpen,
});
};
convertComment = (mdFile) => {
processor.process(mdFile).then((result) => {
let html = String(result);
this.setState({ html: html });
});
};
toggleEditComment = () => {
this.setState({
editable: !this.state.editable
});
};
updateComment = () => {
const newReply = this.state.newReply.trim();
if (this.props.item.reply !== newReply) {
this.props.updateReply(newReply);
}
this.toggleEditComment();
};
handleCommentChange = (event) => {
this.setState({
newReply: event.target.value,
});
};
onCommentContentClick = (e) => {
// click participant link, page shouldn't jump
if (e.target.nodeName !== 'A') return;
const preNode = e.target.previousSibling;
if (preNode && preNode.nodeType === 3 && preNode.nodeValue.slice(-1) === '@') {
e.preventDefault();
}
};
toggleShowDeletePopover = () => {
this.setState({
isShowDeletePopover: !this.state.isShowDeletePopover
});
};
render() {
const item = this.props.item;
const replyOpToolsId = `commentOpTools_${item?.id}`;
if (this.state.editable) {
return (
<li className="seafile-comment-item" id={item.id}>
<div className="seafile-comment-info mt-1">
<img className="avatar" src={item.avatar_url} alt=""/>
<div className="comment-author-info">
<div className="comment-author-name ellipsis">{item.user_name}</div>
<div className="comment-author-time">{this.props.time}</div>
</div>
</div>
<div className="seafile-edit-comment">
<textarea className="edit-comment-input" value={this.state.newReply} onChange={this.handleCommentChange} clos="100" rows="3" warp="virtual"></textarea>
<Button className="comment-btn" color="primary" size="sm" onClick={this.updateComment} id={item.id}>{gettext('Update')}</Button>{' '}
<Button className="comment-btn" color="secondary" size="sm" onClick={this.toggleEditComment}>{gettext('Cancel')}</Button>
</div>
</li>
);
}
return (
<li className={'seafile-comment-item'} id={item.id}>
<div className="seafile-comment-info mt-1">
<img className="avatar" src={item.avatar_url} alt=""/>
<div className="comment-author-info">
<div className="comment-author-name ellipsis">{item.user_name}</div>
<div className="comment-author-time">{this.props.time}</div>
</div>
{(item.user_email === username) &&
<Dropdown
isOpen={this.state.dropdownOpen}
size="sm"
className="seafile-comment-dropdown"
toggle={this.toggleDropDownMenu}
id={replyOpToolsId}
>
<DropdownToggle
tag="i"
role="button"
tabIndex="0"
className="seafile-comment-dropdown-btn sf-dropdown-toggle sf3-font-more sf3-font"
title={gettext('More operations')}
aria-label={gettext('More operations')}
data-toggle="dropdown"
aria-expanded={this.state.dropdownOpen}
aria-haspopup={true}
/>
<DropdownMenu>
<DropdownItem
onClick={this.toggleShowDeletePopover}
className="delete-comment"
id={item.id}
>
{gettext('Delete')}
</DropdownItem>
<DropdownItem
onClick={this.toggleEditComment}
className="edit-comment"
id={item.id}
>
{gettext('Edit')}
</DropdownItem>
</DropdownMenu>
</Dropdown>
}
</div>
<div
className="seafile-comment-content"
dangerouslySetInnerHTML={{ __html: this.state.html }}
onClick={e => this.onCommentContentClick(e)}
>
</div>
{this.state.isShowDeletePopover && (
<CommentDeletePopover
type="reply"
deleteConfirm={this.props.deleteReply}
setIsShowDeletePopover={this.toggleShowDeletePopover}
targetId={replyOpToolsId}
/>
)}
</li>
);
}
}
ReplyItem.propTypes = commentItemPropTypes;
export default ReplyItem;