Commit a69e405c authored by Steven's avatar Steven

refactor: remove dead code and deduplicate comment amount logic

parent 3a5d3c8f
...@@ -4,18 +4,17 @@ import useCurrentUser from "@/hooks/useCurrentUser"; ...@@ -4,18 +4,17 @@ import useCurrentUser from "@/hooks/useCurrentUser";
import { useUser } from "@/hooks/useUserQueries"; import { useUser } from "@/hooks/useUserQueries";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
import { State } from "@/types/proto/api/v1/common_pb"; 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 { isSuperUser } from "@/utils/user";
import MemoEditor from "../MemoEditor"; import MemoEditor from "../MemoEditor";
import PreviewImageDialog from "../PreviewImageDialog"; import PreviewImageDialog from "../PreviewImageDialog";
import { MemoBody, MemoCommentListView, MemoHeader } from "./components"; import { MemoBody, MemoCommentListView, MemoHeader } from "./components";
import { MEMO_CARD_BASE_CLASSES } from "./constants"; import { MEMO_CARD_BASE_CLASSES } from "./constants";
import { useImagePreview, useMemoActions, useMemoHandlers } from "./hooks"; import { useImagePreview, useMemoActions, useMemoHandlers } from "./hooks";
import { MemoViewContext } from "./MemoViewContext"; import { computeCommentAmount, MemoViewContext } from "./MemoViewContext";
import type { MemoViewProps } from "./types"; import type { MemoViewProps } from "./types";
const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => { const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
const { memo: memoData, className, parentPage: parentPageProp } = props; const { memo: memoData, className, parentPage: parentPageProp, compact, showCreator, showVisibility, showPinned } = props;
const cardRef = useRef<HTMLDivElement>(null); const cardRef = useRef<HTMLDivElement>(null);
const [showEditor, setShowEditor] = useState(false); const [showEditor, setShowEditor] = useState(false);
...@@ -31,7 +30,7 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => { ...@@ -31,7 +30,7 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
const toggleNsfwVisibility = () => setShowNSFWContent((prev) => !prev); const toggleNsfwVisibility = () => setShowNSFWContent((prev) => !prev);
const { previewState, openPreview, setPreviewOpen } = useImagePreview(); const { previewState, openPreview, setPreviewOpen } = useImagePreview();
const { unpinMemo } = useMemoActions(memoData, isArchived); const { unpinMemo } = useMemoActions(memoData);
const closeEditor = () => setShowEditor(false); const closeEditor = () => setShowEditor(false);
const openEditor = () => setShowEditor(true); const openEditor = () => setShowEditor(true);
...@@ -46,10 +45,7 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => { ...@@ -46,10 +45,7 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
const location = useLocation(); const location = useLocation();
const isInMemoDetailPage = location.pathname.startsWith(`/${memoData.name}`); const isInMemoDetailPage = location.pathname.startsWith(`/${memoData.name}`);
const commentAmount = memoData.relations.filter( const showCommentPreview = !isInMemoDetailPage && computeCommentAmount(memoData) > 0;
(r) => r.type === MemoRelation_Type.COMMENT && r.relatedMemo?.name === memoData.name,
).length;
const showCommentPreview = !isInMemoDetailPage && commentAmount > 0;
const contextValue = useMemo( const contextValue = useMemo(
() => ({ () => ({
...@@ -85,16 +81,16 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => { ...@@ -85,16 +81,16 @@ const MemoView: React.FC<MemoViewProps> = (props: MemoViewProps) => {
tabIndex={readonly ? -1 : 0} tabIndex={readonly ? -1 : 0}
> >
<MemoHeader <MemoHeader
showCreator={props.showCreator} showCreator={showCreator}
showVisibility={props.showVisibility} showVisibility={showVisibility}
showPinned={props.showPinned} showPinned={showPinned}
onEdit={openEditor} onEdit={openEditor}
onGotoDetail={handleGotoMemoDetailPage} onGotoDetail={handleGotoMemoDetailPage}
onUnpin={unpinMemo} onUnpin={unpinMemo}
/> />
<MemoBody <MemoBody
compact={props.compact} compact={compact}
onContentClick={handleMemoContentClick} onContentClick={handleMemoContentClick}
onContentDoubleClick={handleMemoContentDoubleClick} onContentDoubleClick={handleMemoContentDoubleClick}
onToggleNsfwVisibility={toggleNsfwVisibility} onToggleNsfwVisibility={toggleNsfwVisibility}
......
...@@ -27,15 +27,15 @@ export const useMemoViewContext = (): MemoViewContextValue => { ...@@ -27,15 +27,15 @@ export const useMemoViewContext = (): MemoViewContextValue => {
return context; 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 = () => { export const useMemoViewDerived = () => {
const { memo, isArchived, readonly } = useMemoViewContext(); const { memo, isArchived, readonly } = useMemoViewContext();
const location = useLocation(); const location = useLocation();
const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`); const isInMemoDetailPage = location.pathname.startsWith(`/${memo.name}`);
const commentAmount = computeCommentAmount(memo);
const commentAmount = memo.relations.filter(
(relation) => relation.type === MemoRelation_Type.COMMENT && relation.relatedMemo?.name === memo.name,
).length;
const displayTime = memo.displayTime ? timestampDate(memo.displayTime) : undefined; const displayTime = memo.displayTime ? timestampDate(memo.displayTime) : undefined;
const relativeTimeFormat: "datetime" | "auto" = const relativeTimeFormat: "datetime" | "auto" =
......
import { ArrowUpRightIcon } from "lucide-react"; import { ArrowUpRightIcon } from "lucide-react";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { extractMemoIdFromName } from "@/helpers/resource-names";
import { useMemoComments } from "@/hooks/useMemoQueries"; import { useMemoComments } from "@/hooks/useMemoQueries";
import { useMemoViewContext, useMemoViewDerived } from "../MemoViewContext"; import { useMemoViewContext, useMemoViewDerived } from "../MemoViewContext";
...@@ -28,11 +29,18 @@ const MemoCommentListView: React.FC = () => { ...@@ -28,11 +29,18 @@ const MemoCommentListView: React.FC = () => {
<ArrowUpRightIcon className="w-3 h-3" /> <ArrowUpRightIcon className="w-3 h-3" />
</Link> </Link>
</div> </div>
{displayedComments.map((comment) => ( {displayedComments.map((comment) => {
<div key={comment.name} className="bg-muted/60 rounded-md px-2 py-1 text-xs text-muted-foreground truncate leading-relaxed"> const uid = extractMemoIdFromName(comment.name);
{comment.content} return (
</div> <Link
))} key={comment.name}
to={`/${memo.name}#${uid}`}
className="bg-muted/60 rounded-md px-2 py-1 text-xs text-muted-foreground truncate leading-relaxed hover:bg-muted transition-colors block"
>
{comment.content}
</Link>
);
})}
</div> </div>
); );
}; };
......
...@@ -9,7 +9,6 @@ export interface ImagePreviewState { ...@@ -9,7 +9,6 @@ export interface ImagePreviewState {
export interface UseImagePreviewReturn { export interface UseImagePreviewReturn {
previewState: ImagePreviewState; previewState: ImagePreviewState;
openPreview: (url: string) => void; openPreview: (url: string) => void;
closePreview: () => void;
setPreviewOpen: (open: boolean) => void; setPreviewOpen: (open: boolean) => void;
} }
...@@ -19,7 +18,6 @@ export const useImagePreview = (): UseImagePreviewReturn => { ...@@ -19,7 +18,6 @@ export const useImagePreview = (): UseImagePreviewReturn => {
return { return {
previewState, previewState,
openPreview: (url: string) => setPreviewState({ open: true, urls: [url], index: 0 }), openPreview: (url: string) => setPreviewState({ open: true, urls: [url], index: 0 }),
closePreview: () => setPreviewState({ open: false, urls: [], index: 0 }),
setPreviewOpen: (open: boolean) => setPreviewState((prev) => ({ ...prev, open })), setPreviewOpen: (open: boolean) => setPreviewState((prev) => ({ ...prev, open })),
}; };
}; };
import toast from "react-hot-toast";
import { useUpdateMemo } from "@/hooks/useMemoQueries"; 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 type { Memo } from "@/types/proto/api/v1/memo_service_pb";
import { useTranslate } from "@/utils/i18n";
export const useMemoActions = (memo: Memo, isArchived: boolean) => { export const useMemoActions = (memo: Memo) => {
const t = useTranslate();
const { mutateAsync: updateMemo } = useUpdateMemo(); 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 () => { const unpinMemo = async () => {
if (!memo.pinned) return; if (!memo.pinned) return;
await updateMemo({ update: { name: memo.name, pinned: false }, updateMask: ["pinned"] }); await updateMemo({ update: { name: memo.name, pinned: false }, updateMask: ["pinned"] });
}; };
return { archiveMemo, unpinMemo }; return { unpinMemo };
}; };
import { ConnectError } from "@connectrpc/connect"; import { ConnectError } from "@connectrpc/connect";
import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react"; import { ArrowUpLeftFromCircleIcon, MessageCircleIcon } from "lucide-react";
import { useState } from "react"; import { useEffect, useState } from "react";
import { toast } from "react-hot-toast"; import { toast } from "react-hot-toast";
import { Link, useLocation, useParams } from "react-router-dom"; import { Link, useLocation, useParams } from "react-router-dom";
import { MemoDetailSidebar, MemoDetailSidebarDrawer } from "@/components/MemoDetailSidebar"; import { MemoDetailSidebar, MemoDetailSidebarDrawer } from "@/components/MemoDetailSidebar";
...@@ -8,7 +8,7 @@ import MemoEditor from "@/components/MemoEditor"; ...@@ -8,7 +8,7 @@ import MemoEditor from "@/components/MemoEditor";
import MemoView from "@/components/MemoView"; import MemoView from "@/components/MemoView";
import MobileHeader from "@/components/MobileHeader"; import MobileHeader from "@/components/MobileHeader";
import { Button } from "@/components/ui/button"; 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 useCurrentUser from "@/hooks/useCurrentUser";
import useMediaQuery from "@/hooks/useMediaQuery"; import useMediaQuery from "@/hooks/useMediaQuery";
import { useMemo, useMemoComments } from "@/hooks/useMemoQueries"; import { useMemo, useMemoComments } from "@/hooks/useMemoQueries";
...@@ -47,6 +47,13 @@ const MemoDetail = () => { ...@@ -47,6 +47,13 @@ const MemoDetail = () => {
}); });
const comments = commentsResponse?.memos || []; 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; const showCreateCommentButton = currentUser && !showCommentEditor;
if (isLoading || !memo) { if (isLoading || !memo) {
...@@ -135,13 +142,9 @@ const MemoDetail = () => { ...@@ -135,13 +142,9 @@ const MemoDetail = () => {
</div> </div>
)} )}
{comments.map((comment) => ( {comments.map((comment) => (
<MemoView <div key={`${comment.name}-${comment.displayTime}`} id={extractMemoIdFromName(comment.name)}>
key={`${comment.name}-${comment.displayTime}`} <MemoView memo={comment} parentPage={locationState?.from} showCreator compact />
memo={comment} </div>
parentPage={locationState?.from}
showCreator
compact
/>
))} ))}
</div> </div>
</div> </div>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment