feat: add stock pages and ticker navigation
Add stock search and detail pages with charts, dividends and shared event rows. Use verified ticker links for portfolio names and logos, numeric dates and refreshed account cards. Update the generated API contract.
This commit is contained in:
@@ -0,0 +1,110 @@
|
||||
import {
|
||||
apiQueryClient,
|
||||
useAuthenticatedQueries,
|
||||
useAuthenticatedQuery,
|
||||
} from "@/shared/api";
|
||||
|
||||
type StockPeriod = "month" | "halfYear" | "year" | "all";
|
||||
|
||||
function useStockSearch(query: string) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks", {
|
||||
params: { query: { query } },
|
||||
}),
|
||||
enabled: query.length >= 2,
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
function stockQueryOptions(uid: string) {
|
||||
return {
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}", {
|
||||
params: { path: { uid } },
|
||||
}),
|
||||
staleTime: 30_000,
|
||||
};
|
||||
}
|
||||
|
||||
function useStocks(uids: string[]) {
|
||||
const uniqueUids = [...new Set(uids)];
|
||||
const queries = useAuthenticatedQueries(uniqueUids.map(stockQueryOptions));
|
||||
return new Map(
|
||||
queries.map((query, index) => [uniqueUids[index], query.data]),
|
||||
);
|
||||
}
|
||||
|
||||
function useStock(identifier: string) {
|
||||
const isUid =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
|
||||
identifier,
|
||||
);
|
||||
|
||||
const byUid = useAuthenticatedQuery({
|
||||
...stockQueryOptions(identifier),
|
||||
enabled: Boolean(identifier) && isUid,
|
||||
});
|
||||
const byTicker = useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/by-ticker/{ticker}", {
|
||||
params: { path: { ticker: identifier } },
|
||||
}),
|
||||
enabled: Boolean(identifier) && !isUid,
|
||||
staleTime: 30_000,
|
||||
});
|
||||
return isUid ? byUid : byTicker;
|
||||
}
|
||||
function useStockQuote(uid: string) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/quote", {
|
||||
params: { path: { uid } },
|
||||
}),
|
||||
enabled: Boolean(uid),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
function useStockCandles(uid: string, period: StockPeriod) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/candles", {
|
||||
params: { path: { uid }, query: { period } },
|
||||
}),
|
||||
enabled: Boolean(uid),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
function useStockPosition(uid: string) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/position", {
|
||||
params: { path: { uid } },
|
||||
}),
|
||||
enabled: Boolean(uid),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
function useStockCompany(uid: string) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/company", {
|
||||
params: { path: { uid } },
|
||||
}),
|
||||
enabled: Boolean(uid),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
function useStockDividends(uid: string) {
|
||||
return useAuthenticatedQuery({
|
||||
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/dividends", {
|
||||
params: { path: { uid } },
|
||||
}),
|
||||
enabled: Boolean(uid),
|
||||
staleTime: 30_000,
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
type StockPeriod,
|
||||
useStock,
|
||||
useStockCandles,
|
||||
useStockCompany,
|
||||
useStockDividends,
|
||||
useStockPosition,
|
||||
useStockQuote,
|
||||
useStockSearch,
|
||||
useStocks,
|
||||
};
|
||||
Reference in New Issue
Block a user