Files
zhixing-system/zhixing-web/src/features/sector-radar/api/sector-radar.query.ts
T

130 lines
3.4 KiB
TypeScript
Raw Normal View History

import {
useInfiniteQuery,
useQuery,
type InfiniteData,
} from "@tanstack/react-query"
import {
getSectorRadarDates,
getSectorRadarRankings,
getStockSectorMembership,
getSectorRadarHistory,
getSectorRadarDetail,
} from "./sector-radar.api"
import type {
RadarRankingsQuery,
RadarRankingsResponse,
RadarSectorQuery,
} from "./sector-radar.types"
export const sectorRadarDatesQueryKey = ["sectorRadar", "dates"] as const
export const stockSectorMembershipQueryKey = (
tsCode?: string,
tradeDate?: string,
) =>
[
"sectorRadar",
"stockMembership",
tsCode ?? "none",
tradeDate ?? "none",
] as const
/**
* Read one stock's point-in-time industries and concepts for a detail view.
*
* Disabled until both the stock code and target trade date are known; the
* query stays cached per code-date pair so switching selections refetches
* only unseen pairs.
*/
export function useStockSectorMembership(tsCode?: string, tradeDate?: string) {
return useQuery({
enabled: Boolean(tsCode && tradeDate),
queryFn: ({ signal }) =>
getStockSectorMembership(tsCode ?? "", tradeDate ?? "", signal),
queryKey: stockSectorMembershipQueryKey(tsCode, tradeDate),
staleTime: 5 * 60 * 1000,
})
}
export const sectorRadarRankingsQueryKey = (query: RadarRankingsQuery) =>
[
"sectorRadar",
"rankings",
query.tradeDate ?? "latest",
query.sectorType,
query.view,
query.rankChangeMetric,
query.rankChangeDays,
query.side,
query.search ?? "",
query.pageSize,
] as const
export function useSectorRadarDates() {
return useQuery({
queryFn: ({ signal }) => getSectorRadarDates(signal),
queryKey: sectorRadarDatesQueryKey,
})
}
export function useSectorRadarRankings(query: RadarRankingsQuery) {
return useInfiniteQuery<
RadarRankingsResponse,
Error,
InfiniteData<RadarRankingsResponse>,
ReturnType<typeof sectorRadarRankingsQueryKey>,
number
>({
getNextPageParam: (lastPage, pages, lastPageParam) => {
const loadedRowCount = pages.reduce(
(count, page) => count + page.rows.length,
0,
)
if (
lastPage.status !== "success" ||
lastPage.rows.length === 0 ||
lastPage.page !== lastPageParam ||
loadedRowCount >= lastPage.total
) {
return undefined
}
const nextPageParam = lastPageParam + 1
return Number.isSafeInteger(nextPageParam) ? nextPageParam : undefined
},
initialPageParam: 1,
queryFn: ({ pageParam, signal }) =>
getSectorRadarRankings({ ...query, page: pageParam }, signal),
queryKey: sectorRadarRankingsQueryKey(query),
})
}
export const sectorRadarSectorQueryKey = (
resource: "history" | "detail",
query: RadarSectorQuery,
) =>
[
"sectorRadar",
resource,
query.sectorType,
query.sectorCode,
query.tradeDate,
] as const
/** Keep on-demand history isolated by sector type, code and requested date. */
export function useSectorRadarHistory(query: RadarSectorQuery) {
return useQuery({
queryKey: sectorRadarSectorQueryKey("history", query),
queryFn: ({ signal }) => getSectorRadarHistory(query, signal),
})
}
/** Mount only while the detail dialog is open; never reuse another date as placeholder data. */
export function useSectorRadarDetail(query: RadarSectorQuery) {
return useQuery({
queryKey: sectorRadarSectorQueryKey("detail", query),
queryFn: ({ signal }) => getSectorRadarDetail(query, signal),
})
}