[mobile] Comments (edit reply)
This commit is contained in:
parent
8410b269c4
commit
e8749b09d6
|
@ -5,7 +5,7 @@ import {Device} from '../../../../../common/mobile/utils/device';
|
||||||
import { withTranslation} from 'react-i18next';
|
import { withTranslation} from 'react-i18next';
|
||||||
import { LocalStorage } from '../../../utils/LocalStorage';
|
import { LocalStorage } from '../../../utils/LocalStorage';
|
||||||
|
|
||||||
import {AddComment, EditComment, AddReply, ViewComments} from '../../view/collaboration/Comments';
|
import {AddComment, EditComment, AddReply, EditReply, ViewComments} from '../../view/collaboration/Comments';
|
||||||
|
|
||||||
// utils
|
// utils
|
||||||
const timeZoneOffsetInMs = (new Date()).getTimezoneOffset() * 60000;
|
const timeZoneOffsetInMs = (new Date()).getTimezoneOffset() * 60000;
|
||||||
|
@ -271,6 +271,7 @@ class EditCommentController extends Component {
|
||||||
super(props);
|
super(props);
|
||||||
this.onEditComment = this.onEditComment.bind(this);
|
this.onEditComment = this.onEditComment.bind(this);
|
||||||
this.onAddReply = this.onAddReply.bind(this);
|
this.onAddReply = this.onAddReply.bind(this);
|
||||||
|
this.onEditReply = this.onEditReply.bind(this);
|
||||||
}
|
}
|
||||||
getUserInfo () {
|
getUserInfo () {
|
||||||
this.currentUser = this.props.users.currentUser;
|
this.currentUser = this.props.users.currentUser;
|
||||||
|
@ -375,6 +376,14 @@ class EditCommentController extends Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onEditReply (comment, reply, textReply) {
|
||||||
|
const currentUser = this.props.users.currentUser;
|
||||||
|
const indReply = reply.ind;
|
||||||
|
comment.replies[indReply].reply = textReply;
|
||||||
|
comment.replies[indReply].userid = currentUser.asc_getIdOriginal();
|
||||||
|
comment.replies[indReply].username = currentUser.asc_getUserName();
|
||||||
|
this.onChangeComment(comment);
|
||||||
|
}
|
||||||
render() {
|
render() {
|
||||||
const storeComments = this.props.storeComments;
|
const storeComments = this.props.storeComments;
|
||||||
const comment = storeComments.currentComment;
|
const comment = storeComments.currentComment;
|
||||||
|
@ -382,6 +391,7 @@ class EditCommentController extends Component {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{storeComments.isOpenEditComment && <EditComment comment={comment} onEditComment={this.onEditComment}/>}
|
{storeComments.isOpenEditComment && <EditComment comment={comment} onEditComment={this.onEditComment}/>}
|
||||||
{storeComments.isOpenAddReply && <AddReply userInfo={this.getUserInfo()} comment={comment} onAddReply={this.onAddReply}/>}
|
{storeComments.isOpenAddReply && <AddReply userInfo={this.getUserInfo()} comment={comment} onAddReply={this.onAddReply}/>}
|
||||||
|
{storeComments.isOpenEditReply && <EditReply comment={comment} reply={storeComments.currentReply} onEditReply={this.onEditReply}/>}
|
||||||
</Fragment>
|
</Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -438,11 +448,13 @@ class ViewCommentsController extends Component {
|
||||||
const api = Common.EditorApi.get();
|
const api = Common.EditorApi.get();
|
||||||
comment && api.asc_removeComment(comment.uid);
|
comment && api.asc_removeComment(comment.uid);
|
||||||
}
|
}
|
||||||
deleteReply (comment, indReply) {
|
deleteReply (comment, reply) {
|
||||||
let replies = null,
|
let replies = null,
|
||||||
addReply = null,
|
addReply = null,
|
||||||
ascComment = (!!Asc.asc_CCommentDataWord ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null));
|
ascComment = (!!Asc.asc_CCommentDataWord ? new Asc.asc_CCommentDataWord(null) : new Asc.asc_CCommentData(null));
|
||||||
|
|
||||||
|
const indReply = reply.ind;
|
||||||
|
|
||||||
if (ascComment && comment) {
|
if (ascComment && comment) {
|
||||||
ascComment.asc_putText(comment.comment);
|
ascComment.asc_putText(comment.comment);
|
||||||
ascComment.asc_putQuoteText(comment.quote);
|
ascComment.asc_putQuoteText(comment.quote);
|
||||||
|
@ -478,7 +490,7 @@ class ViewCommentsController extends Component {
|
||||||
api.asc_changeComment(comment.uid, ascComment);
|
api.asc_changeComment(comment.uid, ascComment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onCommentMenuClick (action, comment) {
|
onCommentMenuClick (action, comment, reply) {
|
||||||
const { t } = this.props;
|
const { t } = this.props;
|
||||||
const _t = t("Common.Collaboration", { returnObjects: true });
|
const _t = t("Common.Collaboration", { returnObjects: true });
|
||||||
switch (action) {
|
switch (action) {
|
||||||
|
@ -498,15 +510,14 @@ class ViewCommentsController extends Component {
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case 'editReply':
|
case 'editReply':
|
||||||
this.setState({showEditReply: true});
|
this.props.storeComments.openEditReply(true, comment, reply);
|
||||||
console.log('editReply');
|
|
||||||
break;
|
break;
|
||||||
case 'deleteReply':
|
case 'deleteReply':
|
||||||
f7.dialog.confirm(
|
f7.dialog.confirm(
|
||||||
_t.textMessageDeleteReply,
|
_t.textMessageDeleteReply,
|
||||||
_t.textDeleteReply,
|
_t.textDeleteReply,
|
||||||
() => {
|
() => {
|
||||||
this.deleteReply(comment, indReply);
|
this.deleteReply(comment, reply);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -121,6 +121,7 @@ export class storeComments {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentReply = null;
|
||||||
@observable isOpenAddReply = false;
|
@observable isOpenAddReply = false;
|
||||||
@action openAddReply (open, comment) {
|
@action openAddReply (open, comment) {
|
||||||
if (open !== this.isOpenAddReply) {
|
if (open !== this.isOpenAddReply) {
|
||||||
|
@ -128,4 +129,13 @@ export class storeComments {
|
||||||
this.isOpenAddReply = open;
|
this.isOpenAddReply = open;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@observable isOpenEditReply = false;
|
||||||
|
@action openEditReply (open, comment, reply) {
|
||||||
|
if (open !== this.isOpenEditReply) {
|
||||||
|
this.currentComment = open ? comment : null;
|
||||||
|
this.currentReply = open ? reply : null;
|
||||||
|
this.isOpenEditReply = open;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -148,6 +148,25 @@ const CommentActions = ({comment, onCommentMenuClick, opened, openActionComment}
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ReplyActions = ({comment, reply, onCommentMenuClick, opened, openActionReply}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Common.Collaboration', {returnObjects: true});
|
||||||
|
return (
|
||||||
|
<Actions id='reply-menu' opened={opened} onActionsClosed={() => openActionReply(false)}>
|
||||||
|
<ActionsGroup>
|
||||||
|
{reply && <Fragment>
|
||||||
|
{reply.editable && <ActionsButton onClick={() => {onCommentMenuClick('editReply', comment, reply);}}>{_t.textEdit}</ActionsButton>}
|
||||||
|
{reply.removable && <ActionsButton color='red' onClick={() => {onCommentMenuClick('deleteReply', comment, reply);}}>{_t.textDeleteReply}</ActionsButton>}
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
</ActionsGroup>
|
||||||
|
<ActionsGroup>
|
||||||
|
<ActionsButton>{_t.textCancel}</ActionsButton>
|
||||||
|
</ActionsGroup>
|
||||||
|
</Actions>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
// Edit comment
|
// Edit comment
|
||||||
const EditCommentPopup = inject("storeComments")(observer(({storeComments, comment, onEditComment}) => {
|
const EditCommentPopup = inject("storeComments")(observer(({storeComments, comment, onEditComment}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -253,7 +272,6 @@ const EditCommentDialog = inject("storeComments")(observer(({storeComments, comm
|
||||||
done.classList.remove('disabled');
|
done.classList.remove('disabled');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
done.classList.add('disabled');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).open();
|
}).open();
|
||||||
|
@ -386,6 +404,127 @@ const AddReply = ({userInfo, comment, onAddReply}) => {
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const EditReplyPopup = inject("storeComments")(observer(({storeComments, comment, reply, onEditReply}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Common.Collaboration', {returnObjects: true});
|
||||||
|
useEffect(() => {
|
||||||
|
f7.popup.open('.edit-reply-popup');
|
||||||
|
});
|
||||||
|
const [stateText, setText] = useState(reply.reply);
|
||||||
|
return (
|
||||||
|
<Popup className="edit-reply-popup">
|
||||||
|
<Navbar>
|
||||||
|
<NavLeft>
|
||||||
|
<Link onClick={() => {
|
||||||
|
f7.popup.close('.edit-reply-popup');
|
||||||
|
storeComments.openEditReply(false);
|
||||||
|
}}>{_t.textCancel}</Link>
|
||||||
|
</NavLeft>
|
||||||
|
<NavTitle>{_t.textEditReply}</NavTitle>
|
||||||
|
<NavRight>
|
||||||
|
<Link className={stateText.length === 0 && 'disabled'}
|
||||||
|
onClick={() => {
|
||||||
|
onEditReply(comment, reply, stateText);
|
||||||
|
f7.popup.close('.edit-reply-popup');
|
||||||
|
storeComments.openEditReply(false);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{Device.android ? <Icon icon='icon-done-comment-white'/> : _t.textDone}
|
||||||
|
</Link>
|
||||||
|
</NavRight>
|
||||||
|
</Navbar>
|
||||||
|
<div className='wrap-comment'>
|
||||||
|
<div className="comment-header">
|
||||||
|
{Device.android &&
|
||||||
|
<div className='initials' style={{backgroundColor: `${reply.userColor}`}}>{reply.userInitials}</div>
|
||||||
|
}
|
||||||
|
<div>
|
||||||
|
<div className='name'>{reply.userName}</div>
|
||||||
|
<div className='reply-date'>{reply.date}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='wrap-textarea'>
|
||||||
|
<Input type='textarea' placeholder={_t.textEditReply} autofocus value={stateText} onChange={(event) => {setText(event.target.value);}}></Input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Popup>
|
||||||
|
)
|
||||||
|
}));
|
||||||
|
|
||||||
|
const EditReplyDialog = inject("storeComments")(observer(({storeComments, comment, reply, onEditReply}) => {
|
||||||
|
const { t } = useTranslation();
|
||||||
|
const _t = t('Common.Collaboration', {returnObjects: true});
|
||||||
|
const templateInitials = `<div class="initials" style="background-color: ${reply.userColor};">${reply.userInitials}</div>`;
|
||||||
|
useEffect(() => {
|
||||||
|
f7.dialog.create({
|
||||||
|
destroyOnClose: true,
|
||||||
|
containerEl: document.getElementById('edit-reply-dialog'),
|
||||||
|
content:
|
||||||
|
`<div class="navbar">
|
||||||
|
<div class="navbar-bg"></div>
|
||||||
|
<div class="navbar-inner sliding">
|
||||||
|
<div class="left">
|
||||||
|
<a href="#" id="reply-cancel">${_t.textCancel}</a>
|
||||||
|
</div>
|
||||||
|
<div class="title">${_t.textEditReply}</div>
|
||||||
|
<div class="right">
|
||||||
|
<a href="#" class="done" id="reply-done">${ Device.android ? '<i class="icon icon-done-comment-white"></i>' : _t.textDone}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='wrap-comment'>
|
||||||
|
<div class="header-comment">
|
||||||
|
${Device.android ? templateInitials : ''}
|
||||||
|
<div>
|
||||||
|
<div class='name'>${reply.userName}</div>
|
||||||
|
<div class='reply-date'>${reply.date}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class='wrap-textarea'>
|
||||||
|
<textarea id='reply-text' placeholder='${_t.textEditComment}' autofocus>${reply.reply}</textarea>
|
||||||
|
</div>
|
||||||
|
</div>`,
|
||||||
|
on: {
|
||||||
|
opened: () => {
|
||||||
|
const cancel = document.getElementById('reply-cancel');
|
||||||
|
cancel.addEventListener('click', () => {
|
||||||
|
f7.dialog.close();
|
||||||
|
storeComments.openEditReply(false);
|
||||||
|
});
|
||||||
|
const done = document.getElementById('reply-done');
|
||||||
|
done.addEventListener('click', () => {
|
||||||
|
const value = document.getElementById('reply-text').value;
|
||||||
|
if (value.length > 0) {
|
||||||
|
onEditReply(comment, reply, value);
|
||||||
|
f7.dialog.close();
|
||||||
|
storeComments.openEditReply(false);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
const area = document.getElementById('reply-text');
|
||||||
|
area.addEventListener('input', (event) => {
|
||||||
|
if (event.target.value.length === 0 && !done.classList.contains('disabled')) {
|
||||||
|
done.classList.add('disabled');
|
||||||
|
} else if (event.target.value.length > 0 && done.classList.contains('disabled')) {
|
||||||
|
done.classList.remove('disabled');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}).open();
|
||||||
|
});
|
||||||
|
return (
|
||||||
|
<div id='edit-reply-dialog'></div>
|
||||||
|
);
|
||||||
|
}));
|
||||||
|
|
||||||
|
const EditReply = ({comment, reply, onEditReply}) => {
|
||||||
|
return (
|
||||||
|
Device.phone ?
|
||||||
|
<EditReplyPopup comment={comment} reply={reply} onEditReply={onEditReply}/> :
|
||||||
|
<EditReplyDialog comment={comment} reply={reply} onEditReply={onEditReply}/>
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
// View comments
|
// View comments
|
||||||
const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onResolveComment}) => {
|
const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onResolveComment}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
@ -405,9 +544,12 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [clickComment, setClickComment] = useState();
|
const [clickComment, setComment] = useState();
|
||||||
const [commentActionsOpened, openActionComment] = useState(false);
|
const [commentActionsOpened, openActionComment] = useState(false);
|
||||||
|
|
||||||
|
const [reply, setReply] = useState();
|
||||||
|
const [replyActionsOpened, openActionReply] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Page>
|
<Page>
|
||||||
<Navbar title={_t.textComments} backLink={_t.textBack}/>
|
<Navbar title={_t.textComments} backLink={_t.textBack}/>
|
||||||
|
@ -429,7 +571,7 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes
|
||||||
<div className='right'>
|
<div className='right'>
|
||||||
<div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'} /></div>
|
<div className='comment-resolve' onClick={() => {onResolveComment(comment);}}><Icon icon={comment.resolved ? 'icon-resolve-comment check' : 'icon-resolve-comment'} /></div>
|
||||||
<div className='comment-menu'
|
<div className='comment-menu'
|
||||||
onClick={() => {setClickComment(comment); openActionComment(true);}}
|
onClick={() => {setComment(comment); openActionComment(true);}}
|
||||||
><Icon icon='icon-menu-comment'/></div>
|
><Icon icon='icon-menu-comment'/></div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
@ -457,7 +599,11 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes
|
||||||
</div>
|
</div>
|
||||||
{!viewMode &&
|
{!viewMode &&
|
||||||
<div className='right'>
|
<div className='right'>
|
||||||
<div className='reply-menu'><Icon icon='icon-menu-comment'/></div>
|
<div className='reply-menu'
|
||||||
|
onClick={() => {setComment(comment); setReply(reply); openActionReply(true);}}
|
||||||
|
>
|
||||||
|
<Icon icon='icon-menu-comment'/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -480,6 +626,7 @@ const ViewComments = ({storeComments, storeAppOptions, onCommentMenuClick, onRes
|
||||||
}
|
}
|
||||||
|
|
||||||
<CommentActions comment={clickComment} onCommentMenuClick={onCommentMenuClick} opened={commentActionsOpened} openActionComment={openActionComment}/>
|
<CommentActions comment={clickComment} onCommentMenuClick={onCommentMenuClick} opened={commentActionsOpened} openActionComment={openActionComment}/>
|
||||||
|
<ReplyActions comment={clickComment} reply={reply} onCommentMenuClick={onCommentMenuClick} opened={replyActionsOpened} openActionReply={openActionReply}/>
|
||||||
</Page>
|
</Page>
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
@ -490,5 +637,6 @@ export {
|
||||||
AddComment,
|
AddComment,
|
||||||
EditComment,
|
EditComment,
|
||||||
AddReply,
|
AddReply,
|
||||||
|
EditReply,
|
||||||
_ViewComments as ViewComments
|
_ViewComments as ViewComments
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,14 +17,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#add-comment-dialog, #edit-comment-dialog, #add-reply-dialog {
|
#add-comment-dialog, #edit-comment-dialog, #add-reply-dialog, #edit-reply-dialog {
|
||||||
.dialog {
|
.dialog {
|
||||||
--f7-dialog-width: 400px;
|
--f7-dialog-width: 400px;
|
||||||
.dialog-inner {
|
.dialog-inner {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
height: 400px;
|
height: 400px;
|
||||||
.wrap-comment {
|
.wrap-comment {
|
||||||
.name, .comment-date {
|
.name, .comment-date, .reply-date {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
.wrap-textarea {
|
.wrap-textarea {
|
||||||
|
@ -101,6 +101,6 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.edit-comment-popup, .add-reply-popup {
|
.edit-comment-popup, .add-reply-popup, .edit-reply-popup {
|
||||||
z-index: 20000;
|
z-index: 20000;
|
||||||
}
|
}
|
|
@ -125,7 +125,8 @@
|
||||||
"textMessageDeleteComment": "Do you really want to delete this comment?",
|
"textMessageDeleteComment": "Do you really want to delete this comment?",
|
||||||
"textMessageDeleteReply": "Do you really want to delete this reply?",
|
"textMessageDeleteReply": "Do you really want to delete this reply?",
|
||||||
"textDeleteReply": "Delete Reply",
|
"textDeleteReply": "Delete Reply",
|
||||||
"textEditComment": "Edit Comment"
|
"textEditComment": "Edit Comment",
|
||||||
|
"textEditReply": "Edit Reply"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Settings": {
|
"Settings": {
|
||||||
|
|
Loading…
Reference in a new issue