import { Tooltip } from "@mui/joy"; import classNames from "classnames"; import { memo, useCallback, useEffect, useRef, useState } from "react"; import { useTranslation } from "react-i18next"; import { Link } from "react-router-dom"; import { getRelativeTimeString, getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import useNavigateTo from "@/hooks/useNavigateTo"; import { useUserStore, extractUsernameFromName } from "@/store/v1"; import { MemoRelation_Type } from "@/types/proto/api/v2/memo_relation_service"; import { Memo, Visibility } from "@/types/proto/api/v2/memo_service"; import { useTranslate } from "@/utils/i18n"; import { convertVisibilityToString } from "@/utils/memo"; import showChangeMemoCreatedTsDialog from "./ChangeMemoCreatedTsDialog"; import Icon from "./Icon"; import MemoActionMenu from "./MemoActionMenu"; import MemoContent from "./MemoContent"; import MemoReactionistView from "./MemoReactionListView"; import MemoRelationListView from "./MemoRelationListView"; import MemoResourceListView from "./MemoResourceListView"; import showPreviewImageDialog from "./PreviewImageDialog"; import ReactionSelector from "./ReactionSelector"; import UserAvatar from "./UserAvatar"; import VisibilityIcon from "./VisibilityIcon"; interface Props { memo: Memo; showCreator?: boolean; showVisibility?: boolean; showPinned?: boolean; className?: string; } const MemoView: React.FC = (props: Props) => { const { memo, className } = props; const t = useTranslate(); const navigateTo = useNavigateTo(); const { i18n } = useTranslation(); const currentUser = useCurrentUser(); const userStore = useUserStore(); const user = useCurrentUser(); const [displayTime, setDisplayTime] = useState(getRelativeTimeString(getTimeStampByDate(memo.displayTime))); const [creator, setCreator] = useState(userStore.getUserByUsername(extractUsernameFromName(memo.creator))); const memoContainerRef = useRef(null); const referencedMemos = memo.relations.filter((relation) => relation.type === MemoRelation_Type.REFERENCE); const commentAmount = memo.relations.filter((relation) => relation.type === MemoRelation_Type.COMMENT).length; const readonly = memo.creator !== user?.name; // Initial related data: creator. useEffect(() => { (async () => { const user = await userStore.getOrFetchUserByUsername(extractUsernameFromName(memo.creator)); setCreator(user); })(); }, []); // Update display time string. useEffect(() => { let intervalFlag: any = -1; if (Date.now() - getTimeStampByDate(memo.displayTime) < 1000 * 60 * 60 * 24) { intervalFlag = setInterval(() => { setDisplayTime(getRelativeTimeString(getTimeStampByDate(memo.displayTime))); }, 1000 * 1); } return () => { clearInterval(intervalFlag); }; }, [i18n.language]); const handleGotoMemoDetailPage = (event: React.MouseEvent) => { if (event.altKey) { showChangeMemoCreatedTsDialog(memo.id); } else { navigateTo(`/m/${memo.name}`); } }; const handleMemoContentClick = useCallback(async (e: React.MouseEvent) => { const targetEl = e.target as HTMLElement; if (targetEl.tagName === "IMG") { const imgUrl = targetEl.getAttribute("src"); if (imgUrl) { showPreviewImageDialog([imgUrl], 0); } } }, []); return (
{props.showCreator && creator && ( <> {creator.nickname || creator.username} )} {displayTime} {props.showPinned && memo.pinned && ( <> )}
{props.showVisibility && memo.visibility !== Visibility.PRIVATE && ( )} {currentUser && }
{commentAmount > 0 && {commentAmount}} {!readonly && }
); }; export default memo(MemoView);