import copy from "copy-to-clipboard"; import { ArchiveIcon, ArchiveRestoreIcon, BookmarkMinusIcon, BookmarkPlusIcon, CopyIcon, Edit3Icon, MoreVerticalIcon, TrashIcon, SquareCheckIcon, } from "lucide-react"; import { observer } from "mobx-react-lite"; import toast from "react-hot-toast"; import { useLocation } from "react-router-dom"; import { markdownServiceClient } from "@/grpcweb"; import useNavigateTo from "@/hooks/useNavigateTo"; import { memoStore, userStore } from "@/store/v2"; import { State } from "@/types/proto/api/v1/common"; import { NodeType } from "@/types/proto/api/v1/markdown_service"; import { Memo } from "@/types/proto/api/v1/memo_service"; import { cn } from "@/utils"; import { useTranslate } from "@/utils/i18n"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/Popover"; interface Props { memo: Memo; readonly?: boolean; className?: string; onEdit?: () => void; } const checkHasCompletedTaskList = (memo: Memo) => { for (const node of memo.nodes) { if (node.type === NodeType.LIST && node.listNode?.children && node.listNode?.children?.length > 0) { for (let j = 0; j < node.listNode.children.length; j++) { if (node.listNode.children[j].type === NodeType.TASK_LIST_ITEM && node.listNode.children[j].taskListItemNode?.complete) { return true; } } } } return false; }; const MemoActionMenu = observer((props: Props) => { const { memo, readonly } = props; const t = useTranslate(); const location = useLocation(); const navigateTo = useNavigateTo(); const hasCompletedTaskList = checkHasCompletedTaskList(memo); const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`); const isComment = Boolean(memo.parent); const isArchived = memo.state === State.ARCHIVED; const memoUpdatedCallback = () => { // Refresh user stats. userStore.setStatsStateId(); }; const handleTogglePinMemoBtnClick = async () => { try { if (memo.pinned) { await memoStore.updateMemo( { name: memo.name, pinned: false, }, ["pinned"], ); } else { await memoStore.updateMemo( { name: memo.name, pinned: true, }, ["pinned"], ); } } catch { // do nth } }; const handleEditMemoClick = () => { if (props.onEdit) { props.onEdit(); return; } }; const handleToggleMemoStatusClick = async () => { const state = memo.state === State.ARCHIVED ? State.NORMAL : State.ARCHIVED; const message = memo.state === State.ARCHIVED ? t("message.restored-successfully") : t("message.archived-successfully"); try { await memoStore.updateMemo( { name: memo.name, state, }, ["state"], ); toast(message); } catch (error: any) { toast.error(error.details); console.error(error); return; } if (isInMemoDetailPage) { navigateTo(memo.state === State.ARCHIVED ? "/" : "/archived"); } memoUpdatedCallback(); }; const handleCopyLink = () => { copy(`${window.location.origin}/${memo.name}`); toast.success(t("message.succeed-copy-link")); }; const handleDeleteMemoClick = async () => { const confirmed = window.confirm(t("memo.delete-confirm")); if (confirmed) { await memoStore.deleteMemo(memo.name); toast.success(t("message.deleted-successfully")); if (isInMemoDetailPage) { navigateTo("/"); } memoUpdatedCallback(); } }; const handleRemoveCompletedTaskListItemsClick = async () => { const confirmed = window.confirm(t("memo.remove-completed-task-list-items-confirm")); if (confirmed) { const newNodes = JSON.parse(JSON.stringify(memo.nodes)); for (const node of newNodes) { if (node.type === NodeType.LIST && node.listNode?.children?.length > 0) { const children = node.listNode.children; for (let i = 0; i < children.length; i++) { if (children[i].type === NodeType.TASK_LIST_ITEM && children[i].taskListItemNode?.complete) { // Remove completed taskList item and next line breaks children.splice(i, 1); if (children[i]?.type === NodeType.LINE_BREAK) { children.splice(i, 1); } i--; } } } } const { markdown } = await markdownServiceClient.restoreMarkdownNodes({ nodes: newNodes }); await memoStore.updateMemo( { name: memo.name, content: markdown, }, ["content"], ); toast.success(t("message.remove-completed-task-list-items-successfully")); memoUpdatedCallback(); } }; return (
{!readonly && !isArchived && ( <> {!isComment && ( )} )} {!isArchived && ( )} {!readonly && ( <> {!isArchived && !isComment && hasCompletedTaskList && ( )} {!isComment && ( )} )}
); }); export default MemoActionMenu;