import { useEffect, useRef } from "react"; import { toast } from "react-hot-toast"; import { useParams } from "react-router-dom"; import MemoFilter from "@/components/MemoFilter"; import { DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import { TAG_REG } from "@/labs/marked/parser"; import { useFilterStore, useMemoStore } from "@/store/module"; import { extractUsernameFromName } from "@/store/v1"; import { useTranslate } from "@/utils/i18n"; import Empty from "./Empty"; import Memo from "./Memo"; const MemoList: React.FC = () => { const t = useTranslate(); const params = useParams(); const memoStore = useMemoStore(); const filterStore = useFilterStore(); const filter = filterStore.state; const { loadingStatus, memos } = memoStore.state; const user = useCurrentUser(); const { tag: tagQuery, duration, text: textQuery, visibility } = filter; const showMemoFilter = Boolean(tagQuery || (duration && duration.from < duration.to) || textQuery || visibility); const username = params.username || extractUsernameFromName(user.name); const fetchMoreRef = useRef(null); const shownMemos = ( showMemoFilter ? memos.filter((memo) => { let shouldShow = true; if (tagQuery) { const tagsSet = new Set(); for (const t of Array.from(memo.content.match(new RegExp(TAG_REG, "gu")) ?? [])) { const tag = t.replace(TAG_REG, "$1").trim(); const items = tag.split("/"); let temp = ""; for (const i of items) { temp += i; tagsSet.add(temp); temp += "/"; } } if (!tagsSet.has(tagQuery)) { shouldShow = false; } } if ( duration && duration.from < duration.to && (getTimeStampByDate(memo.displayTs) < duration.from || getTimeStampByDate(memo.displayTs) > duration.to) ) { shouldShow = false; } if (textQuery && !memo.content.toLowerCase().includes(textQuery.toLowerCase())) { shouldShow = false; } if (visibility) { shouldShow = memo.visibility === visibility; } return shouldShow; }) : memos ).filter((memo) => memo.creatorUsername === username && memo.rowStatus === "NORMAL" && !memo.parent); const pinnedMemos = shownMemos.filter((m) => m.pinned); const unpinnedMemos = shownMemos.filter((m) => !m.pinned); const memoSort = (mi: Memo, mj: Memo) => { return mj.displayTs - mi.displayTs; }; pinnedMemos.sort(memoSort); unpinnedMemos.sort(memoSort); const sortedMemos = pinnedMemos.concat(unpinnedMemos).filter((m) => m.rowStatus === "NORMAL"); useEffect(() => { const root = document.body.querySelector("#root"); if (root) { root.scrollTo(0, 0); } }, [filter]); useEffect(() => { if (!fetchMoreRef.current) return; const observer = new IntersectionObserver(([entry]) => { if (!entry.isIntersecting) return; observer.disconnect(); handleFetchMoreClick(); }); observer.observe(fetchMoreRef.current); return () => observer.disconnect(); }, [loadingStatus]); const handleFetchMoreClick = async () => { try { await memoStore.fetchMemos(username, DEFAULT_MEMO_LIMIT, memos.length); } catch (error: any) { toast.error(error.response.data.message); } }; return (
{sortedMemos.map((memo) => ( ))} {loadingStatus === "fetching" ? (

{t("memo.fetching-data")}

) : (
{loadingStatus === "complete" ? ( sortedMemos.length === 0 && (

{t("message.no-data")}

) ) : ( {t("memo.fetch-more")} )}
)}
); }; export default MemoList;