Files
AFFiNE-Mirror/libs/components/layout/src/settings-sidebar/Comments/use-comments.ts
T
2022-09-08 19:20:37 +08:00

130 lines
4.3 KiB
TypeScript

import type { Virgo } from '@toeverything/components/editor-core';
import { services } from '@toeverything/datasource/db-service';
import {
useCurrentEditors,
useShowSettingsSidebar,
} from '@toeverything/datasource/state';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { useParams } from 'react-router-dom';
import type { CommentInfo } from './type';
export const useComments = () => {
const { workspaceId, pageId } = useParams();
const [comments, setComments] = useState<CommentInfo[]>([]);
const [observeIds, setObserveIds] = useState<string[]>([]);
const fetchComments = useCallback(async () => {
if (!workspaceId || !pageId) return;
const ids = [];
const pageComment = await services.api.commentService.getPageComments({
workspace: workspaceId,
pageId: pageId,
});
ids.push(pageComment.id);
let comments = await services.api.commentService.getComments({
workspace: workspaceId,
ids: pageComment?.children,
});
comments = await Promise.all(
comments.map(async comment => {
const commentInfo = comment as CommentInfo;
commentInfo.replyList =
await services.api.commentService.getReplyList({
workspace: workspaceId,
ids: comment.children,
});
ids.push(comment.id);
ids.push(...comment.children);
return commentInfo;
})
);
setComments(comments.reverse() as CommentInfo[]);
setObserveIds(ids);
}, [pageId, workspaceId]);
useEffect(() => {
fetchComments();
}, [fetchComments]);
// first simple implementation
useEffect(() => {
const unobserveList: any[] = [];
observeIds.forEach(async id => {
const unobserve = await services.api.editorBlock.observe(
{ workspace: workspaceId, id: id },
block => {
fetchComments();
}
);
unobserveList.push(unobserve);
});
return () => {
unobserveList.forEach(unobserve => unobserve?.());
};
}, [fetchComments, workspaceId, observeIds]);
return { comments };
};
export const useActiveComment = () => {
const { workspaceId, pageId } = useParams();
const { currentEditors } = useCurrentEditors();
const editor = useMemo(() => {
return currentEditors[pageId] as Virgo;
}, [currentEditors, pageId]);
const [activeCommentId, setActiveCommentId] = useState('');
const { setShowSettingsSidebar: setShowInfoSidebar } =
useShowSettingsSidebar();
const resolveComment = useCallback(
(blockId: string, commentId: string) => {
editor?.blockHelper.resolveComment(blockId, commentId);
},
[editor]
);
useEffect(() => {
if (!editor) return;
editor.selection.onSelectEnd(info => {
// TODO: only do the following when sidebar is open
const { type, anchorNode } = info;
if (type === 'None' || !anchorNode) return;
const currentSelectionInTextBlock =
editor.blockHelper.getCurrentSelection(anchorNode.id);
if (!currentSelectionInTextBlock) return;
// get possible commentId from selection
let maybeActiveCommentsIds = [] as string[];
if (editor.blockHelper.isSelectionCollapsed(anchorNode.id)) {
// TODO: search before/after for comment text node, improve this
maybeActiveCommentsIds =
editor.blockHelper.getCommentsIdsBySelection(anchorNode.id);
} else {
maybeActiveCommentsIds =
editor.blockHelper.getCommentsIdsBySelection(anchorNode.id);
}
// TODO: set the shortest comment as active comment instead of the first
setActiveCommentId(
maybeActiveCommentsIds.length ? maybeActiveCommentsIds[0] : ''
);
});
}, [currentEditors, editor]);
useEffect(() => {
if (activeCommentId) {
setShowInfoSidebar(true);
}
}, [activeCommentId, setShowInfoSidebar]);
return { activeCommentId, resolveComment };
};