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:
2026-09-28 16:36:40 +03:00
committed by ksv741
parent 57630102e4
commit 72d7835227
253 changed files with 10059 additions and 8864 deletions
@@ -1,67 +1,75 @@
import { SimpleGrid } from "@mantine/core";
import type { Meta, StoryObj } from "@storybook/react-vite";
import { SimpleGrid } from "@mantine/core";
import { BankCardFace } from "./BankCardFace";
const meta = {
title: "Product/BankCards/CardAppearance",
component: BankCardFace,
tags: ["autodocs"],
const meta = (/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
args: {
card: {
id: "fictional",
name: "Для повседневных покупок",
bankName: "Сбербанк",
lastFour: "4829",
paymentSystem: "mir",
openingBalance: { value: "0", currency: "RUB" },
openingDate: "2026-01-01",
balance: { value: "128450.75", currency: "RUB" },
archivedAt: null,
balance: { currency: "RUB", value: "128450.75" },
bankName: "Сбербанк",
id: "fictional",
lastFour: "4829",
name: "Для повседневных покупок",
openingBalance: { currency: "RUB", value: "0" },
openingDate: "2026-01-01",
paymentSystem: "mir",
version: 1,
},
},
} satisfies Meta<typeof BankCardFace>;
component: BankCardFace,
tags: ["autodocs"],
title: "Product/BankCards/CardAppearance",
}
/* eslint-enable unicorn/no-null */) satisfies Meta<typeof BankCardFace>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Banks: Story = {
render: (args) => (
render: arguments_ => (
<SimpleGrid cols={{ base: 1, sm: 2 }} maw={920}>
{["Сбербанк", "Т-Банк", "Альфа-Банк", "ВТБ", null].map(
{["Сбербанк", "Т-Банк", "Альфа-Банк", "ВТБ", /* eslint-disable-line unicorn/no-null -- Exercise the explicit null returned by the production API/DOM contract. */ null].map(
(bankName, index) => (
<BankCardFace
card={(/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
...arguments_.card,
bankName,
paymentSystem:
/* eslint-disable-line security/detect-object-injection -- This is a positional index into the local array, not a user-supplied object key. */ (["mir", "mastercard", "visa", "mir", null] as const)[index]
?? null,
}
/* eslint-enable unicorn/no-null */)}
key={bankName ?? "unknown"}
card={{
...args.card,
bankName,
paymentSystem:
(["mir", "mastercard", "visa", "mir", null] as const)[index] ??
null,
}}
/>
),
)}
</SimpleGrid>
),
};
export const MissingDetails: Story = {
args: {
card: {
...meta.args.card,
bankName: null,
lastFour: null,
paymentSystem: null,
export const MissingDetails: Story = (/* eslint-disable unicorn/no-null -- Fixture preserves the production contract’s explicit null values. */
{
args: {
card: {
...meta.args.card,
bankName: null,
lastFour: null,
paymentSystem: null,
},
},
},
};
}
/* eslint-enable unicorn/no-null */);
export const LongArchived: Story = {
args: {
card: {
...meta.args.card,
name: "Карта с очень длинным пользовательским названием для повседневных покупок",
bankName: "Банк с очень длинным названием без пробелов".repeat(2),
archivedAt: "2026-09-12",
balance: { currency: "RUB", value: "184467440737095516.14" },
bankName: "Банк с очень длинным названием без пробелов".repeat(2),
name: "Карта с очень длинным пользовательским названием для повседневных покупок",
paymentSystem: "mastercard",
balance: { value: "184467440737095516.14", currency: "RUB" },
},
},
};
@@ -1,7 +1,11 @@
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { formatMoney } from "@/shared/lib";
import type { BankCard } from "../../api/queries";
import classes from "./BankCardFace.module.css";
type BankCardFaceProps = { card: BankCard };
@@ -9,15 +13,7 @@ const BankCardFace: FC<BankCardFaceProps> = (props) => {
const { card } = props;
const { t } = useTranslation();
const bank = card.bankName?.toLocaleLowerCase("ru") ?? "";
const tone = /сбер|sber/.test(bank)
? "green"
: /тинькофф|т[ -]?банк|t[ -]?bank|tinkoff/.test(bank)
? "yellow"
: /альфа|alfa/.test(bank)
? "red"
: /втб|vtb|газпром|gazprom/.test(bank)
? "blue"
: "graphite";
const tone = bankTone(bank);
return (
<div className={classes.face} data-tone={tone}>
<div className={classes.top}>
@@ -26,26 +22,28 @@ const BankCardFace: FC<BankCardFaceProps> = (props) => {
<span className={classes.archive}>{t("bank.archived")}</span>
)}
</div>
<div className={classes.hardware} aria-hidden="true">
<div aria-hidden="true" className={classes.hardware}>
<span className={classes.chip} />
<svg
aria-hidden="true"
width="24"
fill="none"
height="30"
viewBox="0 0 24 30"
fill="none"
width="24"
>
<path
d="M7 11a8 8 0 0 1 0 8m5-12a15 15 0 0 1 0 16m5-20a23 23 0 0 1 0 24"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeWidth="2"
/>
</svg>
</div>
<div
className={classes.number}
>{`•••• •••• •••• ${card.lastFour || "••••"}`}</div>
>
{`•••• •••• •••• ${card.lastFour || "••••"}`}
</div>
<div className={classes.bottom}>
<div className={classes.details}>
<div className={classes.name}>{card.name}</div>
@@ -54,7 +52,7 @@ const BankCardFace: FC<BankCardFaceProps> = (props) => {
{card.paymentSystem && (
<span className={classes.network} data-network={card.paymentSystem}>
{card.paymentSystem === "mastercard" && (
<span className={classes.circles} aria-hidden="true" />
<span aria-hidden="true" className={classes.circles} />
)}
{t(`bank.paymentSystems.${card.paymentSystem}`)}
</span>
@@ -64,4 +62,11 @@ const BankCardFace: FC<BankCardFaceProps> = (props) => {
);
};
function bankTone(bank: string) {
if (/сбер|sber/.test(bank)) return "green";
if (/тинькофф|т[ -]?банк|t[ -]?bank|tinkoff/.test(bank)) return "yellow";
if (/альфа|alfa/.test(bank)) return "red";
return /втб|vtb|газпром|gazprom/.test(bank) ? "blue" : "graphite";
}
export { BankCardFace };