From 10c9bb081b77b275665c04873846bb98c21a8dc2 Mon Sep 17 00:00:00 2001 From: Steven Date: Sat, 20 Jul 2024 00:28:49 +0800 Subject: [PATCH] chore: retire timeline page --- web/src/components/ActivityCalendar.tsx | 12 +- web/src/components/Navigation.tsx | 10 +- .../TimelineSidebar/TimelineSidebar.tsx | 25 -- .../TimelineSidebar/TimelineSidebarDrawer.tsx | 37 --- web/src/components/TimelineSidebar/index.ts | 4 - web/src/components/UserStatisticsView.tsx | 27 ++- web/src/layouts/RootLayout.tsx | 17 +- web/src/locales/en.json | 3 - web/src/pages/Home.tsx | 7 - web/src/pages/Timeline.tsx | 216 ------------------ web/src/router/index.tsx | 9 +- 11 files changed, 36 insertions(+), 331 deletions(-) delete mode 100644 web/src/components/TimelineSidebar/TimelineSidebar.tsx delete mode 100644 web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx delete mode 100644 web/src/components/TimelineSidebar/index.ts delete mode 100644 web/src/pages/Timeline.tsx diff --git a/web/src/components/ActivityCalendar.tsx b/web/src/components/ActivityCalendar.tsx index e7050834..996894d8 100644 --- a/web/src/components/ActivityCalendar.tsx +++ b/web/src/components/ActivityCalendar.tsx @@ -18,11 +18,11 @@ const getCellAdditionalStyles = (count: number, maxCount: number) => { const ratio = count / maxCount; if (ratio > 0.7) { - return "bg-blue-600 text-gray-100 dark:opacity-80"; + return "bg-teal-600 text-gray-100 dark:opacity-80"; } else if (ratio > 0.4) { - return "bg-blue-400 text-gray-200 dark:opacity-80"; + return "bg-teal-400 text-gray-100 dark:opacity-80"; } else { - return "bg-blue-300 text-gray-600 dark:opacity-80"; + return "bg-teal-300 text-gray-100 dark:opacity-80"; } }; @@ -48,7 +48,7 @@ const ActivityCalendar = (props: Props) => { } return ( -
+
{days.map((day, index) => { const date = getNormalizedDateString( getDateWithOffset(`${year}-${String(month).padStart(2, "0")}-${String(day).padStart(2, "0")}`), @@ -61,7 +61,7 @@ const ActivityCalendar = (props: Props) => {
{
diff --git a/web/src/components/Navigation.tsx b/web/src/components/Navigation.tsx index 724815b3..de6809b8 100644 --- a/web/src/components/Navigation.tsx +++ b/web/src/components/Navigation.tsx @@ -50,16 +50,10 @@ const Navigation = (props: Props) => { const homeNavLink: NavLinkItem = { id: "header-home", - path: Routes.HOME, + path: Routes.ROOT, title: t("common.home"), icon: , }; - const timelineNavLink: NavLinkItem = { - id: "header-timeline", - path: Routes.TIMELINE, - title: t("timeline.title"), - icon: , - }; const resourcesNavLink: NavLinkItem = { id: "header-resources", path: Routes.RESOURCES, @@ -117,7 +111,7 @@ const Navigation = (props: Props) => { }; const navLinks: NavLinkItem[] = user - ? [homeNavLink, timelineNavLink, resourcesNavLink, exploreNavLink, profileNavLink, inboxNavLink, archivedNavLink, settingNavLink] + ? [homeNavLink, resourcesNavLink, exploreNavLink, profileNavLink, inboxNavLink, archivedNavLink, settingNavLink] : [exploreNavLink, signInNavLink, aboutNavLink]; return ( diff --git a/web/src/components/TimelineSidebar/TimelineSidebar.tsx b/web/src/components/TimelineSidebar/TimelineSidebar.tsx deleted file mode 100644 index 134df6e4..00000000 --- a/web/src/components/TimelineSidebar/TimelineSidebar.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import clsx from "clsx"; -import TagsSection from "../HomeSidebar/TagsSection"; -import SearchBar from "../SearchBar"; -import UserStatisticsView from "../UserStatisticsView"; - -interface Props { - className?: string; -} - -const TimelineSidebar = (props: Props) => { - return ( - - ); -}; - -export default TimelineSidebar; diff --git a/web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx b/web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx deleted file mode 100644 index 32318500..00000000 --- a/web/src/components/TimelineSidebar/TimelineSidebarDrawer.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { Drawer, IconButton } from "@mui/joy"; -import { useEffect, useState } from "react"; -import { useLocation } from "react-router-dom"; -import Icon from "../Icon"; -import TimelineSidebar from "./TimelineSidebar"; - -const TimelineSidebarDrawer = () => { - const location = useLocation(); - const [open, setOpen] = useState(false); - - useEffect(() => { - setOpen(false); - }, [location.pathname]); - - const toggleDrawer = (inOpen: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => { - if (event.type === "keydown" && ((event as React.KeyboardEvent).key === "Tab" || (event as React.KeyboardEvent).key === "Shift")) { - return; - } - - setOpen(inOpen); - }; - - return ( - <> - - - - -
- -
-
- - ); -}; - -export default TimelineSidebarDrawer; diff --git a/web/src/components/TimelineSidebar/index.ts b/web/src/components/TimelineSidebar/index.ts deleted file mode 100644 index b5dbfcf5..00000000 --- a/web/src/components/TimelineSidebar/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import TimelineSidebar from "./TimelineSidebar"; -import TimelineSidebarDrawer from "./TimelineSidebarDrawer"; - -export { TimelineSidebar, TimelineSidebarDrawer }; diff --git a/web/src/components/UserStatisticsView.tsx b/web/src/components/UserStatisticsView.tsx index 6435f9a4..a28ffff2 100644 --- a/web/src/components/UserStatisticsView.tsx +++ b/web/src/components/UserStatisticsView.tsx @@ -1,13 +1,16 @@ import { Divider, Tooltip } from "@mui/joy"; import clsx from "clsx"; +import dayjs from "dayjs"; import { useState } from "react"; import toast from "react-hot-toast"; import { memoServiceClient } from "@/grpcweb"; import useAsyncEffect from "@/hooks/useAsyncEffect"; import useCurrentUser from "@/hooks/useCurrentUser"; +import i18n from "@/i18n"; import { useFilterStore } from "@/store/module"; import { useMemoStore } from "@/store/v1"; import { useTranslate } from "@/utils/i18n"; +import ActivityCalendar from "./ActivityCalendar"; import Icon from "./Icon"; interface UserMemoStats { @@ -25,6 +28,8 @@ const UserStatisticsView = () => { const [memoAmount, setMemoAmount] = useState(0); const [isRequesting, setIsRequesting] = useState(false); const [memoStats, setMemoStats] = useState({ link: 0, taskList: 0, code: 0, incompleteTasks: 0 }); + const [activityStats, setActivityStats] = useState>({}); + const monthString = dayjs(new Date().toDateString()).format("YYYY-MM"); const days = Math.ceil((Date.now() - currentUser.createTime!.getTime()) / 86400000); const filter = filterStore.state; @@ -50,6 +55,21 @@ const UserStatisticsView = () => { }); setMemoStats(memoStats); setMemoAmount(properties.length); + + const filters = [`row_status == "NORMAL"`]; + const { stats } = await memoServiceClient.getUserMemosStats({ + name: currentUser.name, + timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + filter: filters.join(" && "), + }); + + setActivityStats( + Object.fromEntries( + Object.entries(stats).filter(([date]) => { + return dayjs(date).format("YYYY-MM") === monthString; + }), + ), + ); setIsRequesting(false); }, [memoStore.stateId]); @@ -64,7 +84,9 @@ const UserStatisticsView = () => { return (
-

{t("common.statistics")}

+

+ {new Date().toLocaleDateString(i18n.language, { month: "long", day: "numeric" })} +

{
+
+ +
diff --git a/web/src/layouts/RootLayout.tsx b/web/src/layouts/RootLayout.tsx index e0cf853e..18dcad04 100644 --- a/web/src/layouts/RootLayout.tsx +++ b/web/src/layouts/RootLayout.tsx @@ -14,31 +14,16 @@ const RootLayout = () => { const location = useLocation(); const { sm } = useResponsiveWidth(); const currentUser = useCurrentUser(); - const [lastVisited] = useLocalStorage("lastVisited", "/home"); const [collapsed, setCollapsed] = useLocalStorage("navigation-collapsed", false); const [initialized, setInitialized] = useState(false); useEffect(() => { if (!currentUser) { - if ( - ([Routes.ROOT, Routes.HOME, Routes.TIMELINE, Routes.RESOURCES, Routes.INBOX, Routes.ARCHIVED, Routes.SETTING] as string[]).includes( - location.pathname, - ) - ) { + if (([Routes.ROOT, Routes.RESOURCES, Routes.INBOX, Routes.ARCHIVED, Routes.SETTING] as string[]).includes(location.pathname)) { window.location.href = Routes.EXPLORE; return; } - } else { - if (location.pathname === Routes.ROOT) { - if (lastVisited && ([Routes.HOME, Routes.TIMELINE] as string[]).includes(lastVisited)) { - window.location.href = lastVisited; - } else { - window.location.href = Routes.HOME; - } - return; - } } - setInitialized(true); }, []); diff --git a/web/src/locales/en.json b/web/src/locales/en.json index 8b15ebaa..fac5b42f 100644 --- a/web/src/locales/en.json +++ b/web/src/locales/en.json @@ -307,8 +307,5 @@ "delete-confirm": "Are you sure to delete this tag? All related memos will be archived.", "delete-tag": "Delete Tag", "no-tag-found": "No tag found" - }, - "timeline": { - "title": "Timeline" } } diff --git a/web/src/pages/Home.tsx b/web/src/pages/Home.tsx index 497f1d30..a97ff4f7 100644 --- a/web/src/pages/Home.tsx +++ b/web/src/pages/Home.tsx @@ -1,7 +1,6 @@ import { Button } from "@mui/joy"; import clsx from "clsx"; import { useEffect, useState } from "react"; -import useLocalStorage from "react-use/lib/useLocalStorage"; import Empty from "@/components/Empty"; import { HomeSidebar, HomeSidebarDrawer } from "@/components/HomeSidebar"; import Icon from "@/components/Icon"; @@ -13,7 +12,6 @@ import { getTimeStampByDate } from "@/helpers/datetime"; import useCurrentUser from "@/hooks/useCurrentUser"; import useFilterWithUrlParams from "@/hooks/useFilterWithUrlParams"; import useResponsiveWidth from "@/hooks/useResponsiveWidth"; -import { Routes } from "@/router"; import { useMemoList, useMemoStore } from "@/store/v1"; import { RowStatus } from "@/types/proto/api/v1/common"; import { useTranslate } from "@/utils/i18n"; @@ -24,7 +22,6 @@ const Home = () => { const user = useCurrentUser(); const memoStore = useMemoStore(); const memoList = useMemoList(); - const [, setLastVisited] = useLocalStorage("lastVisited", Routes.HOME); const [isRequesting, setIsRequesting] = useState(true); const [nextPageToken, setNextPageToken] = useState(""); const filter = useFilterWithUrlParams(); @@ -33,10 +30,6 @@ const Home = () => { .sort((a, b) => getTimeStampByDate(b.displayTime) - getTimeStampByDate(a.displayTime)) .sort((a, b) => Number(b.pinned) - Number(a.pinned)); - useEffect(() => { - setLastVisited(Routes.HOME); - }, []); - useEffect(() => { memoList.reset(); fetchMemos(""); diff --git a/web/src/pages/Timeline.tsx b/web/src/pages/Timeline.tsx deleted file mode 100644 index 45fc949c..00000000 --- a/web/src/pages/Timeline.tsx +++ /dev/null @@ -1,216 +0,0 @@ -import { Button, IconButton } from "@mui/joy"; -import clsx from "clsx"; -import dayjs from "dayjs"; -import { useEffect, useState } from "react"; -import useLocalStorage from "react-use/lib/useLocalStorage"; -import ActivityCalendar from "@/components/ActivityCalendar"; -import Empty from "@/components/Empty"; -import Icon from "@/components/Icon"; -import showMemoEditorDialog from "@/components/MemoEditor/MemoEditorDialog"; -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 { Routes } from "@/router"; -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 [, setLastVisited] = useLocalStorage("lastVisited", Routes.TIMELINE); - const filter = useFilterWithUrlParams(); - const [activityStats, setActivityStats] = useState>({}); - const [selectedDateString, setSelectedDateString] = useState(new Date().toDateString()); - const [isRequesting, setIsRequesting] = useState(true); - const [nextPageToken, setNextPageToken] = useState(""); - const sortedMemos = memoList.value.sort((a, b) => getTimeStampByDate(a.displayTime) - getTimeStampByDate(b.displayTime)); - const monthString = dayjs(selectedDateString).format("YYYY-MM"); - - useEffect(() => { - setLastVisited(Routes.TIMELINE); - }, []); - - useEffect(() => { - memoList.reset(); - fetchMemos(""); - }, [selectedDateString, filter.text, filter.tag, filter.memoPropertyFilter]); - - useEffect(() => { - (async () => { - const filters = [`row_status == "NORMAL"`]; - const { stats } = await memoServiceClient.getUserMemosStats({ - name: user.name, - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, - filter: filters.join(" && "), - }); - - setActivityStats( - Object.fromEntries( - Object.entries(stats).filter(([date]) => { - return dayjs(date).format("YYYY-MM") === monthString; - }), - ), - ); - })(); - }, [sortedMemos.length]); - - const fetchMemos = async (nextPageToken: string) => { - setIsRequesting(true); - const filters = [`creator == "${user.name}"`, `row_status == "NORMAL"`]; - const contentSearch: string[] = []; - if (filter.text) { - contentSearch.push(JSON.stringify(filter.text)); - } - if (contentSearch.length > 0) { - filters.push(`content_search == [${contentSearch.join(", ")}]`); - } - if (filter.tag) { - filters.push(`tag == "${filter.tag}"`); - } - if (filter.memoPropertyFilter) { - if (filter.memoPropertyFilter.hasLink) { - filters.push(`has_link == true`); - } - if (filter.memoPropertyFilter.hasTaskList) { - filters.push(`has_task_list == true`); - } - if (filter.memoPropertyFilter.hasCode) { - filters.push(`has_code == true`); - } - } - if (selectedDateString) { - const selectedDateStamp = getTimeStampByDate(selectedDateString); - filters.push( - ...[`display_time_after == ${selectedDateStamp / 1000}`, `display_time_before == ${(selectedDateStamp + DAILY_TIMESTAMP) / 1000}`], - ); - } - const response = await memoStore.fetchMemos({ - pageSize: DEFAULT_LIST_MEMOS_PAGE_SIZE, - filter: filters.join(" && "), - pageToken: nextPageToken, - }); - setIsRequesting(false); - setNextPageToken(response.nextPageToken); - }; - - const handleSelectedDataChange = (date: string) => { - if (dayjs(date).isValid()) { - setSelectedDateString(new Date(date).toDateString()); - } - }; - - const handleNewMemo = () => { - showMemoEditorDialog({}); - }; - - return ( -
- {!md && ( - - - - )} -
-
-
-
-
-
setSelectedDateString(new Date().toDateString())} - > - - {t("timeline.title")} -
-
-
- handleNewMemo()}> - - -
-
-
-
-
-
-
- {new Date(selectedDateString).toLocaleDateString(i18n.language, { month: "short", day: "numeric" })} - e.target.showPicker()} - onChange={(e) => handleSelectedDataChange(e.target.value)} - /> -
- {dayjs(monthString).year()} -
- setSelectedDateString(date)} - /> -
- -
- {sortedMemos.map((memo) => ( - - ))} -
-
- - {isRequesting ? ( -
- -

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

-
- ) : !nextPageToken ? ( - sortedMemos.length === 0 && ( -
- -

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

-
- ) - ) : ( -
- -
- )} -
-
-
- {md && ( -
- -
- )} -
-
- ); -}; - -export default Timeline; diff --git a/web/src/router/index.tsx b/web/src/router/index.tsx index 418b2183..6cacedf3 100644 --- a/web/src/router/index.tsx +++ b/web/src/router/index.tsx @@ -15,13 +15,10 @@ import Resources from "@/pages/Resources"; import Setting from "@/pages/Setting"; import SignIn from "@/pages/SignIn"; import SignUp from "@/pages/SignUp"; -import Timeline from "@/pages/Timeline"; import UserProfile from "@/pages/UserProfile"; export enum Routes { ROOT = "/", - HOME = "/home", - TIMELINE = "/timeline", RESOURCES = "/resources", INBOX = "/inbox", ARCHIVED = "/archived", @@ -59,13 +56,9 @@ const router = createBrowserRouter([ element: , children: [ { - path: Routes.HOME, + path: "", element: , }, - { - path: Routes.TIMELINE, - element: , - }, { path: Routes.RESOURCES, element: ,