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
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:
@@ -38,8 +38,6 @@ import {
|
||||
} from "./AccountIncomePage.vm";
|
||||
import { IncomePayments } from "./components/IncomePayments.view";
|
||||
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
const analytics
|
||||
= {
|
||||
accountId: "account-1",
|
||||
@@ -81,7 +79,7 @@ const analytics
|
||||
},
|
||||
totalsByCurrency: [summary("RUB", "10", "2")],
|
||||
yearComparison: null,
|
||||
} satisfies /* eslint-enable unicorn/no-null */ IncomeAnalytics;
|
||||
} satisfies IncomeAnalytics;
|
||||
|
||||
function comparison(currency: string) {
|
||||
return {
|
||||
@@ -93,28 +91,24 @@ function comparison(currency: string) {
|
||||
}
|
||||
|
||||
function entry(): IncomeAnalytics["entries"][number] {
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
return (
|
||||
{
|
||||
accruedInterest: null,
|
||||
category: "income",
|
||||
commission: null,
|
||||
description: "Купон",
|
||||
figi: "FIGI",
|
||||
id: "coupon-1",
|
||||
instrumentKey: "income-group-opaque-v2",
|
||||
instrumentType: "bond",
|
||||
instrumentUid: null,
|
||||
logoName: null,
|
||||
occurredAt: "2026-08-01T12:00:00Z",
|
||||
payment: money("RUB", "10"),
|
||||
price: null,
|
||||
quantity: null,
|
||||
ticker: "BOND",
|
||||
type: "OPERATION_TYPE_COUPON",
|
||||
}
|
||||
/* eslint-enable unicorn/no-null */
|
||||
);
|
||||
return {
|
||||
accruedInterest: null,
|
||||
category: "income",
|
||||
commission: null,
|
||||
description: "Купон",
|
||||
figi: "FIGI",
|
||||
id: "coupon-1",
|
||||
instrumentKey: "income-group-opaque-v2",
|
||||
instrumentType: "bond",
|
||||
instrumentUid: null,
|
||||
logoName: null,
|
||||
occurredAt: "2026-08-01T12:00:00Z",
|
||||
payment: money("RUB", "10"),
|
||||
price: null,
|
||||
quantity: null,
|
||||
ticker: "BOND",
|
||||
type: "OPERATION_TYPE_COUPON",
|
||||
};
|
||||
}
|
||||
|
||||
function money(currency: string, value: string) {
|
||||
@@ -211,7 +205,6 @@ describe("AccountIncomePage", () => {
|
||||
|
||||
return HttpResponse.json(
|
||||
resource(
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
null,
|
||||
{
|
||||
sync: {
|
||||
@@ -220,7 +213,6 @@ describe("AccountIncomePage", () => {
|
||||
state: "failed",
|
||||
},
|
||||
},
|
||||
/* eslint-enable unicorn/no-null */
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -434,7 +426,6 @@ describe("AccountIncomePage", () => {
|
||||
});
|
||||
|
||||
it("renders the signed drill-down using opaque membership rather than instrument identity", async () => {
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
const response
|
||||
= {
|
||||
...analytics,
|
||||
@@ -464,7 +455,6 @@ describe("AccountIncomePage", () => {
|
||||
],
|
||||
};
|
||||
|
||||
/* eslint-enable unicorn/no-null */
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/account-1/income-analytics", () =>
|
||||
HttpResponse.json(resource(response)),
|
||||
@@ -607,37 +597,31 @@ describe("income comparison display", () => {
|
||||
[
|
||||
"10",
|
||||
"0",
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
[
|
||||
"0",
|
||||
"0",
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
[
|
||||
"10",
|
||||
"-0.00",
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
[
|
||||
"10",
|
||||
"-100",
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
[
|
||||
"9".repeat(400),
|
||||
"1",
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"9".repeat(400),
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
null,
|
||||
],
|
||||
])("formats change %s against base %s", (difference, base, expected) => {
|
||||
@@ -656,7 +640,7 @@ describe("income comparison display", () => {
|
||||
const result = display?.comparison?.values[0];
|
||||
expect(
|
||||
result?.percentages.coupon?.replaceAll("\u{A0}", " ")
|
||||
// eslint-disable-next-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
|
||||
?? null,
|
||||
).toBe(expected);
|
||||
expect(result?.difference.coupon.value).toBe(difference);
|
||||
@@ -863,7 +847,7 @@ describe("income period and snapshot boundary", () => {
|
||||
),
|
||||
),
|
||||
http.get("*/api/v1/tbank-sync/:id", () =>
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
HttpResponse.json(
|
||||
{
|
||||
errorCode: null,
|
||||
@@ -874,7 +858,6 @@ describe("income period and snapshot boundary", () => {
|
||||
scope: null,
|
||||
state: "succeeded",
|
||||
},
|
||||
/* eslint-enable unicorn/no-null */
|
||||
),
|
||||
),
|
||||
http.get("*/api/v1/brokerage-accounts/account-1/income-analytics", () =>
|
||||
@@ -998,8 +981,6 @@ describe("income period and snapshot boundary", () => {
|
||||
it("maps comparison notices by role regardless of dependency order or resource key", () => {
|
||||
const selected = { ...resource(analytics).meta, role: "selected" as const };
|
||||
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
const previous
|
||||
= {
|
||||
...resource(null).meta,
|
||||
@@ -1012,7 +993,6 @@ it("maps comparison notices by role regardless of dependency order or resource k
|
||||
},
|
||||
};
|
||||
|
||||
/* eslint-enable unicorn/no-null */
|
||||
const year = {
|
||||
...resource(null).meta,
|
||||
resourceKey: "opaque/previous-looking-key",
|
||||
@@ -1041,10 +1021,10 @@ it.each([false, true])(
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/account-1/income-analytics", () =>
|
||||
HttpResponse.json(
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
resource(
|
||||
{ ...analytics, previous: null, yearComparison: null },
|
||||
/* eslint-enable unicorn/no-null */ {
|
||||
{
|
||||
dependencies: legacy
|
||||
? [
|
||||
resource(null).meta,
|
||||
@@ -1073,22 +1053,21 @@ it.each([false, true])(
|
||||
|
||||
it("shows selected income before comparison coverage without inventing a zero baseline", async () => {
|
||||
const dependencies = (["year", "selected", "previous"] as const).map(
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
role =>
|
||||
({
|
||||
...resource(role === "selected" ? analytics : null).meta,
|
||||
role,
|
||||
}),
|
||||
/* eslint-enable unicorn/no-null */
|
||||
);
|
||||
|
||||
server.use(
|
||||
http.get("*/api/v1/brokerage-accounts/account-1/income-analytics", () =>
|
||||
HttpResponse.json(
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
resource(
|
||||
{ ...analytics, previous: null, yearComparison: null },
|
||||
/* eslint-enable unicorn/no-null */ { dependencies },
|
||||
{ dependencies },
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1116,7 +1095,7 @@ it("keeps complete previous comparison while year source failed without inventin
|
||||
{
|
||||
...resource(analytics).meta,
|
||||
role: "previous" as const,
|
||||
/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
|
||||
|
||||
},
|
||||
{
|
||||
...resource(null).meta,
|
||||
@@ -1127,7 +1106,7 @@ it("keeps complete previous comparison while year source failed without inventin
|
||||
state: "failed" as const,
|
||||
},
|
||||
},
|
||||
/* eslint-enable unicorn/no-null */ {
|
||||
{
|
||||
...resource(analytics).meta,
|
||||
role: "selected" as const,
|
||||
},
|
||||
|
||||
@@ -12,12 +12,8 @@ const AccountIncomePage: FC<AccountIncomePageProps> = (props) => {
|
||||
if (viewModel.state === "loading") return <AccountIncomePageLoading />;
|
||||
|
||||
return viewModel.state === "error"
|
||||
? (
|
||||
<AccountIncomePageError {...viewModel} />
|
||||
)
|
||||
: (
|
||||
<AccountIncomePageLoaded {...viewModel} />
|
||||
);
|
||||
? <AccountIncomePageError {...viewModel} />
|
||||
: <AccountIncomePageLoaded {...viewModel} />;
|
||||
};
|
||||
|
||||
export { AccountIncomePage };
|
||||
|
||||
@@ -161,7 +161,6 @@ function comparisonDisplay(
|
||||
comparison: IncomeAnalytics["yearComparison"],
|
||||
): IncomeDisplayModel["comparison"] {
|
||||
if (!comparison)
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model.
|
||||
return null;
|
||||
|
||||
return {
|
||||
@@ -220,11 +219,9 @@ function formatIncomeChange(
|
||||
// Display-only ratio; server-provided Money values remain exact decimal strings.
|
||||
const base = Number(compared);
|
||||
if (!Number.isFinite(base) || base <= 0)
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model.
|
||||
return null;
|
||||
const ratio = Number(difference) / base;
|
||||
if (!Number.isFinite(ratio))
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model.
|
||||
return null;
|
||||
|
||||
return new Intl.NumberFormat("ru-RU", {
|
||||
@@ -272,7 +269,7 @@ function toIncomeDisplayModel(
|
||||
|| instruments.has(instrument.key)
|
||||
|| !currencies.has(instrument.total.currency)
|
||||
)
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the existing nullable validation/ref contract.
|
||||
|
||||
return null;
|
||||
instruments.set(instrument.key, {
|
||||
currency: instrument.total.currency,
|
||||
@@ -286,11 +283,9 @@ function toIncomeDisplayModel(
|
||||
|
||||
for (const entry of analytics.entries) {
|
||||
if (typeof entry.instrumentKey !== "string" || !entry.instrumentKey.trim())
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the existing nullable validation/ref contract.
|
||||
return null;
|
||||
const instrument = instruments.get(entry.instrumentKey);
|
||||
if (!instrument || entry.payment?.currency !== instrument.currency)
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the existing nullable validation/ref contract.
|
||||
return null;
|
||||
const occurrenceKey = JSON.stringify([entry.instrumentKey, entry.id]);
|
||||
const occurrence = occurrences.get(occurrenceKey) ?? 0;
|
||||
@@ -309,7 +304,6 @@ function toIncomeDisplayModel(
|
||||
|
||||
for (const instrument of instruments.values()) {
|
||||
if (instrument.includedCount !== instrument.receiptCount)
|
||||
// eslint-disable-next-line unicorn/no-null -- Preserve the nullable domain value consumed by this view model.
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
+2
-6
@@ -35,12 +35,8 @@ const AccountIncomePageLoadedSummary: FC<LoadedProps> = (props) => {
|
||||
}
|
||||
|
||||
return analytics.totalsByCurrency.length > 0
|
||||
? (
|
||||
<IncomeSummary totals={analytics.totalsByCurrency} />
|
||||
)
|
||||
: (
|
||||
<StateView text={t("income.emptyText")} title={t("income.emptyTitle")} />
|
||||
);
|
||||
? <IncomeSummary totals={analytics.totalsByCurrency} />
|
||||
: <StateView text={t("income.emptyText")} title={t("income.emptyTitle")} />;
|
||||
};
|
||||
|
||||
const AccountIncomePageLoaded: FC<LoadedProps> = (props) => {
|
||||
|
||||
@@ -34,9 +34,7 @@ const IncomeComparisons: FC<IncomeComparisonsProps> = (props) => {
|
||||
<Title order={2}>{props.title}</Title>
|
||||
|
||||
{props.comparison
|
||||
? (
|
||||
<Comparison {...props.comparison} title={props.title} />
|
||||
)
|
||||
? <Comparison {...props.comparison} title={props.title} />
|
||||
: (
|
||||
<Paper className={classes.comparisonNotice} p="sm" radius="md">
|
||||
<Text aria-live="polite" c="gray.7" role="status" size="sm">
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ const PeriodExample: FC<PeriodExampleProps> = (props) => {
|
||||
|
||||
const submitted = isSubmitSuccessful
|
||||
? methods.getValues()
|
||||
: null; // eslint-disable-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract.
|
||||
: null;
|
||||
|
||||
return (
|
||||
<FormProvider {...methods}>
|
||||
|
||||
Reference in New Issue
Block a user