refactor: address frontend review feedback
Frontend verify / commits (pull_request) Successful in 29s
Frontend verify / security (pull_request) Successful in 9s
Frontend verify / verify (pull_request) Successful in 8m54s
Frontend verify / commits (push) Skipped
Frontend verify / security (push) Successful in 12s
Frontend verify / verify (push) Successful in 9m59s

This commit was merged in pull request #43.
This commit is contained in:
2026-09-28 19:20:32 +03:00
parent ca0ad4f824
commit a4046dbe87
139 changed files with 1549 additions and 941 deletions
@@ -62,9 +62,7 @@ const AccountPageLoaded: FC<AccountPageLoadedProps> = (props) => {
sourceError={props.sourceError}
/>
{!!props.portfolio.isStale && (
<Alert color="blue">{t("portfolio.staleWarning")}</Alert>
)}
{!!props.portfolio.isStale && <Alert color="blue">{t("portfolio.staleWarning")}</Alert>}
<Text c="dimmed" size="sm">
{t(
@@ -78,12 +76,8 @@ const AccountPageLoaded: FC<AccountPageLoadedProps> = (props) => {
</Text>
{props.partial
? (
<Alert role="status">{t("investment.partial")}</Alert>
)
: (
<CurrencyCards amounts={props.portfolio.totalsByCurrency} />
)}
? <Alert role="status">{t("investment.partial")}</Alert>
: <CurrencyCards amounts={props.portfolio.totalsByCurrency} />}
{!props.partial && (
<PortfolioStructure
@@ -34,9 +34,7 @@ const AccountPageLoading: FC = () => {
<Skeleton height={260} radius="sm" />
{["first", "second", "third"].map(placeholder => (
<Skeleton height={52} key={placeholder} radius="sm" />
))}
{["first", "second", "third"].map(placeholder => <Skeleton height={52} key={placeholder} radius="sm" />)}
</LoadingSkeleton>
);
};
@@ -69,9 +69,7 @@ const IncomeSummary: FC<IncomeSummaryProps> = (props) => {
{!!props.stale && <Text size="xs">{t("investment.stale")}</Text>}
{!!props.refreshError && (
<Text role="status">{t("income.refreshError")}</Text>
)}
{!!props.refreshError && <Text role="status">{t("income.refreshError")}</Text>}
{props.summary.totalsByCurrency.map(total => (
<Paper key={total.currency} p="sm" withBorder>
@@ -81,13 +81,12 @@ export const Incomplete: Story = {
{
...rub,
categories: rub.categories.map(
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
row =>
({
...row,
sharePercent: null,
}),
/* eslint-enable unicorn/no-null */
),
},
],
@@ -110,14 +109,13 @@ export const Negative: Story = {
{
...rub,
categories: rub.categories.map(
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
row =>
({
...row,
sharePercent: null,
value: row.type === "OTHER" ? "25000" : row.value,
}),
/* eslint-enable unicorn/no-null */
),
hasNegativeValues: true,
totalValue: "1150000",
@@ -27,7 +27,6 @@ const ui = (structure: null | Portfolio["structure"] | undefined) => (
describe("portfolio structure", () => {
it.each([
undefined,
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
null,
])(
"keeps an older snapshot without structure available (%s) and recovers on refresh",
@@ -74,13 +73,12 @@ describe("portfolio structure", () => {
{
...rub,
categories: rub.categories.map(
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
row =>
({
...row,
sharePercent: null,
}),
/* eslint-enable unicorn/no-null */
),
},
],
@@ -106,14 +104,13 @@ describe("portfolio structure", () => {
{
...rub,
categories: rub.categories.map(
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
row =>
({
...row,
sharePercent: null,
value: row.type === "STOCK" ? "-60" : row.value,
}),
/* eslint-enable unicorn/no-null */
),
hasNegativeValues: true,
},
@@ -97,9 +97,7 @@ const PortfolioStructureView: FC<PortfolioStructureViewProps> = (props) => {
</Stack>
)}
{!!props.negative && (
<Text size="sm">{t("portfolio.structure.negative")}</Text>
)}
{!!props.negative && <Text size="sm">{t("portfolio.structure.negative")}</Text>}
{!!(
!props.unavailable
@@ -35,7 +35,7 @@ const usePortfolioStructureVm = (props: PortfolioStructureProps) => {
return {
chartData,
currencies: structure?.currencies.map(item => item.currency) ?? [],
// eslint-disable-next-line unicorn/no-null -- Mantine clears the controlled currency with null.
currency: selected?.currency ?? null,
incomplete: isIncomplete,
negative: selected?.hasNegativeValues ?? false,
@@ -4,8 +4,6 @@ import type { AccountPagePosition } from "../../AccountPage.vm";
import { PositionCard } from "./PositionCard.view";
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
const syntheticPosition
= {
absoluteReturn: { currency: "RUB", value: "5000" },
@@ -22,7 +20,7 @@ const syntheticPosition
shareText: "20%",
ticker: "DEMO",
type: "STOCK",
} satisfies /* eslint-enable unicorn/no-null */ AccountPagePosition;
} satisfies AccountPagePosition;
const meta = {
args: { kind: "stocks", position: syntheticPosition },
@@ -62,8 +60,6 @@ export const StockGain: Story = {
},
};
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
export const BondLoss: Story
= {
args: {
@@ -94,9 +90,6 @@ export const BondLoss: Story
},
},
};
/* eslint-enable unicorn/no-null */
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
export const Other: Story
= {
@@ -120,9 +113,6 @@ export const Other: Story
},
},
};
/* eslint-enable unicorn/no-null */
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
export const MissingValuation: Story
= {
@@ -149,4 +139,3 @@ export const MissingValuation: Story
},
},
};
/* eslint-enable unicorn/no-null */
@@ -60,10 +60,10 @@ const PositionCard: FC<PositionCardProps> = (props) => {
? t("portfolio.avgPrice", {
value: formatMoney(position.averagePurchasePrice),
})
: null, // eslint-disable-line unicorn/no-null -- Mantine represents an empty controlled field as null.
: null,
position.shareText
? t("portfolio.share", { value: position.shareText })
: null, // eslint-disable-line unicorn/no-null -- Mantine represents an empty controlled field as null.
: null,
]
.filter(Boolean)
.join(" · ");
@@ -44,9 +44,7 @@ const PositionGroupCard: FC<PositionGroupCardProps> = (props) => {
{identity.displayName}
</Anchor>
)
: (
<Text fw={600}>{identity.displayName}</Text>
)}
: <Text fw={600}>{identity.displayName}</Text>}
<Text c="dimmed" size="xs">
{identity.ticker ?? identity.isin ?? identity.figi}
@@ -90,9 +88,7 @@ const PositionGroupCard: FC<PositionGroupCardProps> = (props) => {
</Group>
<Group gap="xs" justify="space-between">
{!!position.currentValue && (
<Text size="sm">{formatMoney(position.currentValue)}</Text>
)}
{!!position.currentValue && <Text size="sm">{formatMoney(position.currentValue)}</Text>}
{!!position.returnText && (
<Text className={appearanceClass} size="sm">
@@ -17,9 +17,7 @@ const PositionLogo: FC<PositionLogoProps> = (props) => {
const logo
= src && !failed
? (
<Avatar alt={label} onError={onError} radius="md" size={40} src={src} />
)
? <Avatar alt={label} onError={onError} radius="md" size={40} src={src} />
: (
<Avatar radius="md" size={40}>
{(label.trim()[0] ?? "?").toUpperCase()}
@@ -32,31 +32,21 @@ const RecentOperations: FC<RecentOperationsProps> = (props) => {
{!!operations.stale && <Text size="xs">{t("investment.stale")}</Text>}
{!!operations.refreshError && (
<Text role="status">{t("accounts.refreshError")}</Text>
)}
{!!operations.refreshError && <Text role="status">{t("accounts.refreshError")}</Text>}
</>
)}
{operations.state === "loading" && (
<LoadingSkeleton label={t("ledger.recentLoading")}>
{["first", "second", "third"].map(placeholder => (
<Skeleton height={48} key={placeholder} radius="sm" />
))}
{["first", "second", "third"].map(placeholder => <Skeleton height={48} key={placeholder} radius="sm" />)}
</LoadingSkeleton>
)}
{operations.state === "error" && (
<Alert color="red">{t("ledger.recentError")}</Alert>
)}
{operations.state === "error" && <Alert color="red">{t("ledger.recentError")}</Alert>}
{operations.state === "empty" && (
<Text c="dimmed">{t("ledger.recentEmpty")}</Text>
)}
{operations.state === "empty" && <Text c="dimmed">{t("ledger.recentEmpty")}</Text>}
{operations.state === "partial" && (
<Text role="status">{t("investment.partial")}</Text>
)}
{operations.state === "partial" && <Text role="status">{t("investment.partial")}</Text>}
{(operations.state === "loaded" || operations.state === "partial")
&& operations.items.map(operation => (