feat: show persisted investment data and sync state

Consume the provided resource-envelope API snapshot. Preserve financial snapshots during
refresh, observe synchronization without importing, and fence late responses across
account and connection changes.
This commit is contained in:
2026-09-26 21:22:49 +03:00
parent b987fd8e78
commit 4e5f564fa1
81 changed files with 4714 additions and 1420 deletions
+16 -10
View File
@@ -1,8 +1,9 @@
import {
apiQueryClient,
type paths,
unwrapResourceResult,
useAuthenticatedQueries,
useAuthenticatedQuery,
useResourceQuery,
} from "@/shared/api";
type StockPeriod = NonNullable<
@@ -14,7 +15,7 @@ type StockPeriod = NonNullable<
const STOCK_STALE_TIME_MS = 30_000;
function useStockSearch(query: string) {
return useAuthenticatedQuery({
return useResourceQuery({
...apiQueryClient.queryOptions("get", "/api/v1/stocks", {
params: { query: { query } },
}),
@@ -35,7 +36,10 @@ 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]),
queries.map((query, index) => [
uniqueUids[index],
unwrapResourceResult(query).data,
]),
);
}
@@ -45,11 +49,11 @@ function useStock(identifier: string) {
identifier,
);
const byUid = useAuthenticatedQuery({
const byUid = useResourceQuery({
...stockQueryOptions(identifier),
enabled: Boolean(identifier) && isUid,
});
const byTicker = useAuthenticatedQuery({
const byTicker = useResourceQuery({
...apiQueryClient.queryOptions("get", "/api/v1/stocks/by-ticker/{ticker}", {
params: { path: { ticker: identifier } },
}),
@@ -59,7 +63,7 @@ function useStock(identifier: string) {
return isUid ? byUid : byTicker;
}
function useStockQuote(uid: string) {
return useAuthenticatedQuery({
return useResourceQuery({
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/quote", {
params: { path: { uid } },
}),
@@ -68,7 +72,7 @@ function useStockQuote(uid: string) {
});
}
function useStockCandles(uid: string, period: StockPeriod) {
return useAuthenticatedQuery({
return useResourceQuery({
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/candles", {
params: { path: { uid }, query: { period } },
}),
@@ -77,7 +81,8 @@ function useStockCandles(uid: string, period: StockPeriod) {
});
}
function useStockPosition(uid: string) {
return useAuthenticatedQuery({
return useResourceQuery({
meta: { accessGroup: "brokerage" },
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/position", {
params: { path: { uid } },
}),
@@ -86,7 +91,7 @@ function useStockPosition(uid: string) {
});
}
function useStockCompany(uid: string) {
return useAuthenticatedQuery({
return useResourceQuery({
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/company", {
params: { path: { uid } },
}),
@@ -95,7 +100,8 @@ function useStockCompany(uid: string) {
});
}
function useStockDividends(uid: string) {
return useAuthenticatedQuery({
return useResourceQuery({
meta: { accessGroup: "brokerage" },
...apiQueryClient.queryOptions("get", "/api/v1/stocks/{uid}/dividends", {
params: { path: { uid } },
}),