import copy from "copy-to-clipboard"; import { ArchiveIcon, ArchiveRestoreIcon, BookmarkMinusIcon, BookmarkPlusIcon, CopyIcon, Edit3Icon, FileTextIcon, LinkIcon, MoreVerticalIcon, TrashIcon, SquareCheckIcon, } from "lucide-react"; import { observer } from "mobx-react-lite"; import { useState } from "react"; import toast from "react-hot-toast"; import { useLocation } from "react-router-dom"; import ConfirmDialog from "@/components/ConfirmDialog"; import useNavigateTo from "@/hooks/useNavigateTo"; import { memoStore, userStore } from "@/store"; import { workspaceStore } from "@/store"; import { State } from "@/types/proto/api/v1/common"; import { Memo } from "@/types/proto/api/v1/memo_service"; import { useTranslate } from "@/utils/i18n"; import { hasCompletedTasks, removeCompletedTasks } from "@/utils/markdown-manipulation"; import { Button } from "./ui/button"; import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger, } from "./ui/dropdown-menu"; interface Props { memo: Memo; readonly?: boolean; className?: string; onEdit?: () => void; } const checkHasCompletedTaskList = (memo: Memo) => { return hasCompletedTasks(memo.content); }; const MemoActionMenu = observer((props: Props) => { const { memo, readonly } = props; const t = useTranslate(); const location = useLocation(); const navigateTo = useNavigateTo(); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [removeTasksDialogOpen, setRemoveTasksDialogOpen] = useState(false); 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.success(message); } catch (error: any) { toast.error(error.details); console.error(error); return; } if (isInMemoDetailPage) { navigateTo(memo.state === State.ARCHIVED ? "/" : "/archived"); } memoUpdatedCallback(); }; const handleCopyLink = () => { let host = workspaceStore.state.profile.instanceUrl; if (host === "") { host = window.location.origin; } copy(`${host}/${memo.name}`); toast.success(t("message.succeed-copy-link")); }; const handleCopyContent = () => { copy(memo.content); toast.success(t("message.succeed-copy-content")); }; const handleDeleteMemoClick = () => { setDeleteDialogOpen(true); }; const confirmDeleteMemo = async () => { await memoStore.deleteMemo(memo.name); toast.success(t("message.deleted-successfully")); if (isInMemoDetailPage) { navigateTo("/"); } memoUpdatedCallback(); }; const handleRemoveCompletedTaskListItemsClick = () => { setRemoveTasksDialogOpen(true); }; const confirmRemoveCompletedTaskListItems = async () => { const newContent = removeCompletedTasks(memo.content); await memoStore.updateMemo( { name: memo.name, content: newContent, }, ["content"], ); toast.success(t("message.remove-completed-task-list-items-successfully")); memoUpdatedCallback(); }; return ( {!readonly && !isArchived && ( <> {!isComment && ( {memo.pinned ? : } {memo.pinned ? t("common.unpin") : t("common.pin")} )} {t("common.edit")} )} {!isArchived && ( {t("common.copy")} {t("memo.copy-link")} {t("memo.copy-content")} )} {!readonly && ( <> {!isArchived && !isComment && hasCompletedTaskList && ( {t("memo.remove-completed-task-list-items")} )} {!isComment && ( {isArchived ? : } {isArchived ? t("common.restore") : t("common.archive")} )} {t("common.delete")} )} {/* Delete confirmation dialog */} {/* Remove completed tasks confirmation */} ); }); export default MemoActionMenu;