From a69e405c95baec93721450648fa8b2025849472e Mon Sep 17 00:00:00 2001 From: Steven Date: Tue, 3 Mar 2026 22:30:25 +0800 Subject: [PATCH] refactor: remove dead code and deduplicate comment amount logic --- web/src/components/MemoView/MemoView.tsx | 20 +++++++---------- .../components/MemoView/MemoViewContext.tsx | 8 +++---- .../components/MemoCommentListView.tsx | 18 ++++++++++----- .../MemoView/hooks/useImagePreview.ts | 2 -- .../MemoView/hooks/useMemoActions.ts | 22 ++----------------- web/src/pages/MemoDetail.tsx | 21 ++++++++++-------- 6 files changed, 39 insertions(+), 52 deletions(-) diff --git a/web/src/components/MemoView/MemoView.tsx b/web/src/components/MemoView/MemoView.tsx index 5986d3206..8752fcef1 100644 --- a/web/src/components/MemoView/MemoView.tsx +++ b/web/src/components/MemoView/MemoView.tsx @@ -4,18 +4,17 @@ import useCurrentUser from "@/hooks/useCurrentUser"; import { useUser } from "@/hooks/useUserQueries"; import { cn } from "@/lib/utils"; import { State } from "@/types/proto/api/v1/common_pb"; -import { MemoRelation_Type } from "@/types/proto/api/v1/memo_service_pb"; import { isSuperUser } from "@/utils/user"; import MemoEditor from "../MemoEditor"; import PreviewImageDialog from "../PreviewImageDialog"; import { MemoBody, MemoCommentListView, MemoHeader } from "./components"; import { MEMO_CARD_BASE_CLASSES } from "./constants"; import { useImagePreview, useMemoActions, useMemoHandlers } from "./hooks"; -import { MemoViewContext } from "./MemoViewContext"; +import { computeCommentAmount, MemoViewContext } from "./MemoViewContext"; import type { MemoViewProps } from "./types"; const MemoView: React.FC = (props: MemoViewProps) => { - const { memo: memoData, className, parentPage: parentPageProp } = props; + const { memo: memoData, className, parentPage: parentPageProp, compact, showCreator, showVisibility, showPinned } = props; const cardRef = useRef(null); const [showEditor, setShowEditor] = useState(false); @@ -31,7 +30,7 @@ const MemoView: React.FC = (props: MemoViewProps) => { const toggleNsfwVisibility = () => setShowNSFWContent((prev) => !prev); const { previewState, openPreview, setPreviewOpen } = useImagePreview(); - const { unpinMemo } = useMemoActions(memoData, isArchived); + const { unpinMemo } = useMemoActions(memoData); const closeEditor = () => setShowEditor(false); const openEditor = () => setShowEditor(true); @@ -46,10 +45,7 @@ const MemoView: React.FC = (props: MemoViewProps) => { const location = useLocation(); const isInMemoDetailPage = location.pathname.startsWith(`/${memoData.name}`); - const commentAmount = memoData.relations.filter( - (r) => r.type === MemoRelation_Type.COMMENT && r.relatedMemo?.name === memoData.name, - ).length; - const showCommentPreview = !isInMemoDetailPage && commentAmount > 0; + const showCommentPreview = !isInMemoDetailPage && computeCommentAmount(memoData) > 0; const contextValue = useMemo( () => ({ @@ -85,16 +81,16 @@ const MemoView: React.FC = (props: MemoViewProps) => { tabIndex={readonly ? -1 : 0} > { return context; }; +export const computeCommentAmount = (memo: Memo): number => + memo.relations.filter((r) => r.type === MemoRelation_Type.COMMENT && r.relatedMemo?.name === memo.name).length; + export const useMemoViewDerived = () => { const { memo, isArchived, readonly } = useMemoViewContext(); const location = useLocation(); const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`); - - const commentAmount = memo.relations.filter( - (relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo?.name === memo.name, - ).length; + const commentAmount = computeCommentAmount(memo); const displayTime = memo.displayTime ? timestampDate(memo.displayTime) : undefined; const relativeTimeFormat: "datetime" | "auto" = diff --git a/web/src/components/MemoView/components/MemoCommentListView.tsx b/web/src/components/MemoView/components/MemoCommentListView.tsx index e62714f01..16fc13e65 100644 --- a/web/src/components/MemoView/components/MemoCommentListView.tsx +++ b/web/src/components/MemoView/components/MemoCommentListView.tsx @@ -1,5 +1,6 @@ import { ArrowUpRightIcon } from "lucide-react"; import { Link } from "react-router-dom"; +import { extractMemoIdFromName } from "@/helpers/resource-names"; import { useMemoComments } from "@/hooks/useMemoQueries"; import { useMemoViewContext, useMemoViewDerived } from "../MemoViewContext"; @@ -28,11 +29,18 @@ const MemoCommentListView: React.FC = () => { - {displayedComments.map((comment) => ( -
- {comment.content} -
- ))} + {displayedComments.map((comment) => { + const uid = extractMemoIdFromName(comment.name); + return ( + + {comment.content} + + ); + })} ); }; diff --git a/web/src/components/MemoView/hooks/useImagePreview.ts b/web/src/components/MemoView/hooks/useImagePreview.ts index d5fb46207..51755d003 100644 --- a/web/src/components/MemoView/hooks/useImagePreview.ts +++ b/web/src/components/MemoView/hooks/useImagePreview.ts @@ -9,7 +9,6 @@ export interface ImagePreviewState { export interface UseImagePreviewReturn { previewState: ImagePreviewState; openPreview: (url: string) => void; - closePreview: () => void; setPreviewOpen: (open: boolean) => void; } @@ -19,7 +18,6 @@ export const useImagePreview = (): UseImagePreviewReturn => { return { previewState, openPreview: (url: string) => setPreviewState({ open: true, urls: [url], index: 0 }), - closePreview: () => setPreviewState({ open: false, urls: [], index: 0 }), setPreviewOpen: (open: boolean) => setPreviewState((prev) => ({ ...prev, open })), }; }; diff --git a/web/src/components/MemoView/hooks/useMemoActions.ts b/web/src/components/MemoView/hooks/useMemoActions.ts index c2fb94a53..3fee74d93 100644 --- a/web/src/components/MemoView/hooks/useMemoActions.ts +++ b/web/src/components/MemoView/hooks/useMemoActions.ts @@ -1,31 +1,13 @@ -import toast from "react-hot-toast"; import { useUpdateMemo } from "@/hooks/useMemoQueries"; -import { handleError } from "@/lib/error"; -import { State } from "@/types/proto/api/v1/common_pb"; import type { Memo } from "@/types/proto/api/v1/memo_service_pb"; -import { useTranslate } from "@/utils/i18n"; -export const useMemoActions = (memo: Memo, isArchived: boolean) => { - const t = useTranslate(); +export const useMemoActions = (memo: Memo) => { const { mutateAsync: updateMemo } = useUpdateMemo(); - const archiveMemo = async () => { - if (isArchived) return; - try { - await updateMemo({ update: { name: memo.name, state: State.ARCHIVED }, updateMask: ["state"] }); - toast.success(t("message.archived-successfully")); - } catch (error: unknown) { - handleError(error, toast.error, { - context: "Archive memo", - fallbackMessage: "Failed to archive memo", - }); - } - }; - const unpinMemo = async () => { if (!memo.pinned) return; await updateMemo({ update: { name: memo.name, pinned: false }, updateMask: ["pinned"] }); }; - return { archiveMemo, unpinMemo }; + return { unpinMemo }; }; diff --git a/web/src/pages/MemoDetail.tsx b/web/src/pages/MemoDetail.tsx index d51d56e0c..ade5394a3 100644 --- a/web/src/pages/MemoDetail.tsx +++ b/web/src/pages/MemoDetail.tsx @@ -1,6 +1,6 @@ import { ConnectError } from "@connectrpc/connect"; import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react"; -import { useState } from "react"; +import { useEffect, useState } from "react"; import { toast } from "react-hot-toast"; import { Link, useLocation, useParams } from "react-router-dom"; import { MemoDetailSidebar, MemoDetailSidebarDrawer } from "@/components/MemoDetailSidebar"; @@ -8,7 +8,7 @@ import MemoEditor from "@/components/MemoEditor"; import MemoView from "@/components/MemoView"; import MobileHeader from "@/components/MobileHeader"; import { Button } from "@/components/ui/button"; -import { memoNamePrefix } from "@/helpers/resource-names"; +import { extractMemoIdFromName, memoNamePrefix } from "@/helpers/resource-names"; import useCurrentUser from "@/hooks/useCurrentUser"; import useMediaQuery from "@/hooks/useMediaQuery"; import { useMemo, useMemoComments } from "@/hooks/useMemoQueries"; @@ -47,6 +47,13 @@ const MemoDetail = () => { }); const comments = commentsResponse?.memos || []; + const { hash } = useLocation(); + useEffect(() => { + if (!hash || comments.length === 0) return; + const el = document.getElementById(hash.slice(1)); + el?.scrollIntoView({ behavior: "smooth", block: "center" }); + }, [hash, comments]); + const showCreateCommentButton = currentUser && !showCommentEditor; if (isLoading || !memo) { @@ -135,13 +142,9 @@ const MemoDetail = () => { )} {comments.map((comment) => ( - +
+ +
))}