chore: finish frontend ESLint migration #18
Enable every plugin recommended preset and replace Biome with ESLint formatting. Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { useParams, useSearchParams } from "react-router";
|
||||
|
||||
import type { OperationCategory } from "@/entities/broker-operation";
|
||||
|
||||
import {
|
||||
type StockPeriod,
|
||||
useStock,
|
||||
@@ -22,118 +24,119 @@ const filters = ["all", "trades", "dividends", "other"] as const;
|
||||
type StockEventFilter = (typeof filters)[number];
|
||||
const categories: Record<StockEventFilter, OperationCategory[]> = {
|
||||
all: [],
|
||||
trades: ["trade"],
|
||||
dividends: ["income"],
|
||||
other: ["tax", "fee", "transfer", "other"],
|
||||
trades: ["trade"],
|
||||
};
|
||||
type StockPageVm = ReturnType<typeof useStockPageVm>;
|
||||
function useStockPageVm() {
|
||||
const { stockId = "" } = useParams();
|
||||
const stock = useStock(stockId);
|
||||
const uid = stock.data?.instrumentUid ?? "";
|
||||
const [params, setParams] = useSearchParams();
|
||||
const period =
|
||||
periods.find((value) => value === params.get("period")) ?? "month";
|
||||
const filter =
|
||||
filters.find((value) => value === params.get("events")) ?? "all";
|
||||
const [parameters, setParameters] = useSearchParams();
|
||||
const period
|
||||
= periods.find(value => value === parameters.get("period")) ?? "month";
|
||||
const filter
|
||||
= filters.find(value => value === parameters.get("events")) ?? "all";
|
||||
const quote = useStockQuote(uid);
|
||||
const candles = useStockCandles(uid, period);
|
||||
const position = useStockPosition(uid);
|
||||
const company = useStockCompany(uid);
|
||||
const dividends = useStockDividends(uid);
|
||||
const history = useInstrumentOperations(uid, filter, categories[filter]);
|
||||
const history = useInstrumentOperations(uid, filter, /* eslint-disable-line security/detect-object-injection -- This lookup uses a fixed typed key set, not an arbitrary external property name. */ categories[filter]);
|
||||
const { operations } = history;
|
||||
const sync = useScreenSync(
|
||||
{
|
||||
screen: "stock",
|
||||
instrumentUid: uid,
|
||||
candlePeriod: period,
|
||||
accountId: "all",
|
||||
categories: categories[filter],
|
||||
candlePeriod: period,
|
||||
categories: /* eslint-disable-line security/detect-object-injection -- This lookup uses a fixed typed key set, not an arbitrary external property name. */ categories[filter],
|
||||
instrumentUid: uid,
|
||||
limit: 20,
|
||||
screen: "stock",
|
||||
},
|
||||
[stock, quote, candles, position, company, dividends, operations],
|
||||
);
|
||||
const setParam = (key: string, value: string) => {
|
||||
const next = new URLSearchParams(params);
|
||||
const setParameter = (key: string, value: string) => {
|
||||
const next = new URLSearchParams(parameters);
|
||||
next.set(key, value);
|
||||
setParams(next, { replace: true });
|
||||
setParameters(next, { replace: true });
|
||||
};
|
||||
const chartData =
|
||||
candles.data?.candles.map((candle) => ({
|
||||
const chartData
|
||||
= candles.data?.candles.map(candle => ({
|
||||
...candle,
|
||||
date: formatDate(candle.time),
|
||||
price: Number(candle.close),
|
||||
})) ?? [];
|
||||
const average = position.data?.averagePurchasePrice;
|
||||
const averageLine =
|
||||
average && average.currency === candles.data?.currency
|
||||
const averageLine
|
||||
= average && average.currency === candles.data?.currency
|
||||
? Number(average.value)
|
||||
: null;
|
||||
: /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null;
|
||||
const companyData = company.data;
|
||||
const search = parameters.size > 0 ? `?${parameters.toString()}` : "";
|
||||
return {
|
||||
refresh: sync.refresh,
|
||||
refreshing: sync.refreshing,
|
||||
refreshError: sync.transportError || sync.sourceError,
|
||||
averageLine:
|
||||
averageLine !== null && Number.isFinite(averageLine) ? averageLine : /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null,
|
||||
candles: candles.data,
|
||||
candlesState: section(candles, sync.retry),
|
||||
canonicalTo:
|
||||
stock.data?.slug && stock.data.slug !== stockId
|
||||
? `/stocks/${encodeURIComponent(stock.data.slug)}${params.size ? `?${params.toString()}` : ""}`
|
||||
: null,
|
||||
stock: stock.data,
|
||||
stockState: section(stock, uid ? sync.retry : () => stock.refetch()),
|
||||
code: apiErrorCode(stock.error),
|
||||
logoSrc: instrumentLogoUrl(stock.data?.logoName),
|
||||
quote: quote.data,
|
||||
quoteState: section(quote, sync.retry),
|
||||
candles: candles.data,
|
||||
? `/stocks/${encodeURIComponent(stock.data.slug)}${search}`
|
||||
: /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null,
|
||||
chartData,
|
||||
priceRows: chartData.toReversed(),
|
||||
candlesState: section(candles, sync.retry),
|
||||
period,
|
||||
setPeriod: (value: string) => setParam("period", value),
|
||||
averageLine:
|
||||
averageLine !== null && Number.isFinite(averageLine) ? averageLine : null,
|
||||
hasIncompleteCandle:
|
||||
candles.data?.candles.some((candle) => !candle.isComplete) ?? false,
|
||||
position: position.data,
|
||||
positionState: section(position, sync.retry),
|
||||
code: apiErrorCode(stock.error),
|
||||
company: companyData,
|
||||
companyState: section(company, sync.retry),
|
||||
dividends: dividends.data,
|
||||
dividendsState: section(dividends, sync.retry),
|
||||
upcoming:
|
||||
dividends.data?.dividends
|
||||
.filter((event) => event.timing === "upcoming")
|
||||
.sort((a, b) =>
|
||||
(a.recordDate ?? a.paymentDate ?? "").localeCompare(
|
||||
b.recordDate ?? b.paymentDate ?? "",
|
||||
),
|
||||
) ?? [],
|
||||
pastDividends:
|
||||
dividends.data?.dividends
|
||||
.filter((event) => event.timing !== "upcoming")
|
||||
.sort((a, b) =>
|
||||
(b.recordDate ?? b.paymentDate ?? "").localeCompare(
|
||||
a.recordDate ?? a.paymentDate ?? "",
|
||||
),
|
||||
) ?? [],
|
||||
eventRows:
|
||||
operations.data?.items.map(item => ({
|
||||
...item,
|
||||
logoName: item.logoName ?? stock.data?.logoName ?? /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null,
|
||||
ticker: item.ticker ?? stock.data?.ticker ?? /* eslint-disable-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model. */ null,
|
||||
})) ?? [],
|
||||
filter,
|
||||
hasIncompleteCandle:
|
||||
candles.data?.candles.some(candle => !candle.isComplete) ?? false,
|
||||
hasPrevious: history.hasPrevious,
|
||||
logoSrc: instrumentLogoUrl(stock.data?.logoName),
|
||||
onNext: history.onNext,
|
||||
onPrevious: history.onPrevious,
|
||||
operations: operations.data,
|
||||
operationsState: {
|
||||
...section(operations, sync.retry),
|
||||
retry: () => history.retry(sync.retry),
|
||||
},
|
||||
eventRows:
|
||||
operations.data?.items.map((item) => ({
|
||||
...item,
|
||||
ticker: item.ticker ?? stock.data?.ticker ?? null,
|
||||
logoName: item.logoName ?? stock.data?.logoName ?? null,
|
||||
})) ?? [],
|
||||
filter,
|
||||
setFilter: (value: string) => setParam("events", value),
|
||||
hasPrevious: history.hasPrevious,
|
||||
onPrevious: history.onPrevious,
|
||||
onNext: history.onNext,
|
||||
pastDividends:
|
||||
dividends.data?.dividends
|
||||
.filter(event => event.timing !== "upcoming")
|
||||
.toSorted((a, b) =>
|
||||
(b.recordDate ?? b.paymentDate ?? "").localeCompare(
|
||||
a.recordDate ?? a.paymentDate ?? "",
|
||||
),
|
||||
) ?? [],
|
||||
period,
|
||||
position: position.data,
|
||||
positionState: section(position, sync.retry),
|
||||
priceRows: chartData.toReversed(),
|
||||
quote: quote.data,
|
||||
quoteState: section(quote, sync.retry),
|
||||
refresh: sync.refresh,
|
||||
refreshError: sync.transportError || sync.sourceError,
|
||||
refreshing: sync.refreshing,
|
||||
setFilter: (value: string) => setParameter("events", value),
|
||||
setPeriod: (value: string) => setParameter("period", value),
|
||||
stock: stock.data,
|
||||
stockState: section(stock, uid ? sync.retry : () => stock.refetch()),
|
||||
upcoming:
|
||||
dividends.data?.dividends
|
||||
.filter(event => event.timing === "upcoming")
|
||||
.toSorted((a, b) =>
|
||||
(a.recordDate ?? a.paymentDate ?? "").localeCompare(
|
||||
b.recordDate ?? b.paymentDate ?? "",
|
||||
),
|
||||
) ?? [],
|
||||
};
|
||||
}
|
||||
type StockPageVm = ReturnType<typeof useStockPageVm>;
|
||||
|
||||
export { type StockPageVm, useStockPageVm };
|
||||
|
||||
Reference in New Issue
Block a user