import { Button, Divider, IconButton } from "@mui/joy"; import classNames from "classnames"; import { sum } from "lodash-es"; import { Fragment, useEffect, 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 { memoServiceClient } from "@/grpcweb"; import { DAILY_TIMESTAMP, DEFAULT_MEMO_LIMIT } from "@/helpers/consts"; import { getNormalizedTimeString, getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; import i18n from "@/i18n"; import { useFilterStore } from "@/store/module"; import { useMemoList, useMemoStore } from "@/store/v1"; import { Memo } from "@/types/proto/api/v2/memo_service"; import { useTranslate } from "@/utils/i18n"; interface GroupedByMonthItem { // Format: 2021-1 month: string; data: Record; memos: Memo[]; } const groupByMonth = (dateCountMap: Record, memos: Memo[]): GroupedByMonthItem[] => { const groupedByMonth: GroupedByMonthItem[] = []; Object.entries(dateCountMap).forEach(([date, count]) => { const month = date.split("-").slice(0, 2).join("-"); const existingMonth = groupedByMonth.find((group) => group.month === month); if (existingMonth) { existingMonth.data[date] = count; } else { const monthMemos = memos.filter((memo) => getNormalizedTimeString(memo.displayTime).startsWith(month)); groupedByMonth.push({ month, data: { [date]: count }, memos: monthMemos }); } }); return groupedByMonth.filter((group) => group.memos.length > 0).sort((a, b) => getTimeStampByDate(b.month) - getTimeStampByDate(a.month)); }; const Timeline = () => { const t = useTranslate(); const { md } = useResponsiveWidth(); const user = useCurrentUser(); const memoStore = useMemoStore(); const memoList = useMemoList(); const filterStore = useFilterStore(); const [activityStats, setActivityStats] = useState>({}); const [selectedDay, setSelectedDay] = useState(); const [isRequesting, setIsRequesting] = useState(true); const [isComplete, setIsComplete] = useState(false); const { tag: tagQuery, text: textQuery } = filterStore.state; const sortedMemos = memoList.value.sort((a, b) => getTimeStampByDate(b.displayTime) - getTimeStampByDate(a.displayTime)); const groupedByMonth = groupByMonth(activityStats, sortedMemos); useEffect(() => { memoList.reset(); fetchMemos(); }, [selectedDay, tagQuery, textQuery]); useEffect(() => { (async () => { const filters = [`row_status == "NORMAL"`]; const contentSearch: string[] = []; if (tagQuery) { contentSearch.push(JSON.stringify(`#${tagQuery}`)); } if (textQuery) { contentSearch.push(JSON.stringify(textQuery)); } if (contentSearch.length > 0) { filters.push(`content_search == [${contentSearch.join(", ")}]`); } const { stats } = await memoServiceClient.getUserMemosStats({ name: user.name, timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, filter: filters.join(" && "), }); setActivityStats(stats); })(); }, [sortedMemos.length]); const fetchMemos = async () => { const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`]; const contentSearch: string[] = []; if (tagQuery) { contentSearch.push(JSON.stringify(`#${tagQuery}`)); } if (textQuery) { contentSearch.push(JSON.stringify(textQuery)); } if (contentSearch.length > 0) { filters.push(`content_search == [${contentSearch.join(", ")}]`); } if (selectedDay) { const selectedDateStamp = getTimeStampByDate(selectedDay) + new Date().getTimezoneOffset() * 60 * 1000; filters.push( ...[`display_time_after == ${selectedDateStamp / 1000}`, `display_time_before == ${(selectedDateStamp + DAILY_TIMESTAMP) / 1000}`] ); } setIsRequesting(true); const data = await memoStore.fetchMemos({ filter: filters.join(" && "), limit: DEFAULT_MEMO_LIMIT, offset: memoList.size(), }); setIsRequesting(false); setIsComplete(data.length < DEFAULT_MEMO_LIMIT); }; const handleNewMemo = () => { showMemoEditorDialog({}); }; return (
setSelectedDay(undefined)} > {t("timeline.title")}
handleNewMemo()}>
{groupedByMonth.map((group, index) => (
{new Date(group.month).toLocaleString(i18n.language, { month: "short" })} {new Date(group.month).getFullYear()} Total: {sum(Object.values(group.data))}
setSelectedDay(date)} />
{group.memos.map((memo, index) => (
{group.memos.length > 1 && (
{index !== group.memos.length - 1 && (
)}
)}
))}
{index !== groupedByMonth.length - 1 && }
))} {isRequesting ? (

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

) : isComplete ? ( sortedMemos.length === 0 && (

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

) ) : (
)}
); }; export default Timeline;