import { Button, IconButton } from "@mui/joy"; import clsx from "clsx"; import { useEffect, useRef, useState } from "react"; import ActivityCalendar from "@/components/ActivityCalendar"; import Empty from "@/components/Empty"; import Icon from "@/components/Icon"; import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog"; import MemoFilter from "@/components/MemoFilter"; import MemoView from "@/components/MemoView"; import MobileHeader from "@/components/MobileHeader"; import { TimelineSidebar, TimelineSidebarDrawer } from "@/components/TimelineSidebar"; import { memoServiceClient } from "@/grpcweb"; import { DAILY_TIMESTAMP, DEFAULT_LIST_MEMOS_PAGE_SIZE } from "@/helpers/consts"; import { getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import useFilterWithUrlParams from "@/hooks/useFilterWithUrlParams"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import i18n from "@/i18n"; import { useMemoList, useMemoStore } from "@/store/v1"; import { useTranslate } from "@/utils/i18n"; const Timeline = () => { const t = useTranslate(); const { md } = useResponsiveWidth(); const user = useCurrentUser(); const memoStore = useMemoStore(); const memoList = useMemoList(); const { tag: tagQuery, text: textQuery } = useFilterWithUrlParams(); const [activityStats, setActivityStats] = useState>({}); const [selectedDateString, setSelectedDateString] = useState(new Date().toDateString()); const [isRequesting, setIsRequesting] = useState(true); const nextPageTokenRef = useRef(undefined); const sortedMemos = memoList.value.sort((a, b) => getTimeStampByDate(a.displayTime) - getTimeStampByDate(b.displayTime)); const monthString = new Date(selectedDateString).getFullYear() + "-" + (new Date(selectedDateString).getMonth() + 1); useEffect(() => { setIsRequesting(true); nextPageTokenRef.current = undefined; setTimeout(async () => { memoList.reset(); const nextPageToken = await fetchMemos(); nextPageTokenRef.current = nextPageToken; setIsRequesting(false); }); }, [selectedDateString, tagQuery, textQuery]); useEffect(() => { (async () => { const filters = [`row_status == "NORMAL"`]; const contentSearch: string[] = []; if (textQuery) { contentSearch.push(JSON.stringify(textQuery)); } if (contentSearch.length > 0) { filters.push(`content_search == [${contentSearch.join(", ")}]`); } if (tagQuery) { filters.push(`tag == "${tagQuery}"`); } const { stats } = await memoServiceClient.getUserMemosStats({ name: user.name, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, filter: filters.join(" && "), }); setActivityStats( Object.fromEntries( Object.entries(stats).filter(([date]) => { const d = new Date(date); return `${d.getFullYear()}-${d.getMonth() + 1}` === monthString; }), ), ); })(); }, [sortedMemos.length]); const fetchMemos = async () => { const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`]; const contentSearch: string[] = []; if (textQuery) { contentSearch.push(JSON.stringify(textQuery)); } if (contentSearch.length > 0) { filters.push(`content_search == [${contentSearch.join(", ")}]`); } if (tagQuery) { filters.push(`tag == "${tagQuery}"`); } if (selectedDateString) { const selectedDateStamp = getTimeStampByDate(selectedDateString); filters.push( ...[`display_time_after == ${selectedDateStamp / 1000}`, `display_time_before == ${(selectedDateStamp + DAILY_TIMESTAMP) / 1000}`], ); } const { nextPageToken } = await memoStore.fetchMemos({ pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE, filter: filters.join(" && "), pageToken: nextPageTokenRef.current, }); return nextPageToken; }; const handleNewMemo = () => { showMemoEditorDialog({}); }; return (
{!md && ( )}
setSelectedDateString(new Date().toDateString())} > {t("timeline.title")}
handleNewMemo()}>
{new Date(selectedDateString).toLocaleDateString(i18n.language, { month: "short", day: "numeric" })} {new Date(monthString).getFullYear()}
setSelectedDateString(date)} />
{sortedMemos.map((memo, index) => (
{index !== sortedMemos.length - 1 && (
)}
))}
{isRequesting ? (

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

) : !nextPageTokenRef.current ? ( sortedMemos.length === 0 && (

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

) ) : (
)}
{md && (
)}
); }; export default Timeline;