Frontend security / security (push) Successful in 9s
Frontend verify / verify (push) Failing after 37m50s
Frontend security / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Failing after 42m10s
Conventional commits / commits (pull_request) Successful in 29s
Enable every plugin recommended preset and replace Biome with ESLint formatting. Preserve API contracts and JSX whitespace; verify source, tests, builds and tooling.
72 lines
1.9 KiB
TypeScript
72 lines
1.9 KiB
TypeScript
import type {
|
|
BrokerageAccount,
|
|
useBrokerageAccounts,
|
|
} from "../api/useBrokerageAccounts";
|
|
|
|
const VISIBLE_CURRENCY_LIMIT = 2;
|
|
|
|
type BrokerageAccountCard = {
|
|
account: BrokerageAccount;
|
|
positionCounts: null | { bonds: number; stocks: number };
|
|
source?: NonNullable<
|
|
ReturnType<typeof useBrokerageAccounts>["meta"]
|
|
>["dependencies"] extends (infer T)[] | undefined
|
|
? T
|
|
: never;
|
|
summary:
|
|
| { remainingCurrencyCount: number; state: "available"; totals: Money[] }
|
|
| { state: "empty" }
|
|
| { state: "unavailable" };
|
|
};
|
|
|
|
type Money = NonNullable<
|
|
BrokerageAccount["portfolioSummary"]
|
|
>["totalsByCurrency"][number];
|
|
|
|
function accountTypeKey(type: BrokerageAccount["type"]) {
|
|
return `accounts.types.${type}` as const;
|
|
}
|
|
|
|
function brokerageAccountCards(
|
|
accounts: BrokerageAccount[],
|
|
dependencies: NonNullable<
|
|
ReturnType<typeof useBrokerageAccounts>["meta"]
|
|
>["dependencies"] = [],
|
|
): BrokerageAccountCard[] {
|
|
return accounts.map((account) => {
|
|
const source = dependencies.find(
|
|
item =>
|
|
item.resourceKey === `portfolio/${encodeURIComponent(account.id)}`,
|
|
);
|
|
const summary = account.portfolioSummary;
|
|
if (!summary)
|
|
return {
|
|
account,
|
|
positionCounts: /* eslint-disable-line unicorn/no-null -- The existing formatter contract uses null for unavailable data. */ null,
|
|
source,
|
|
summary: { state: "unavailable" },
|
|
};
|
|
const positionCounts = {
|
|
bonds: summary.bondPositionCount,
|
|
stocks: summary.stockPositionCount,
|
|
};
|
|
if (summary.totalsByCurrency.length === 0)
|
|
return { account, positionCounts, source, summary: { state: "empty" } };
|
|
return {
|
|
account,
|
|
positionCounts,
|
|
source,
|
|
summary: {
|
|
remainingCurrencyCount: Math.max(
|
|
summary.totalsByCurrency.length - VISIBLE_CURRENCY_LIMIT,
|
|
0,
|
|
),
|
|
state: "available",
|
|
totals: summary.totalsByCurrency.slice(0, VISIBLE_CURRENCY_LIMIT),
|
|
},
|
|
};
|
|
});
|
|
}
|
|
|
|
export { accountTypeKey, type BrokerageAccountCard, brokerageAccountCards };
|