refactor: enhance timeline handling and view parsing
- Updated `useNavigateEntry` to utilize `getTimelineIdByView` for better clarity in timeline ID generation. - Introduced `VIEW_SLUG_BY_VIEW` and `VIEW_PARAM_ALIAS_MAP` in `useRouteParams` for improved mapping of feed views to their respective routes. - Refactored `computeTimelineTabLists` in `useTimelineList` to normalize and filter timeline IDs, enhancing the handling of known timeline values. This refactor improves maintainability and readability of the timeline navigation logic. Signed-off-by: Innei <tukon479@gmail.com>
This commit is contained in:
parent
bffe2cd0df
commit
4a1fb17eae
|
|
@ -1,7 +1,7 @@
|
|||
import { getReadonlyRoute, getStableRouterNavigate } from "@follow/components/atoms/route.js"
|
||||
import { useMobile } from "@follow/components/hooks/useMobile.js"
|
||||
import { useSheetContext } from "@follow/components/ui/sheet/context.js"
|
||||
import { FeedViewType } from "@follow/constants"
|
||||
import type { FeedViewType } from "@follow/constants"
|
||||
import { getEntry } from "@follow/store/entry/getter"
|
||||
import { getSubscriptionByFeedId } from "@follow/store/subscription/getter"
|
||||
import { tracker } from "@follow/tracker"
|
||||
|
|
@ -18,11 +18,9 @@ import {
|
|||
ROUTE_FEED_IN_INBOX,
|
||||
ROUTE_FEED_IN_LIST,
|
||||
ROUTE_FEED_PENDING,
|
||||
ROUTE_TIMELINE_OF_VIEW,
|
||||
ROUTE_VIEW_ALL,
|
||||
} from "~/constants"
|
||||
|
||||
import { useRouteParamsSelector } from "./useRouteParams"
|
||||
import { getTimelineIdByView, useRouteParamsSelector } from "./useRouteParams"
|
||||
|
||||
export type NavigateEntryOptions = Partial<{
|
||||
timelineId: string
|
||||
|
|
@ -86,8 +84,7 @@ const parseNavigateEntryOptions = (options: NavigateEntryOptions): ParsedNavigat
|
|||
finalFeedId = encodeURIComponent(finalFeedId)
|
||||
|
||||
if (finalView !== undefined && !timelineId) {
|
||||
finalTimelineId =
|
||||
finalView === FeedViewType.All ? ROUTE_VIEW_ALL : `${ROUTE_TIMELINE_OF_VIEW}${finalView}`
|
||||
finalTimelineId = getTimelineIdByView(finalView)
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -109,7 +106,7 @@ export function getNavigateEntryPath(options: NavigateEntryOptions | ParsedNavig
|
|||
|
||||
/*
|
||||
* /timeline/:timelineId/:feedId/:entryId
|
||||
* timelineId: view-1
|
||||
* timelineId: articles | social-media | view-1 (legacy) | ...
|
||||
* feedId: xxx, folder-xxx, list-xxx, inbox-xxx
|
||||
* entryId: xxx
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -43,14 +43,59 @@ export interface BizRouteParams {
|
|||
timelineId?: string
|
||||
}
|
||||
|
||||
const VIEW_SLUG_BY_VIEW: Record<FeedViewType, string> = {
|
||||
[FeedViewType.All]: ROUTE_VIEW_ALL,
|
||||
[FeedViewType.Articles]: "articles",
|
||||
[FeedViewType.SocialMedia]: "social-media",
|
||||
[FeedViewType.Pictures]: "pictures",
|
||||
[FeedViewType.Videos]: "videos",
|
||||
[FeedViewType.Audios]: "audios",
|
||||
[FeedViewType.Notifications]: "notifications",
|
||||
}
|
||||
|
||||
const VIEW_PARAM_ALIAS_MAP: Record<string, FeedViewType> = Object.entries(VIEW_SLUG_BY_VIEW).reduce(
|
||||
(acc, [view, slug]) => {
|
||||
if (slug === ROUTE_VIEW_ALL) return acc
|
||||
const numericView = Number(view)
|
||||
if (Number.isNaN(numericView)) return acc
|
||||
acc[slug] = numericView as FeedViewType
|
||||
return acc
|
||||
},
|
||||
{} as Record<string, FeedViewType>,
|
||||
)
|
||||
|
||||
const FEED_VIEW_VALUES = new Set<FeedViewType>(
|
||||
Object.values(FeedViewType).filter((value): value is FeedViewType => typeof value === "number"),
|
||||
)
|
||||
|
||||
const isFeedViewTypeValue = (value: number): value is FeedViewType =>
|
||||
Number.isInteger(value) && FEED_VIEW_VALUES.has(value as FeedViewType)
|
||||
|
||||
export const getTimelineIdByView = (view: FeedViewType) =>
|
||||
VIEW_SLUG_BY_VIEW[view] ?? `${ROUTE_TIMELINE_OF_VIEW}${view}`
|
||||
|
||||
export function parseView(input: string | undefined): FeedViewType | undefined {
|
||||
if (input === ROUTE_VIEW_ALL) return FeedViewType.All
|
||||
if (input?.startsWith(ROUTE_TIMELINE_OF_VIEW)) {
|
||||
const view = Number.parseInt(input?.slice(ROUTE_TIMELINE_OF_VIEW.length), 10)
|
||||
if (Object.values(FeedViewType).includes(view)) {
|
||||
return view as FeedViewType
|
||||
if (!input) return undefined
|
||||
|
||||
const normalizedInput = input.toLowerCase()
|
||||
|
||||
if (normalizedInput === ROUTE_VIEW_ALL) return FeedViewType.All
|
||||
|
||||
const aliasView = VIEW_PARAM_ALIAS_MAP[normalizedInput]
|
||||
if (aliasView !== undefined) return aliasView
|
||||
|
||||
if (normalizedInput.startsWith(ROUTE_TIMELINE_OF_VIEW)) {
|
||||
const view = Number.parseInt(normalizedInput.slice(ROUTE_TIMELINE_OF_VIEW.length), 10)
|
||||
if (isFeedViewTypeValue(view)) {
|
||||
return view
|
||||
}
|
||||
}
|
||||
|
||||
const numericView = Number.parseInt(normalizedInput, 10)
|
||||
|
||||
if (isFeedViewTypeValue(numericView)) {
|
||||
return numericView
|
||||
}
|
||||
}
|
||||
|
||||
const parseRouteParams = (params: Params<any>, _searchParams: URLSearchParams): BizRouteParams => {
|
||||
|
|
|
|||
|
|
@ -4,12 +4,29 @@ import { useSubscriptionStore } from "@follow/store/subscription/store"
|
|||
import { useMemo } from "react"
|
||||
|
||||
import { useUISettingKey } from "~/atoms/settings/ui"
|
||||
import { ROUTE_TIMELINE_OF_VIEW, ROUTE_VIEW_ALL } from "~/constants/app"
|
||||
import { ROUTE_VIEW_ALL } from "~/constants/app"
|
||||
|
||||
import { getTimelineIdByView, parseView } from "./useRouteParams"
|
||||
|
||||
const ALL_TIMELINE_IDS = getViewList({ includeAll: true }).map((view) =>
|
||||
view.view === FeedViewType.All ? ROUTE_VIEW_ALL : `${ROUTE_TIMELINE_OF_VIEW}${view.view}`,
|
||||
getTimelineIdByView(view.view),
|
||||
)
|
||||
|
||||
const normalizeTimelineId = (id: string) => {
|
||||
const view = parseView(id)
|
||||
return view !== undefined ? getTimelineIdByView(view) : id
|
||||
}
|
||||
|
||||
const filterKnownTimelineIds = (ids: string[]) => {
|
||||
const seen = new Set<string>()
|
||||
return ids.filter((id) => {
|
||||
if (!ALL_TIMELINE_IDS.includes(id)) return false
|
||||
if (seen.has(id)) return false
|
||||
seen.add(id)
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
export const computeTimelineTabLists = ({
|
||||
timelineTabs,
|
||||
hasAudiosSubscription,
|
||||
|
|
@ -19,16 +36,17 @@ export const computeTimelineTabLists = ({
|
|||
hasAudiosSubscription: boolean
|
||||
hasNotificationsSubscription: boolean
|
||||
}) => {
|
||||
const savedVisible = (timelineTabs?.visible ?? []).filter((id) => ALL_TIMELINE_IDS.includes(id))
|
||||
const savedHidden = (timelineTabs?.hidden ?? []).filter((id) => ALL_TIMELINE_IDS.includes(id))
|
||||
const savedVisible = filterKnownTimelineIds(
|
||||
(timelineTabs?.visible ?? []).map(normalizeTimelineId),
|
||||
)
|
||||
const savedHidden = filterKnownTimelineIds((timelineTabs?.hidden ?? []).map(normalizeTimelineId))
|
||||
const extras = ALL_TIMELINE_IDS.filter(
|
||||
(id) => !savedVisible.includes(id) && !savedHidden.includes(id),
|
||||
)
|
||||
|
||||
const isDefaultHidden = (id: string) => {
|
||||
if (id === `${ROUTE_TIMELINE_OF_VIEW}${FeedViewType.Audios}`) return !hasAudiosSubscription
|
||||
if (id === `${ROUTE_TIMELINE_OF_VIEW}${FeedViewType.Notifications}`)
|
||||
return !hasNotificationsSubscription
|
||||
if (id === getTimelineIdByView(FeedViewType.Audios)) return !hasAudiosSubscription
|
||||
if (id === getTimelineIdByView(FeedViewType.Notifications)) return !hasNotificationsSubscription
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue