feat(desktop): display list analytics

This commit is contained in:
DIYgod 2025-05-22 20:04:20 +08:00
parent e0b379bba9
commit e525edc83d
No known key found for this signature in database
5 changed files with 29 additions and 18 deletions

View File

@ -1,5 +1,5 @@
import { Skeleton } from "@follow/components/ui/skeleton/index.js"
import type { FeedOrListRespModel } from "@follow/models"
import type { FeedAnalyticsModel, FeedOrListRespModel, ListAnalyticsModel } from "@follow/models"
import type { FC } from "react"
import { useMemo } from "react"
import { useTranslation } from "react-i18next"
@ -11,11 +11,7 @@ import { FollowSummary } from "../feed/feed-summary"
export interface FeedSummaryProps {
feed: FeedOrListRespModel
analytics?: {
updatesPerWeek: number | null
subscriptionCount: number | null
latestEntryPublishedAt: string | null
}
analytics?: FeedAnalyticsModel | ListAnalyticsModel
showAnalytics?: boolean
}
@ -28,7 +24,7 @@ export const FeedSummary: FC<FeedSummaryProps> = ({ feed, analytics, showAnalyti
{showAnalytics && (
<div className="text-callout mt-2 flex h-6 justify-between gap-4 pl-10">
{!analytics ? (
{!analytics && !("updatedAt" in feed && "updatedAt" in feed && feed.updatedAt) ? (
<Skeleton className="mt-1 h-5 w-40" />
) : (
<div className="text-text-secondary flex items-center gap-3">
@ -42,12 +38,14 @@ export const FeedSummary: FC<FeedSummaryProps> = ({ feed, analytics, showAnalyti
</span>
</div>
)}
{analytics?.updatesPerWeek ? (
{analytics && "updatesPerWeek" in analytics && analytics?.updatesPerWeek ? (
<div className="flex items-center gap-1.5">
<i className="i-mgc-safety-certificate-cute-re" />
<span>{t("feed.entry_week", { count: analytics.updatesPerWeek ?? 0 })}</span>
</div>
) : analytics?.latestEntryPublishedAt ? (
) : analytics &&
"latestEntryPublishedAt" in analytics &&
analytics?.latestEntryPublishedAt ? (
<div className="flex items-center gap-1.5">
<i className="i-mgc-safe-alert-cute-re" />
<span>{t("feed.updated_at")}</span>
@ -57,6 +55,13 @@ export const FeedSummary: FC<FeedSummaryProps> = ({ feed, analytics, showAnalyti
/>
</div>
) : null}
{"updatedAt" in feed && feed.updatedAt ? (
<div className="flex items-center gap-1.5">
<i className="i-mgc-safety-certificate-cute-re" />
<span>{t("feed.updated_at")}</span>
<RelativeTime date={feed.updatedAt} displayAbsoluteTimeAfterDay={Infinity} />
</div>
) : null}
</div>
)}
</div>

View File

@ -1,5 +1,4 @@
import { Button } from "@follow/components/ui/button/index.js"
import { Card, CardHeader } from "@follow/components/ui/card/index.jsx"
import {
Form,
FormControl,
@ -13,7 +12,7 @@ import { Input } from "@follow/components/ui/input/index.js"
import { LoadingCircle } from "@follow/components/ui/loading/index.jsx"
import { Switch } from "@follow/components/ui/switch/index.jsx"
import { FeedViewType } from "@follow/constants"
import type { ListModel } from "@follow/models/types"
import type { ListAnalyticsModel, ListModel } from "@follow/models/types"
import { tracker } from "@follow/tracker"
import { cn } from "@follow/utils/utils"
import { zodResolver } from "@hookform/resolvers/zod"
@ -31,7 +30,6 @@ import { apiClient } from "~/lib/api-fetch"
import { tipcClient } from "~/lib/client"
import { getFetchErrorMessage, toastFetchError } from "~/lib/error-parser"
import { getNewIssueUrl } from "~/lib/issues"
import { FollowSummary } from "~/modules/feed/feed-summary"
import { entries as entriesQuery } from "~/queries/entries"
import { lists as listsQuery, useList } from "~/queries/lists"
import { subscription as subscriptionQuery } from "~/queries/subscriptions"
@ -41,6 +39,7 @@ import { feedUnreadActions } from "~/store/unread"
import { useTOTPModalWrapper } from "../profile/hooks"
import { ViewSelectorRadioGroup } from "../shared/ViewSelectorRadioGroup"
import { FeedSummary } from "./FeedSummary"
const formSchema = z.object({
view: z.string(),
@ -92,6 +91,7 @@ export const ListForm: Component<{
onSuccess,
subscriptionData: feedQuery.data?.subscription,
analytics: feedQuery.data?.analytics,
list,
}}
/>
@ -165,6 +165,7 @@ const ListInnerForm = ({
onSuccess,
subscriptionData,
list,
analytics,
}: {
defaultValues?: z.infer<typeof formSchema>
id?: string
@ -177,6 +178,7 @@ const ListInnerForm = ({
title?: string | null
}
list: ListModel
analytics?: ListAnalyticsModel
}) => {
const subscription = useSubscriptionByFeedId(id || "") || subscriptionData
const isSubscribed = !!subscription
@ -272,11 +274,7 @@ const ListInnerForm = ({
return (
<div className="flex flex-1 flex-col gap-y-4">
<Card>
<CardHeader>
<FollowSummary feed={list} />
</CardHeader>
</Card>
<FeedSummary feed={list} analytics={analytics} showAnalytics />
<Form {...form}>
<form onSubmit={form.handleSubmit(onSubmit)} className="flex flex-1 flex-col gap-y-4">
<FormField

View File

@ -51,7 +51,7 @@ export function FollowSummary({
</EllipsisHorizontalTextWithTooltip>
</div>
</div>
{!simple && (
{!simple && feed.description && (
<EllipsisHorizontalTextWithTooltip className="text-text/80 text-body truncate pl-10 font-normal">
{feed.description}
</EllipsisHorizontalTextWithTooltip>

View File

@ -38,6 +38,10 @@ export type FeedAnalyticsModel = ExtractBizResponse<
typeof _apiClient.feeds.$get
>["data"]["analytics"]
export type ListAnalyticsModel = ExtractBizResponse<
typeof _apiClient.lists.$get
>["data"]["analytics"]
export type ListModel = Omit<ListModelPoplutedFeeds, "feeds">
export type ListModelPoplutedFeeds = ExtractBizResponse<
typeof _apiClient.lists.$get

View File

@ -19638,6 +19638,10 @@ declare const _routes: hono_hono_base.HonoBase<Env, ({
};
readCount: number;
feedCount: number;
analytics?: {
subscriptionCount: number | null;
listId: string;
} | undefined;
subscription?: {
createdAt: string;
userId: string;