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
+4 -2
View File
@@ -1,9 +1,11 @@
import type { FC } from "react";
import { MantineProvider } from "@mantine/core";
import { DatesProvider } from "@mantine/dates";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { cssVariablesResolver, theme } from "@wealthledger/ui/theme";
import type { FC } from "react";
import { BrowserRouter } from "react-router";
import { AppRoutes, RouteErrorBoundary } from "@/app/routes";
import { AuthProvider } from "@/features/auth";
@@ -17,8 +19,8 @@ const App: FC = () => {
return (
<MantineProvider
cssVariablesResolver={cssVariablesResolver}
theme={theme}
forceColorScheme="light"
theme={theme}
>
<DatesProvider settings={{ locale: "ru" }}>
<QueryClientProvider client={queryClient}>
@@ -1,6 +1,9 @@
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { useBrokerageAccounts } from "@/entities/brokerage-account";
import { BreadcrumbTrail } from "./BreadcrumbTrail";
type AccountBreadcrumbsProps = {
@@ -12,11 +15,11 @@ const AccountBreadcrumbs: FC<AccountBreadcrumbsProps> = (props) => {
const { accountId, section } = props;
const { data: accounts } = useBrokerageAccounts();
const { t } = useTranslation();
const accountName =
accountId === "all"
const accountName
= accountId === "all"
? t("accounts.all")
: (accounts?.find((account) => account.id === accountId)?.name ??
t("breadcrumbs.accountFallback"));
: (accounts?.find(account => account.id === accountId)?.name
?? t("breadcrumbs.accountFallback"));
const accountPath = `/accounts/${accountId}`;
const items = [
{ label: t("breadcrumbs.accounts"), to: "/accounts" },
@@ -1,7 +1,9 @@
import { Select } from "@mantine/core";
import type { FC } from "react";
import { Select } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router";
import { useBrokerageAccounts } from "@/entities/brokerage-account";
type AccountScopeSwitchProps = { accountId: string; section?: string };
@@ -13,31 +15,31 @@ const AccountScopeSwitch: FC<AccountScopeSwitchProps> = (props) => {
const navigate = useNavigate();
const { search } = useLocation();
const data = [
{ value: "all", label: t("accounts.all") },
...(accounts ?? []).map((account) => ({
value: account.id,
{ label: t("accounts.all"), value: "all" },
...(accounts ?? []).map(account => ({
label: account.name,
value: account.id,
})),
];
if (!data.some((item) => item.value === accountId))
data.push({ value: accountId, label: t("breadcrumbs.accountFallback") });
if (data.every(item => item.value !== accountId))
data.push({ label: t("breadcrumbs.accountFallback"), value: accountId });
return (
<Select
label={t("accounts.scope")}
value={accountId}
data={data}
allowDeselect={false}
data={data}
label={t("accounts.scope")}
maw={360}
w="100%"
onChange={(value) => {
if (!value || value === accountId) return;
const filters = new URLSearchParams(search);
filters.delete("cursor");
void navigate({
pathname: `/accounts/${encodeURIComponent(value)}${section ? `/${section}` : ""}`,
pathname: ["/accounts", encodeURIComponent(value), section].filter(Boolean).join("/"),
search: filters.toString(),
});
}}
value={accountId}
w="100%"
/>
);
};
@@ -2,6 +2,7 @@ import { MantineProvider } from "@mantine/core";
import { render, screen, within } from "@testing-library/react";
import { MemoryRouter } from "react-router";
import { afterEach, describe, expect, it, vi } from "vitest";
import { AppBreadcrumbs } from "./AppBreadcrumbs";
const { useBrokerageAccounts } = vi.hoisted(() => ({
+12 -12
View File
@@ -1,7 +1,9 @@
import { Stack } from "@mantine/core";
import type { FC } from "react";
import { Stack } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { useMatch } from "react-router";
import { AccountBreadcrumbs } from "./AccountBreadcrumbs";
import { AccountScopeSwitch } from "./AccountScopeSwitch";
import { BondBreadcrumbs } from "./BondBreadcrumbs";
@@ -12,19 +14,19 @@ import { StockBreadcrumbs } from "./StockBreadcrumbs";
const AppBreadcrumbs: FC = () => {
const { t } = useTranslation();
const operations = useMatch({
path: "/accounts/:accountId/operations",
end: true,
path: "/accounts/:accountId/operations",
});
const events = useMatch({ path: "/accounts/:accountId/events", end: true });
const income = useMatch({ path: "/accounts/:accountId/income", end: true });
const account = useMatch({ path: "/accounts/:accountId", end: true });
const events = useMatch({ end: true, path: "/accounts/:accountId/events" });
const income = useMatch({ end: true, path: "/accounts/:accountId/income" });
const account = useMatch({ end: true, path: "/accounts/:accountId" });
const card = useMatch("/cards/:cardId");
const cards = useMatch("/cards");
const accounts = useMatch({ path: "/accounts", end: true });
const settings = useMatch({ path: "/settings", end: true });
const accounts = useMatch({ end: true, path: "/accounts" });
const settings = useMatch({ end: true, path: "/settings" });
const stock = useMatch({ path: "/stocks/:stockId", end: true });
const bond = useMatch({ path: "/bonds/:bondId", end: true });
const stock = useMatch({ end: true, path: "/stocks/:stockId" });
const bond = useMatch({ end: true, path: "/bonds/:bondId" });
if (bond) return <BondBreadcrumbs identifier={bond.params.bondId ?? ""} />;
if (stock)
return <StockBreadcrumbs identifier={stock.params.stockId ?? ""} />;
@@ -78,9 +80,7 @@ const AppBreadcrumbs: FC = () => {
if (cards) return <BreadcrumbTrail items={[{ label: t("bank.title") }]} />;
if (accounts)
return <BreadcrumbTrail items={[{ label: t("breadcrumbs.accounts") }]} />;
if (settings)
return <BreadcrumbTrail items={[{ label: t("breadcrumbs.settings") }]} />;
return null;
return settings ? <BreadcrumbTrail items={[{ label: t("breadcrumbs.settings") }]} /> : undefined;
};
export { AppBreadcrumbs };
@@ -1,6 +1,9 @@
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { useBond } from "@/entities/bond";
import { BreadcrumbTrail } from "./BreadcrumbTrail";
type BondBreadcrumbsProps = { identifier: string };
+16 -12
View File
@@ -1,11 +1,13 @@
import { Breadcrumbs } from "@mantine/core";
import type { FC } from "react";
import { Breadcrumbs } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { Link } from "react-router";
import classes from "./AppBreadcrumbs.module.css";
type Crumb = { label: string; to?: string };
type BreadcrumbTrailProps = { items: Crumb[] };
type Crumb = { label: string; to?: string };
const BreadcrumbTrail: FC<BreadcrumbTrailProps> = (props) => {
const { items } = props;
@@ -18,16 +20,18 @@ const BreadcrumbTrail: FC<BreadcrumbTrailProps> = (props) => {
data-depth={items.length}
separator={<span aria-hidden="true">→</span>}
>
{items.map((item) =>
item.to ? (
<Link className={classes.link} key={item.to} to={item.to}>
{item.label}
</Link>
) : (
<span aria-current="page" key={item.label}>
{item.label}
</span>
),
{items.map(item =>
item.to
? (
<Link className={classes.link} key={item.to} to={item.to}>
{item.label}
</Link>
)
: (
<span aria-current="page" key={item.label}>
{item.label}
</span>
),
)}
</Breadcrumbs>
);
@@ -1,6 +1,9 @@
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { useBankCard } from "@/entities/bank-card";
import { BreadcrumbTrail } from "./BreadcrumbTrail";
type CardBreadcrumbsProps = { identifier: string };
@@ -1,6 +1,9 @@
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { useStock } from "@/entities/stock";
import { BreadcrumbTrail } from "./BreadcrumbTrail";
type StockBreadcrumbsProps = { identifier: string };
+40 -37
View File
@@ -1,8 +1,11 @@
import { AppShell as MantineAppShell, NavLink, Text } from "@mantine/core";
import type { FC, ReactNode } from "react";
import { AppShell as MantineAppShell, NavLink, Text } from "@mantine/core";
import { useTranslation } from "react-i18next";
import { Outlet, NavLink as RouterNavLink, useLocation } from "react-router";
import { bindIconAnimation } from "@/shared/lib";
import classes from "./AppShell.module.css";
type AppShellProps = {
@@ -15,9 +18,6 @@ const AppShell: FC<AppShellProps> = (props) => {
const { pathname } = useLocation();
const items = [
{
to: "/accounts",
label: t("navigation.accounts"),
iconClassName: classes.portfolioIcon,
icon: (
<>
<path d="M3 10v9h18v-9" />
@@ -32,11 +32,11 @@ const AppShell: FC<AppShellProps> = (props) => {
/>
</>
),
iconClassName: classes.portfolioIcon,
label: t("navigation.accounts"),
to: "/accounts",
},
{
to: "/cards",
label: t("navigation.cards"),
iconClassName: classes.cardsIcon,
icon: (
<>
<path d="M3 5h18v14H3V5Zm0 4h18M6 15h4" />
@@ -47,42 +47,42 @@ const AppShell: FC<AppShellProps> = (props) => {
</g>
</>
),
iconClassName: classes.cardsIcon,
label: t("navigation.cards"),
to: "/cards",
},
{
to: "/stocks",
label: t("navigation.stocks"),
iconClassName: classes.stocksIcon,
icon: (
<>
<path d="M3 3v18h18" />
<path
className={classes.drawStroke}
pathLength={1}
d="M7 14l5-5 4 3 5-7"
pathLength={1}
/>
<path className={classes.stockArrow} d="M16 5h5v5" />
</>
),
iconClassName: classes.stocksIcon,
label: t("navigation.stocks"),
to: "/stocks",
},
{
to: "/bonds",
label: t("navigation.bonds"),
iconClassName: classes.bondsIcon,
icon: (
<>
<path d="M6 3h12v18l-3-2-3 2-3-2-3 2V3Z" />
<g className={classes.couponLines}>
<path pathLength={1} d="M9 7h6" />
<path pathLength={1} d="M9 11h6" />
<path pathLength={1} d="M9 15h3" />
<path d="M9 7h6" pathLength={1} />
<path d="M9 11h6" pathLength={1} />
<path d="M9 15h3" pathLength={1} />
</g>
</>
),
iconClassName: classes.bondsIcon,
label: t("navigation.bonds"),
to: "/bonds",
},
{
to: "/settings",
label: t("navigation.settings"),
iconClassName: classes.settingsIcon,
icon: (
<>
<path d="M4 7h16M4 17h16" />
@@ -90,48 +90,51 @@ const AppShell: FC<AppShellProps> = (props) => {
<path className={classes.bottomSlider} d="M10 14v6h4v-6h-4Z" />
</>
),
iconClassName: classes.settingsIcon,
label: t("navigation.settings"),
to: "/settings",
},
];
return (
<MantineAppShell
header={{ height: 60 }}
navbar={{ width: 220, breakpoint: "sm", collapsed: { mobile: true } }}
navbar={{ breakpoint: "sm", collapsed: { mobile: true }, width: 220 }}
padding="md"
>
<MantineAppShell.Header className={classes.header}>
<Text fw={700}>{t("appName")}</Text>
</MantineAppShell.Header>
<MantineAppShell.Navbar p="sm">
{items.map((item) => (
{items.map(item => (
<NavLink
component={RouterNavLink}
active={pathname.startsWith(item.to)}
className={classes.navLink}
component={RouterNavLink}
key={item.to}
to={item.to}
label={item.label}
leftSection={
leftSection={(
<span
className={`${classes.navIcon} ${item.iconClassName ?? ""}`}
>
<svg
ref={bindIconAnimation}
width={20}
height={20}
viewBox="0 0 24 24"
aria-hidden="true"
fill="none"
focusable="false"
height={20}
ref={bindIconAnimation}
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
focusable="false"
strokeWidth="1.5"
viewBox="0 0 24 24"
width={20}
>
{item.icon}
</svg>
</span>
}
active={pathname.startsWith(item.to)}
)}
to={item.to}
/>
))}
</MantineAppShell.Navbar>
@@ -141,11 +144,11 @@ const AppShell: FC<AppShellProps> = (props) => {
<Outlet />
</div>
</MantineAppShell.Main>
<nav className={classes.bottomNav} aria-label={t("appName")}>
{items.map((item) => (
<nav aria-label={t("appName")} className={classes.bottomNav}>
{items.map(item => (
<RouterNavLink
className={
pathname.startsWith(item.to) ? classes.active : undefined
(pathname.startsWith(item.to)) ? (classes.active) : undefined
}
key={item.to}
to={item.to}