From ac7121c21aac4eb26b8b08ec07ab018d300a1dd4 Mon Sep 17 00:00:00 2001 From: johnnyjoy Date: Fri, 10 Jan 2025 20:24:05 +0800 Subject: [PATCH] chore: update archived page --- web/src/components/MemoActionMenu.tsx | 112 +++++++++++--------- web/src/components/MemoReactionListView.tsx | 4 +- web/src/components/MemoView.tsx | 51 ++------- web/src/components/ReactionView.tsx | 6 +- web/src/pages/Archived.tsx | 61 +---------- 5 files changed, 82 insertions(+), 152 deletions(-) diff --git a/web/src/components/MemoActionMenu.tsx b/web/src/components/MemoActionMenu.tsx index 14d3f7f8..830cb029 100644 --- a/web/src/components/MemoActionMenu.tsx +++ b/web/src/components/MemoActionMenu.tsx @@ -24,17 +24,32 @@ import { useTranslate } from "@/utils/i18n"; interface Props { memo: Memo; + readonly?: boolean; className?: string; - hiddenActions?: ("edit" | "archive" | "delete" | "share" | "pin" | "remove_completed_task_list")[]; 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 = (props: Props) => { - const { memo, hiddenActions } = props; + const { memo, readonly } = props; const t = useTranslate(); const location = useLocation(); const navigateTo = useNavigateTo(); const memoStore = useMemoStore(); + const isArchived = memo.rowStatus === RowStatus.ARCHIVED; + const hasCompletedTaskList = checkHasCompletedTaskList(memo); const isInMemoDetailPage = location.pathname.startsWith(`/m/${memo.uid}`); const handleTogglePinMemoBtnClick = async () => { @@ -69,26 +84,17 @@ const MemoActionMenu = (props: Props) => { }; const handleToggleMemoStatusClick = async () => { + const status = memo.rowStatus === RowStatus.ARCHIVED ? RowStatus.ACTIVE : RowStatus.ARCHIVED; + const message = memo.rowStatus === RowStatus.ARCHIVED ? t("message.restored-successfully") : t("message.archived-successfully"); try { - if (memo.rowStatus === RowStatus.ARCHIVED) { - await memoStore.updateMemo( - { - name: memo.name, - rowStatus: RowStatus.ACTIVE, - }, - ["row_status"], - ); - toast(t("message.restored-successfully")); - } else { - await memoStore.updateMemo( - { - name: memo.name, - rowStatus: RowStatus.ARCHIVED, - }, - ["row_status"], - ); - toast.success(t("message.archived-successfully")); - } + await memoStore.updateMemo( + { + name: memo.name, + rowStatus: status, + }, + ["row_status"], + ); + toast(message); } catch (error: any) { toast.error(error.details); console.error(error); @@ -155,38 +161,44 @@ const MemoActionMenu = (props: Props) => { - {!hiddenActions?.includes("pin") && ( - - {memo.pinned ? : } - {memo.pinned ? t("common.unpin") : t("common.pin")} - + {!readonly && !isArchived && ( + <> + + {memo.pinned ? : } + {memo.pinned ? t("common.unpin") : t("common.pin")} + + + + {t("common.edit")} + + )} - {!hiddenActions?.includes("edit") && props.onEdit && ( - - - {t("common.edit")} - - )} - {!hiddenActions?.includes("share") && ( - - - {t("memo.copy-link")} - - )} - - {memo.rowStatus === RowStatus.ARCHIVED ? : } - {memo.rowStatus === RowStatus.ARCHIVED ? t("common.restore") : t("common.archive")} + + + {t("memo.copy-link")} - {!hiddenActions?.includes("remove_completed_task_list") && ( - - - {t("memo.remove-completed-task-list-items")} - + {!readonly && ( + <> + {!isArchived && hasCompletedTaskList && ( + + + {t("memo.remove-completed-task-list-items")} + + )} + + {memo.rowStatus === RowStatus.ARCHIVED ? ( + + ) : ( + + )} + {memo.rowStatus === RowStatus.ARCHIVED ? t("common.restore") : t("common.archive")} + + + + {t("common.delete")} + + )} - - - {t("common.delete")} - ); diff --git a/web/src/components/MemoReactionListView.tsx b/web/src/components/MemoReactionListView.tsx index 36693700..5553cab6 100644 --- a/web/src/components/MemoReactionListView.tsx +++ b/web/src/components/MemoReactionListView.tsx @@ -2,6 +2,7 @@ import { uniq } from "lodash-es"; import { memo, useEffect, useState } from "react"; import useCurrentUser from "@/hooks/useCurrentUser"; import { useUserStore } from "@/store/v1"; +import { RowStatus } from "@/types/proto/api/v1/common"; import { Memo } from "@/types/proto/api/v1/memo_service"; import { Reaction } from "@/types/proto/api/v1/reaction_service"; import { User } from "@/types/proto/api/v1/user_service"; @@ -18,6 +19,7 @@ const MemoReactionListView = (props: Props) => { const currentUser = useCurrentUser(); const userStore = useUserStore(); const [reactionGroup, setReactionGroup] = useState>(new Map()); + const readonly = memo.rowStatus === RowStatus.ARCHIVED; useEffect(() => { (async () => { @@ -38,7 +40,7 @@ const MemoReactionListView = (props: Props) => { {Array.from(reactionGroup).map(([reactionType, users]) => { return ; })} - {currentUser && } + {!readonly && currentUser && } ) ); diff --git a/web/src/components/MemoView.tsx b/web/src/components/MemoView.tsx index 88d23759..e84d8bbf 100644 --- a/web/src/components/MemoView.tsx +++ b/web/src/components/MemoView.tsx @@ -7,7 +7,7 @@ import useAsyncEffect from "@/hooks/useAsyncEffect"; import useCurrentUser from "@/hooks/useCurrentUser"; import useNavigateTo from "@/hooks/useNavigateTo"; import { useUserStore, useWorkspaceSettingStore, useMemoStore } from "@/store/v1"; -import { NodeType } from "@/types/proto/api/v1/markdown_service"; +import { RowStatus } from "@/types/proto/api/v1/common"; import { MemoRelation_Type } from "@/types/proto/api/v1/memo_relation_service"; import { Memo, Visibility } from "@/types/proto/api/v1/memo_service"; import { WorkspaceMemoRelatedSetting } from "@/types/proto/api/v1/workspace_setting_service"; @@ -29,7 +29,6 @@ import VisibilityIcon from "./VisibilityIcon"; interface Props { memo: Memo; - displayTimeFormat?: "auto" | "time"; compact?: boolean; showCreator?: boolean; showVisibility?: boolean; @@ -59,6 +58,7 @@ const MemoView: React.FC = (props: Props) => { (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo?.name === memo.name, ).length; const relativeTimeFormat = Date.now() - memo.displayTime!.getTime() > 1000 * 60 * 60 * 24 ? "datetime" : "auto"; + const isArchived = memo.rowStatus === RowStatus.ARCHIVED; const readonly = memo.creator !== user?.name && !isSuperUser(user); const isInMemoDetailPage = location.pathname.startsWith(`/m/${memo.uid}`); const parentPage = props.parentPage || location.pathname; @@ -115,42 +115,11 @@ const MemoView: React.FC = (props: Props) => { } }; - const displayTime = - props.displayTimeFormat === "time" ? ( - memo.displayTime?.toLocaleTimeString() - ) : ( - - ); - - const handleHiddenActions = () => { - const hiddenActions: ("edit" | "archive" | "delete" | "share" | "pin" | "remove_completed_task_list")[] = []; - if (!props.showPinned) { - hiddenActions.push("pin"); - } - // check if the content has done tasks - let hasCompletedTaskList = false; - const newNodes = JSON.parse(JSON.stringify(memo.nodes)); - for (let i = 0; i < newNodes.length; i++) { - if (hasCompletedTaskList) { - break; - } - if (newNodes[i].type === NodeType.LIST && newNodes[i].listNode?.children?.length > 0) { - for (let j = 0; j < newNodes[i].listNode.children.length; j++) { - if ( - newNodes[i].listNode.children[j].type === NodeType.TASK_LIST_ITEM && - newNodes[i].listNode.children[j].taskListItemNode?.complete - ) { - hasCompletedTaskList = true; - break; - } - } - } - } - if (!hasCompletedTaskList) { - hiddenActions.push("remove_completed_task_list"); - } - return hiddenActions; - }; + const displayTime = isArchived ? ( + memo.displayTime?.toLocaleString() + ) : ( + + ); return (
= (props: Props) => { )} - {currentUser && } + {currentUser && !isArchived && }
{!isInMemoDetailPage && (workspaceMemoRelatedSetting.enableComment || commentAmount > 0) && ( = (props: Props) => { )} - {!readonly && ( - setShowEditor(true)} /> - )} + setShowEditor(true)} /> { const currentUser = useCurrentUser(); const memoStore = useMemoStore(); const hasReaction = users.some((user) => currentUser && user.username === currentUser.username); + const readonly = memo.rowStatus === RowStatus.ARCHIVED; const handleReactionClick = async () => { - if (!currentUser) { + if (!currentUser || readonly) { return; } @@ -68,7 +70,7 @@ const ReactionView = (props: Props) => { className={clsx( "h-7 border px-2 py-0.5 rounded-full flex flex-row justify-center items-center gap-1 dark:border-zinc-700", "text-sm text-gray-600 dark:text-gray-400", - currentUser && "cursor-pointer", + currentUser && !readonly && "cursor-pointer", hasReaction && "bg-blue-100 border-blue-200 dark:bg-zinc-900", )} onClick={handleReactionClick} diff --git a/web/src/pages/Archived.tsx b/web/src/pages/Archived.tsx index 4424f687..a39a3917 100644 --- a/web/src/pages/Archived.tsx +++ b/web/src/pages/Archived.tsx @@ -1,16 +1,13 @@ -import { Tooltip } from "@mui/joy"; import dayjs from "dayjs"; -import { ArchiveIcon, ArchiveRestoreIcon, TrashIcon } from "lucide-react"; -import { ClientError } from "nice-grpc-web"; +import { ArchiveIcon } from "lucide-react"; import { useMemo } from "react"; -import toast from "react-hot-toast"; -import MemoContent from "@/components/MemoContent"; import MemoFilters from "@/components/MemoFilters"; +import MemoView from "@/components/MemoView"; import MobileHeader from "@/components/MobileHeader"; import PagedMemoList from "@/components/PagedMemoList"; import SearchBar from "@/components/SearchBar"; import useCurrentUser from "@/hooks/useCurrentUser"; -import { useMemoFilterStore, useMemoStore } from "@/store/v1"; +import { useMemoFilterStore } from "@/store/v1"; import { RowStatus } from "@/types/proto/api/v1/common"; import { Memo } from "@/types/proto/api/v1/memo_service"; import { useTranslate } from "@/utils/i18n"; @@ -18,7 +15,6 @@ import { useTranslate } from "@/utils/i18n"; const Archived = () => { const t = useTranslate(); const user = useCurrentUser(); - const memoStore = useMemoStore(); const memoFilterStore = useMemoFilterStore(); const memoListFilter = useMemo(() => { @@ -44,29 +40,6 @@ const Archived = () => { return filters.join(" && "); }, [user, memoFilterStore.filters]); - const handleDeleteMemoClick = async (memo: Memo) => { - const confirmed = window.confirm(t("memo.delete-confirm")); - if (confirmed) { - await memoStore.deleteMemo(memo.name); - } - }; - - const handleRestoreMemoClick = async (memo: Memo) => { - try { - await memoStore.updateMemo( - { - name: memo.name, - rowStatus: RowStatus.ACTIVE, - }, - ["row_status"], - ); - toast(t("message.restored-successfully")); - } catch (error: unknown) { - console.error(error); - toast.error((error as ClientError).details); - } - }; - return (
@@ -83,33 +56,7 @@ const Archived = () => { ( -
-
-
-
- -
-
-
- - - - - - -
-
- -
- )} + renderer={(memo: Memo) => } listSort={(memos: Memo[]) => memos .filter((memo) => memo.rowStatus === RowStatus.ARCHIVED)