diff --git a/web/src/components/ActivityCalendar.tsx b/web/src/components/ActivityCalendar.tsx index 429996bfd..106484a47 100644 --- a/web/src/components/ActivityCalendar.tsx +++ b/web/src/components/ActivityCalendar.tsx @@ -8,7 +8,7 @@ interface Props { month: string; data: Record; onClick?: (date: string) => void; - selectedDate?: string; + selectedDate?: string; } const getCellAdditionalStyles = (count: number, maxCount: number) => { @@ -56,7 +56,7 @@ const ActivityCalendar = (props: Props) => { const count = data[date] || 0; const isToday = new Date().toDateString() === new Date(date).toDateString(); const tooltipText = count ? t("memo.count-memos-in-date", { count: count, date: date }) : date; - const isSelected = date === selectedDate; + const isSelected = date === selectedDate; return day ? (
{ "w-4 h-4 text-[9px] rounded-md flex justify-center items-center border border-transparent", getCellAdditionalStyles(count, maxCount), isToday && "border-gray-600 dark:!border-gray-500", - isSelected && "bg-green-500 text-white", + isSelected && "bg-green-500 text-white", )} onClick={() => count && onClick && onClick(date)} > diff --git a/web/src/pages/Timeline.tsx b/web/src/pages/Timeline.tsx index 6e29f8baa..4ac280357 100644 --- a/web/src/pages/Timeline.tsx +++ b/web/src/pages/Timeline.tsx @@ -1,6 +1,7 @@ import { Button, Divider, IconButton } from "@mui/joy"; import classNames from "classnames"; import { Fragment, useEffect, useRef, useState } from "react"; +import toast from "react-hot-toast"; import ActivityCalendar from "@/components/ActivityCalendar"; import Empty from "@/components/Empty"; import Icon from "@/components/Icon"; @@ -19,7 +20,6 @@ import i18n from "@/i18n"; import { useMemoList, useMemoStore } from "@/store/v1"; import { Memo } from "@/types/proto/api/v2/memo_service"; import { useTranslate } from "@/utils/i18n"; -import toast from "react-hot-toast"; interface GroupedByMonthItem { // Format: 2021-1 @@ -67,79 +67,85 @@ const Timeline = () => { } }; const handlePrevDay = () => { - if (!selectedDay) return; - + if (!selectedDay) return; + const currentDate = new Date(selectedDay); - currentDate.setUTCDate(currentDate.getUTCDate() - 1); - + currentDate.setUTCDate(currentDate.getUTCDate() - 1); + let found = false; while (currentDate >= new Date(Object.keys(activityStats).sort()[0])) { - const checkDateStr = currentDate.toISOString().substring(0, 10); + const checkDateStr = currentDate.toISOString().substring(0, 10); if (activityStats[checkDateStr] && activityStats[checkDateStr] > 0) { - setSelectedDay(checkDateStr); + setSelectedDay(checkDateStr); found = true; break; } currentDate.setUTCDate(currentDate.getUTCDate() - 1); } - + if (!found) { toast.error(t("message.no-more-memos")); } }; const handleNextDay = () => { - if (!selectedDay) return; - + if (!selectedDay) return; + const currentDate = new Date(selectedDay); - currentDate.setUTCDate(currentDate.getUTCDate() + 1); - + currentDate.setUTCDate(currentDate.getUTCDate() + 1); + let found = false; while (currentDate <= new Date(Object.keys(activityStats).sort().reverse()[0])) { - const checkDateStr = currentDate.toISOString().substring(0, 10); + const checkDateStr = currentDate.toISOString().substring(0, 10); if (activityStats[checkDateStr] && activityStats[checkDateStr] > 0) { - setSelectedDay(checkDateStr); + setSelectedDay(checkDateStr); found = true; break; } currentDate.setUTCDate(currentDate.getUTCDate() + 1); - } + } if (!found) { - toast.error(t("message.no-more-memos")); + toast.error(t("message.no-more-memos")); } }; - const handlePrevMonth = () => { - if (!selectedDay) return; - const currentMonth = new Date(selectedDay); - currentMonth.setUTCMonth(currentMonth.getUTCMonth() - 1); + const handlePrevMonth = () => { + if (!selectedDay) return; + const currentMonth = new Date(selectedDay); + currentMonth.setUTCMonth(currentMonth.getUTCMonth() - 1); - const prevMonthStr = currentMonth.toISOString().substring(0, 7); - const datesWithData = Object.keys(activityStats).filter(date => date.startsWith(prevMonthStr)).sort(); - if (datesWithData.length > 0) { - setSelectedDay(datesWithData[0]); + const prevMonthStr = currentMonth.toISOString().substring(0, 7); + const datesWithData = Object.keys(activityStats) + .filter((date) => date.startsWith(prevMonthStr)) + .sort(); + if (datesWithData.length > 0) { + setSelectedDay(datesWithData[0]); + } else { + handlePrevDay(); + } + }; + const handleNextMonth = () => { + if (!selectedDay) return; + const currentMonth = new Date(selectedDay); + currentMonth.setUTCMonth(currentMonth.getUTCMonth() + 1); + const nextMonthStr = currentMonth.toISOString().substring(0, 7); + const datesWithData = Object.keys(activityStats) + .filter((date) => date.startsWith(nextMonthStr)) + .sort(); + if (datesWithData.length > 0) { + setSelectedDay(datesWithData[0]); + } else { + const currentMonthStr = selectedDay.substring(0, 7); + const datesInCurrentMonth = Object.keys(activityStats) + .filter((date) => date.startsWith(currentMonthStr)) + .sort(); + if (datesInCurrentMonth.length > 0 && selectedDay !== datesInCurrentMonth[datesInCurrentMonth.length - 1]) { + setSelectedDay(datesInCurrentMonth[datesInCurrentMonth.length - 1]); } else { - handlePrevDay() + toast.error(t("message.no-more-memos")); } - }; - const handleNextMonth = () => { - if (!selectedDay) return; - const currentMonth = new Date(selectedDay); - currentMonth.setUTCMonth(currentMonth.getUTCMonth() + 1); - const nextMonthStr = currentMonth.toISOString().substring(0, 7); - const datesWithData = Object.keys(activityStats).filter(date => date.startsWith(nextMonthStr)).sort(); - if (datesWithData.length > 0) { - setSelectedDay(datesWithData[0]); - } else { - const currentMonthStr = selectedDay.substring(0, 7); - const datesInCurrentMonth = Object.keys(activityStats).filter(date => date.startsWith(currentMonthStr)).sort(); - if (datesInCurrentMonth.length > 0 && selectedDay !== datesInCurrentMonth[datesInCurrentMonth.length - 1]) { - setSelectedDay(datesInCurrentMonth[datesInCurrentMonth.length - 1]); - } else { - toast.error(t("message.no-more-memos")); - } - } - }; - + } + }; + useEffect(() => { nextPageTokenRef.current = undefined; memoList.reset(); @@ -221,22 +227,22 @@ const Timeline = () => {
- { selectedDay && ( -
- handlePrevMonth()}> - - - handlePrevDay()}> - - - handleNextDay()}> - - - handleNextMonth()}> - - -
- )} + {selectedDay && ( +
+ handlePrevMonth()}> + + + handlePrevDay()}> + + + handleNextDay()}> + + + handleNextMonth()}> + + +
+ )} handleNewMemo()}> @@ -246,57 +252,64 @@ const Timeline = () => {
- {activityStats && Object.keys(activityStats).length > 0 && groupedByMonth.map((group, index) => ( - -
-
-
- - {new Date(group.month).toLocaleString(i18n.language, { month: "short", timeZone: "UTC" })} - - {selectedDay ? ( - - {new Date(selectedDay).toLocaleDateString(i18n.language, { - month: 'long', - day: 'numeric', - timeZone: "UTC" - })} + {activityStats && + Object.keys(activityStats).length > 0 && + groupedByMonth.map((group, index) => ( + +
+
+
+ + {new Date(group.month).toLocaleString(i18n.language, { month: "short", timeZone: "UTC" })} - ) : ( - - {new Date().toLocaleDateString(i18n.language, { - month: 'long', - timeZone: "UTC" - })} - - )} - {new Date(group.month).getUTCFullYear()} + {selectedDay ? ( + + {new Date(selectedDay).toLocaleDateString(i18n.language, { + month: "long", + day: "numeric", + timeZone: "UTC", + })} + + ) : ( + + {new Date().toLocaleDateString(i18n.language, { + month: "long", + timeZone: "UTC", + })} + + )} + {new Date(group.month).getUTCFullYear()} +
+ handleDateClick(date)} + selectedDate={selectedDay} + />
- handleDateClick(date)} selectedDate={selectedDay} /> -
-
- {group.memos.map((memo, index) => ( -
- -
- {index !== group.memos.length - 1 && ( -
- )} -
- +
+ {group.memos.map((memo, index) => ( +
+ +
+ {index !== group.memos.length - 1 && ( +
+ )} +
+ +
-
- ))} + ))} +
-
- {index !== groupedByMonth.length - 1 && } - - ))} + {index !== groupedByMonth.length - 1 && } + + ))} {isRequesting ? (