From ba0876a563a5b4a4f7edb0bac280646baaf0e71c Mon Sep 17 00:00:00 2001 From: Steven Date: Mon, 27 May 2024 20:04:07 +0800 Subject: [PATCH] feat: update statistics view --- server/router/api/v1/memo_service.go | 38 ++++++++++ web/src/components/UserStatisticsView.tsx | 88 +++++++++++++++++------ 2 files changed, 103 insertions(+), 23 deletions(-) diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index 3fc9f1e2..db2628d2 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -563,6 +563,44 @@ func (s *APIV1Service) ExportMemos(ctx context.Context, request *v1pb.ExportMemo }, nil } +func (s *APIV1Service) ListMemoProperties(ctx context.Context, request *v1pb.ListMemoPropertiesRequest) (*v1pb.ListMemoPropertiesResponse, error) { + user, err := s.GetCurrentUser(ctx) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to get current user") + } + + normalRowStatus := store.Normal + memoFind := &store.FindMemo{ + CreatorID: &user.ID, + RowStatus: &normalRowStatus, + ExcludeComments: true, + // Default exclude content for performance. + ExcludeContent: true, + } + if request.Name != "memos/-" { + memoID, err := ExtractMemoIDFromName(request.Name) + if err != nil { + return nil, status.Errorf(codes.InvalidArgument, "invalid memo name: %v", err) + } + memoFind.ID = &memoID + } + + memos, err := s.Store.ListMemos(ctx, memoFind) + if err != nil { + return nil, status.Errorf(codes.Internal, "failed to list memos") + } + + properties := []*v1pb.MemoProperty{} + for _, memo := range memos { + if memo.Payload.Property != nil { + properties = append(properties, convertMemoPropertyFromStore(memo.Payload.Property)) + } + } + return &v1pb.ListMemoPropertiesResponse{ + Properties: properties, + }, nil +} + func (s *APIV1Service) RebuildMemoProperty(ctx context.Context, request *v1pb.RebuildMemoPropertyRequest) (*emptypb.Empty, error) { user, err := s.GetCurrentUser(ctx) if err != nil { diff --git a/web/src/components/UserStatisticsView.tsx b/web/src/components/UserStatisticsView.tsx index 3253e978..e7b72985 100644 --- a/web/src/components/UserStatisticsView.tsx +++ b/web/src/components/UserStatisticsView.tsx @@ -9,13 +9,20 @@ interface Props { user: User; } +interface UserMemoStats { + links: number; + todos: number; + code: number; +} + const UserStatisticsView = (props: Props) => { const { user } = props; const t = useTranslate(); - const tagStore = useTagStore(); const memoStore = useMemoStore(); + const tagStore = useTagStore(); const [memoAmount, setMemoAmount] = useState(0); const [isRequesting, setIsRequesting] = useState(false); + const [memoStats, setMemoStats] = useState({ links: 0, todos: 0, code: 0 }); const days = Math.ceil((Date.now() - user.createTime!.getTime()) / 86400000); const memos = Object.values(memoStore.getState().memoMapByName); const tags = tagStore.sortedTags().length; @@ -27,40 +34,75 @@ const UserStatisticsView = (props: Props) => { (async () => { setIsRequesting(true); - const { stats } = await memoServiceClient.getUserMemosStats({ - name: user.name, - timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, + const { properties } = await memoServiceClient.listMemoProperties({ + name: `memos/-`, }); + const memoStats: UserMemoStats = { links: 0, todos: 0, code: 0 }; + properties.forEach((property) => { + if (property.hasLink) { + memoStats.links += 1; + } + if (property.hasTaskList) { + memoStats.todos += 1; + } + if (property.hasCode) { + memoStats.code += 1; + } + }); + setMemoStats(memoStats); + setMemoAmount(properties.length); setIsRequesting(false); - setMemoAmount(Object.values(stats).reduce((acc, cur) => acc + cur, 0)); })(); }, [memos.length, user.name]); return (
-
+

{t("common.statistics")}

-
-
- - {t("common.days")} +
+
+
+ + {t("common.days")} +
+ {days}
- {days} -
-
-
- - {t("common.memos")} +
+
+ + {t("common.memos")} +
+ {isRequesting ? : {memoAmount}}
- {isRequesting ? : {memoAmount}} -
-
-
- - {t("common.tags")} +
+
+ + {t("common.tags")} +
+ {tags} +
+
+
+ + Links +
+ {memoStats.links} +
+
+
+ + Todos +
+ {memoStats.todos} +
+
+
+ + Code +
+ {memoStats.code}
- {tags}
);