memos/web/src/components/MemoActionMenu/MemoActionMenu.tsx

163 lines
5.4 KiB
TypeScript

import {
ArchiveIcon,
ArchiveRestoreIcon,
BookmarkMinusIcon,
BookmarkPlusIcon,
CopyIcon,
Edit3Icon,
FileTextIcon,
LinkIcon,
MoreVerticalIcon,
SquareCheckIcon,
TrashIcon,
} from "lucide-react";
import { observer } from "mobx-react-lite";
import { useState } from "react";
import ConfirmDialog from "@/components/ConfirmDialog";
import { Button } from "@/components/ui/button";
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSub,
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { State } from "@/types/proto/api/v1/common_pb";
import { useTranslate } from "@/utils/i18n";
import { hasCompletedTasks } from "@/utils/markdown-manipulation";
import { useMemoActionHandlers } from "./hooks";
import type { MemoActionMenuProps } from "./types";
const MemoActionMenu = observer((props: MemoActionMenuProps) => {
const { memo, readonly } = props;
const t = useTranslate();
// Dialog state
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
const [removeTasksDialogOpen, setRemoveTasksDialogOpen] = useState(false);
// Derived state
const hasCompletedTaskList = hasCompletedTasks(memo.content);
const isComment = Boolean(memo.parent);
const isArchived = memo.state === State.ARCHIVED;
// Action handlers
const {
handleTogglePinMemoBtnClick,
handleEditMemoClick,
handleToggleMemoStatusClick,
handleCopyLink,
handleCopyContent,
handleDeleteMemoClick,
confirmDeleteMemo,
handleRemoveCompletedTaskListItemsClick,
confirmRemoveCompletedTaskListItems,
} = useMemoActionHandlers({
memo,
onEdit: props.onEdit,
setDeleteDialogOpen,
setRemoveTasksDialogOpen,
});
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="icon" className="size-4">
<MoreVerticalIcon className="text-muted-foreground" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" sideOffset={2}>
{/* Edit actions (non-readonly, non-archived) */}
{!readonly && !isArchived && (
<>
{!isComment && (
<DropdownMenuItem onClick={handleTogglePinMemoBtnClick}>
{memo.pinned ? <BookmarkMinusIcon className="w-4 h-auto" /> : <BookmarkPlusIcon className="w-4 h-auto" />}
{memo.pinned ? t("common.unpin") : t("common.pin")}
</DropdownMenuItem>
)}
<DropdownMenuItem onClick={handleEditMemoClick}>
<Edit3Icon className="w-4 h-auto" />
{t("common.edit")}
</DropdownMenuItem>
</>
)}
{/* Copy submenu (non-archived) */}
{!isArchived && (
<DropdownMenuSub>
<DropdownMenuSubTrigger>
<CopyIcon className="w-4 h-auto" />
{t("common.copy")}
</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem onClick={handleCopyLink}>
<LinkIcon className="w-4 h-auto" />
{t("memo.copy-link")}
</DropdownMenuItem>
<DropdownMenuItem onClick={handleCopyContent}>
<FileTextIcon className="w-4 h-auto" />
{t("memo.copy-content")}
</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
)}
{/* Write actions (non-readonly) */}
{!readonly && (
<>
{/* Remove completed tasks (non-archived, non-comment, has completed tasks) */}
{!isArchived && !isComment && hasCompletedTaskList && (
<DropdownMenuItem onClick={handleRemoveCompletedTaskListItemsClick}>
<SquareCheckIcon className="w-4 h-auto" />
{t("memo.remove-completed-task-list-items")}
</DropdownMenuItem>
)}
{/* Archive/Restore (non-comment) */}
{!isComment && (
<DropdownMenuItem onClick={handleToggleMemoStatusClick}>
{isArchived ? <ArchiveRestoreIcon className="w-4 h-auto" /> : <ArchiveIcon className="w-4 h-auto" />}
{isArchived ? t("common.restore") : t("common.archive")}
</DropdownMenuItem>
)}
{/* Delete */}
<DropdownMenuItem onClick={handleDeleteMemoClick}>
<TrashIcon className="w-4 h-auto" />
{t("common.delete")}
</DropdownMenuItem>
</>
)}
</DropdownMenuContent>
{/* Delete confirmation dialog */}
<ConfirmDialog
open={deleteDialogOpen}
onOpenChange={setDeleteDialogOpen}
title={t("memo.delete-confirm")}
confirmLabel={t("common.delete")}
description={t("memo.delete-confirm-description")}
cancelLabel={t("common.cancel")}
onConfirm={confirmDeleteMemo}
confirmVariant="destructive"
/>
{/* Remove completed tasks confirmation */}
<ConfirmDialog
open={removeTasksDialogOpen}
onOpenChange={setRemoveTasksDialogOpen}
title={t("memo.remove-completed-task-list-items-confirm")}
confirmLabel={t("common.confirm")}
cancelLabel={t("common.cancel")}
onConfirm={confirmRemoveCompletedTaskListItems}
confirmVariant="destructive"
/>
</DropdownMenu>
);
});
export default MemoActionMenu;