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
+322 -290
View File
@@ -1,3 +1,5 @@
import type { FC } from "react";
import {
Accordion,
Alert,
@@ -13,8 +15,8 @@ import {
Title,
} from "@mantine/core";
import { LoadingSkeleton } from "@wealthledger/ui";
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import {
InstrumentChart,
InstrumentEvents,
@@ -27,133 +29,143 @@ import {
formatMoney,
formatSnapshotTime,
} from "@/shared/lib";
import classes from "./BondPage.module.css";
import type { BondPageVm } from "./BondPage.vm";
import classes from "./BondPage.module.css";
type BondPageViewProps = { vm: BondPageVm };
const BondPageView: FC<BondPageViewProps> = (props) => {
const { vm } = props;
const { t } = useTranslation();
const bond = vm.bond;
if (!bond) return null;
if (!bond) return;
const maturity = bond.maturityDate ? formatDate(bond.maturityDate) : t("bond.unknown");
return (
<Stack className={classes.page} gap="lg">
<Paper component="header" className={classes.section} withBorder>
<Group justify="space-between" align="start">
<Paper className={classes.section} component="header" withBorder>
<Group align="start" justify="space-between">
<div className={classes.identity}>
<Avatar src={vm.logoSrc} alt="" size={56} radius="md">
<Avatar alt="" radius="md" size={56} src={vm.logoSrc}>
{bond.name[0]}
</Avatar>
<div>
<Title order={1} size="h2">
{bond.name}
</Title>
<Text size="sm" c="dimmed">
{bond.ticker} · {bond.isin}
<Text c="dimmed" size="sm">
{bond.ticker}
{" "}
·
{" "}
{bond.isin}
</Text>
</div>
</div>
<Button
variant="subtle"
onClick={vm.refresh}
disabled={vm.refreshing}
onClick={vm.refresh}
variant="subtle"
>
{t("investment.refresh")}
</Button>
</Group>
<Group mt="md" gap="xs">
{bond.floatingCoupon ? (
<Group gap="xs" mt="md">
{!!(bond.floatingCoupon) && ((
<Badge variant="light">{t("bond.floatingCoupon")}</Badge>
) : null}
{bond.amortization ? (
))}
{!!(bond.amortization) && ((
<Badge variant="light">{t("bond.amortization")}</Badge>
) : null}
{bond.perpetual ? (
))}
{!!(bond.perpetual) && ((
<Badge variant="light">{t("bond.perpetual")}</Badge>
) : null}
{bond.subordinated ? (
<Badge variant="light" color="orange">
))}
{!!(bond.subordinated) && ((
<Badge color="orange" variant="light">
{t("bond.subordinated")}
</Badge>
) : null}
))}
</Group>
{vm.refreshError || vm.bondState.error || vm.quoteState.error ? (
<Alert role="status" aria-live="polite" color="orange" mt="md">
{!!(vm.refreshError || vm.bondState.error || vm.quoteState.error) && ((
<Alert aria-live="polite" color="orange" mt="md" role="status">
{t(vm.quote ? "accounts.refreshError" : "stock.sectionError")}
</Alert>
) : null}
{vm.quoteState.loading ? (
<LoadingSkeleton label={t("stock.loadingPrice")}>
<Skeleton mt="lg" h={55} w="50%" />
</LoadingSkeleton>
) : (
<Stack gap="xs" mt="lg" aria-live="polite">
<Text size="sm" c="dimmed">
{t("bond.percentOfNominal")}
</Text>
<Text className={classes.price}>
{vm.quote?.pricePercent != null
? `${formatDecimal(vm.quote.pricePercent)} %`
: t("bond.unknown")}
</Text>
{vm.quote?.changePercentagePoints != null ? (
<Text fw={600}>
{formatDecimal(vm.quote.changePercentagePoints)}{" "}
{t("bond.percentagePoints")}
</Text>
) : null}
<Text size="xs" c="dimmed">
{vm.quote?.previousCloseDate
? t("stock.changeBase", {
date: formatDate(vm.quote.previousCloseDate),
})
: t("stock.noComparison")}
</Text>
<Group gap="xl" my="sm">
<Metric
label={t("bond.cleanPrice")}
value={formatMoney(vm.quote?.cleanPrice ?? null)}
/>
<Metric
label={t("bond.aci")}
value={formatMoney(vm.quote?.aci ?? null)}
/>
<Metric
label={t("bond.dirtyPrice")}
value={formatMoney(vm.quote?.dirtyPrice ?? null)}
/>
</Group>
<Text size="xs" c="dimmed">
{t("bond.indicativePrice")}
</Text>
<Group>
<Badge color="gray" variant="light">
{t(`stock.trading.${vm.quote?.tradingStatus}`, {
defaultValue: t("stock.trading.unknown"),
})}
</Badge>
{vm.quote?.priceAt ? (
<Text size="xs" c="dimmed">
{t("stock.priceAt", {
date: formatSnapshotTime(vm.quote.priceAt),
})}
))}
{vm.quoteState.loading
? (
<LoadingSkeleton label={t("stock.loadingPrice")}>
<Skeleton h={55} mt="lg" w="50%" />
</LoadingSkeleton>
)
: (
<Stack aria-live="polite" gap="xs" mt="lg">
<Text c="dimmed" size="sm">
{t("bond.percentOfNominal")}
</Text>
) : null}
</Group>
{vm.quote?.unavailable.length ? (
<Text size="xs" c="dimmed">
{t("stock.partialQuote")}
</Text>
) : null}
</Stack>
)}
{vm.quoteState.refreshing || vm.bondState.refreshing ? (
<Text role="status" size="xs" c="dimmed">
<Text className={classes.price}>
{vm.quote?.pricePercent == undefined
? t("bond.unknown")
: `${formatDecimal(vm.quote.pricePercent)} %`}
</Text>
{vm.quote?.changePercentagePoints != undefined && ((
<Text fw={600}>
{formatDecimal(vm.quote.changePercentagePoints)}
{" "}
{t("bond.percentagePoints")}
</Text>
))}
<Text c="dimmed" size="xs">
{vm.quote?.previousCloseDate
? t("stock.changeBase", {
date: formatDate(vm.quote.previousCloseDate),
})
: t("stock.noComparison")}
</Text>
<Group gap="xl" my="sm">
<Metric
label={t("bond.cleanPrice")}
value={formatMoney(vm.quote?.cleanPrice)}
/>
<Metric
label={t("bond.aci")}
value={formatMoney(vm.quote?.aci)}
/>
<Metric
label={t("bond.dirtyPrice")}
value={formatMoney(vm.quote?.dirtyPrice)}
/>
</Group>
<Text c="dimmed" size="xs">
{t("bond.indicativePrice")}
</Text>
<Group>
<Badge color="gray" variant="light">
{t(`stock.trading.${vm.quote?.tradingStatus}`, {
defaultValue: t("stock.trading.unknown"),
})}
</Badge>
{!!(vm.quote?.priceAt) && ((
<Text c="dimmed" size="xs">
{t("stock.priceAt", {
date: formatSnapshotTime(vm.quote.priceAt),
})}
</Text>
))}
</Group>
{!!(vm.quote?.unavailable.length) && ((
<Text c="dimmed" size="xs">
{t("stock.partialQuote")}
</Text>
))}
</Stack>
)}
{!!(vm.quoteState.refreshing || vm.bondState.refreshing) && ((
<Text c="dimmed" role="status" size="xs">
{t("accounts.refreshing")}
</Text>
) : null}
))}
<div className={classes.embeddedSection}>
<Title order={2} size="h3" mb="md">
<Title mb="md" order={2} size="h3">
{t("bond.terms")}
</Title>
<div className={classes.companyMetrics}>
@@ -170,9 +182,7 @@ const BondPageView: FC<BondPageViewProps> = (props) => {
value={
bond.perpetual
? t("bond.perpetual")
: bond.maturityDate
? formatDate(bond.maturityDate)
: t("bond.unknown")
: maturity
}
/>
<Metric
@@ -184,207 +194,226 @@ const BondPageView: FC<BondPageViewProps> = (props) => {
<Metric
label={t("bond.couponFrequency")}
value={
bond.couponQuantityPerYear != null
? String(bond.couponQuantityPerYear)
: t("bond.unknown")
bond.couponQuantityPerYear == undefined
? t("bond.unknown")
: String(bond.couponQuantityPerYear)
}
/>
<Metric
label={t("bond.lot")}
value={bond.lot != null ? String(bond.lot) : t("bond.unknown")}
value={bond.lot == undefined ? t("bond.unknown") : String(bond.lot)}
/>
</div>
</div>
</Paper>
<InstrumentSection title={t("bond.metrics")} state={vm.metricsState}>
{vm.metrics ? (
<Stack gap="md">
<div className={classes.companyMetrics}>
<Metric
label={t("bond.creditRating")}
value={
vm.metrics.creditRating
? vm.metrics.creditRating.status === "withdrawn"
? t("bond.ratingWithdrawn")
: (vm.metrics.creditRating.value ?? t("bond.unknown"))
: vm.metrics.unavailable.includes("rating")
? t("bond.ratingUnavailable")
: t("bond.ratingMissing")
}
/>
<Metric
label={t("bond.couponAmount")}
value={formatMoney(vm.metrics.coupon)}
/>
<Metric
label={t("bond.couponType")}
value={t(`bond.couponTypes.${vm.metrics.couponType}`, {
defaultValue: t("bond.unknown"),
})}
/>
<Metric
label={t("bond.couponDate")}
value={
vm.metrics.couponDate
? formatDate(vm.metrics.couponDate)
: t("bond.unknown")
}
/>
<Metric
label={t("bond.effectiveYield")}
value={
vm.metrics.effectiveYield
? `${formatDecimal(vm.metrics.effectiveYield.value)} %`
: t("bond.unknown")
}
/>
<Metric
label={t("bond.couponYield")}
value={
vm.metrics.couponYieldPercent !== null
? `${formatDecimal(vm.metrics.couponYieldPercent)} %`
: t("bond.unknown")
}
/>
</div>
{vm.metrics.creditRating ? (
<Group gap="xs">
<Anchor
href={vm.metrics.creditRating.sourceUrl}
target="_blank"
rel="noopener noreferrer"
size="sm"
>
{t("bond.ratingSource", {
date: formatDate(vm.metrics.creditRating.date),
})}
</Anchor>
<Text size="xs" c="dimmed">
{t("bond.ratingChecked", {
date: formatSnapshotTime(
vm.metrics.creditRating.observedAt,
),
})}
</Text>
</Group>
) : null}
<Text size="xs" c="dimmed">
{t("bond.ratingCoverage")}
</Text>
{vm.metrics.effectiveYield ? (
<Text size="xs" c="dimmed">
{t("bond.yieldSource", {
target: t(
`bond.yieldTargets.${vm.metrics.effectiveYield.dateType}`,
{ defaultValue: t("bond.yieldTargets.unknown") },
),
date: formatDate(vm.metrics.effectiveYield.date),
price: formatDecimal(vm.metrics.effectiveYield.pricePercent),
at: formatSnapshotTime(vm.metrics.effectiveYield.tradeAt),
})}
</Text>
) : (
<Text size="xs" c="dimmed">
{t("bond.yieldUnavailable")}
</Text>
)}
<Text size="xs" c="dimmed">
{t("bond.couponYieldNote")}
</Text>
{vm.metrics.couponYieldPriceAt ? (
<Text size="xs" c="dimmed">
{t("bond.couponYieldPriceAt", {
date: formatSnapshotTime(vm.metrics.couponYieldPriceAt),
})}
</Text>
) : null}
{vm.metrics.unavailable.length ? (
<Text size="xs" c="dimmed">
{t("bond.metricsPartial")}
</Text>
) : null}
</Stack>
) : null}
</InstrumentSection>
<InstrumentChart vm={vm} priceUnit="percent" />
<BondMetrics vm={vm} />
<InstrumentChart priceUnit="percent" vm={vm} />
<InstrumentPosition
vm={vm}
returnNote={t("bond.returnNote")}
quantityLabel={t("bond.quantity")}
/>
<InstrumentSection
title={t("bond.upcomingCoupons")}
state={vm.couponsState}
>
{vm.coupons ? (
<Stack gap="md">
{vm.coupons.estimateUnavailable || vm.coupons.positionIsStale ? (
<Alert color="orange" role="status" aria-live="polite">
{t("stock.estimateUnavailable")}
</Alert>
) : null}
{vm.upcoming.length ? (
vm.upcoming.map((coupon) => (
<Coupon
key={`${coupon.number}:${coupon.paymentDate}`}
coupon={coupon}
/>
))
) : (
<Text c="dimmed">{t("bond.noCoupons")}</Text>
)}
<Text size="xs" c="dimmed">
{t("bond.couponWindow", {
from: formatDate(vm.coupons.from),
to: formatDate(vm.coupons.to),
})}
</Text>
<Text size="xs" c="dimmed">
{t("bond.couponNote")}
</Text>
{vm.coupons.positionAt ? (
<Text size="xs" c="dimmed">
{t("stock.snapshotAt", {
date: formatSnapshotTime(vm.coupons.positionAt),
})}
</Text>
) : null}
<Accordion variant="contained" radius="md">
<Accordion.Item value="history">
<Accordion.Control>{t("bond.couponHistory")}</Accordion.Control>
<Accordion.Panel>
<Stack gap="sm">
{vm.pastCoupons.length ? (
vm.pastCoupons.map((coupon) => (
<Coupon
key={`${coupon.number}:${coupon.paymentDate}`}
coupon={coupon}
/>
))
) : (
<Text c="dimmed">{t("bond.noCoupons")}</Text>
)}
</Stack>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Stack>
) : null}
</InstrumentSection>
<InstrumentEvents
returnNote={t("bond.returnNote")}
vm={vm}
incomeLabel={t("bond.coupons")}
incomeFilter="coupons"
/>
<BondCoupons vm={vm} />
<InstrumentEvents
historyNote={t("bond.historyNote")}
incomeFilter="coupons"
incomeLabel={t("bond.coupons")}
vm={vm}
/>
</Stack>
);
};
const BondMetrics: FC<BondPageViewProps> = (props) => {
const { vm } = props;
const { t } = useTranslation();
const creditRating = vm.metrics?.creditRating;
let rating = t(vm.metrics?.unavailable.includes("rating") ? "bond.ratingUnavailable" : "bond.ratingMissing");
if (creditRating) rating = creditRating.status === "withdrawn" ? t("bond.ratingWithdrawn") : (creditRating.value ?? t("bond.unknown"));
return (
<InstrumentSection state={vm.metricsState} title={t("bond.metrics")}>
{!!(vm.metrics) && ((
<Stack gap="md">
<div className={classes.companyMetrics}>
<Metric
label={t("bond.creditRating")}
value={
rating
}
/>
<Metric
label={t("bond.couponAmount")}
value={formatMoney(vm.metrics.coupon)}
/>
<Metric
label={t("bond.couponType")}
value={t(`bond.couponTypes.${vm.metrics.couponType}`, {
defaultValue: t("bond.unknown"),
})}
/>
<Metric
label={t("bond.couponDate")}
value={
vm.metrics.couponDate
? formatDate(vm.metrics.couponDate)
: t("bond.unknown")
}
/>
<Metric
label={t("bond.effectiveYield")}
value={
vm.metrics.effectiveYield
? `${formatDecimal(vm.metrics.effectiveYield.value)} %`
: t("bond.unknown")
}
/>
<Metric
label={t("bond.couponYield")}
value={
vm.metrics.couponYieldPercent === null
? t("bond.unknown")
: `${formatDecimal(vm.metrics.couponYieldPercent)} %`
}
/>
</div>
{!!(vm.metrics.creditRating) && ((
<Group gap="xs">
<Anchor
href={vm.metrics.creditRating.sourceUrl}
rel="noopener noreferrer"
size="sm"
target="_blank"
>
{t("bond.ratingSource", {
date: formatDate(vm.metrics.creditRating.date),
})}
</Anchor>
<Text c="dimmed" size="xs">
{t("bond.ratingChecked", {
date: formatSnapshotTime(
vm.metrics.creditRating.observedAt,
),
})}
</Text>
</Group>
))}
<Text c="dimmed" size="xs">
{t("bond.ratingCoverage")}
</Text>
{vm.metrics.effectiveYield
? (
<Text c="dimmed" size="xs">
{t("bond.yieldSource", {
at: formatSnapshotTime(vm.metrics.effectiveYield.tradeAt),
date: formatDate(vm.metrics.effectiveYield.date),
price: formatDecimal(vm.metrics.effectiveYield.pricePercent),
target: t(
`bond.yieldTargets.${vm.metrics.effectiveYield.dateType}`,
{ defaultValue: t("bond.yieldTargets.unknown") },
),
})}
</Text>
)
: (
<Text c="dimmed" size="xs">
{t("bond.yieldUnavailable")}
</Text>
)}
<Text c="dimmed" size="xs">
{t("bond.couponYieldNote")}
</Text>
{!!(vm.metrics.couponYieldPriceAt) && ((
<Text c="dimmed" size="xs">
{t("bond.couponYieldPriceAt", {
date: formatSnapshotTime(vm.metrics.couponYieldPriceAt),
})}
</Text>
))}
{vm.metrics.unavailable.length > 0 && ((
<Text c="dimmed" size="xs">
{t("bond.metricsPartial")}
</Text>
))}
</Stack>
))}
</InstrumentSection>
);
};
const BondCoupons: FC<BondPageViewProps> = (props) => {
const { vm } = props;
const { t } = useTranslation();
return (
<InstrumentSection
state={vm.couponsState}
title={t("bond.upcomingCoupons")}
>
{!!(vm.coupons) && ((
<Stack gap="md">
{!!(vm.coupons.estimateUnavailable || vm.coupons.positionIsStale) && ((
<Alert aria-live="polite" color="orange" role="status">
{t("stock.estimateUnavailable")}
</Alert>
))}
{vm.upcoming.length > 0
? (
vm.upcoming.map(coupon => (
<Coupon
coupon={coupon}
key={`${coupon.number}:${coupon.paymentDate}`}
/>
))
)
: (
<Text c="dimmed">{t("bond.noCoupons")}</Text>
)}
<Text c="dimmed" size="xs">
{t("bond.couponWindow", {
from: formatDate(vm.coupons.from),
to: formatDate(vm.coupons.to),
})}
</Text>
<Text c="dimmed" size="xs">
{t("bond.couponNote")}
</Text>
{!!(vm.coupons.positionAt) && ((
<Text c="dimmed" size="xs">
{t("stock.snapshotAt", {
date: formatSnapshotTime(vm.coupons.positionAt),
})}
</Text>
))}
<Accordion radius="md" variant="contained">
<Accordion.Item value="history">
<Accordion.Control>{t("bond.couponHistory")}</Accordion.Control>
<Accordion.Panel>
<Stack gap="sm">
{vm.pastCoupons.length > 0
? (
vm.pastCoupons.map(coupon => (
<Coupon
coupon={coupon}
key={`${coupon.number}:${coupon.paymentDate}`}
/>
))
)
: (
<Text c="dimmed">{t("bond.noCoupons")}</Text>
)}
</Stack>
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Stack>
))}
</InstrumentSection>
);
};
type MetricProps = { label: string; value: string };
const Metric: FC<MetricProps> = (props) => (
const Metric: FC<MetricProps> = props => (
<div>
<Text size="xs" c="dimmed">
<Text c="dimmed" size="xs">
{props.label}
</Text>
<Text fw={600} size="lg">
@@ -399,44 +428,47 @@ const Coupon: FC<CouponProps> = (props) => {
const { coupon } = props;
const { t } = useTranslation();
return (
<Paper withBorder p="md" radius="md">
<Group justify="space-between" align="start">
<Paper p="md" radius="md" withBorder>
<Group align="start" justify="space-between">
<div>
<Text fw={600}>
{coupon.paymentDate
? formatDate(coupon.paymentDate)
: t("stock.dateUnknown")}
</Text>
<Text size="xs" c="dimmed">
<Text c="dimmed" size="xs">
{t("bond.couponNumber", {
number: coupon.number ?? t("bond.unknown"),
})}
</Text>
</div>
<Metric label={t("bond.perBond")} value={formatMoney(coupon.perBond)} />
{coupon.estimatedAmount ? (
{!!(coupon.estimatedAmount) && ((
<Metric
label={t("stock.yourEstimate")}
value={formatMoney(coupon.estimatedAmount)}
/>
) : null}
))}
</Group>
<Group mt="sm" gap="md">
<Badge variant="light" color="gray">
<Group gap="md" mt="sm">
<Badge color="gray" variant="light">
{t(`bond.couponTypes.${coupon.couponType}`, {
defaultValue: t("bond.unknown"),
})}
</Badge>
{coupon.periodDays != null ? (
<Text size="xs" c="dimmed">
{coupon.periodDays != undefined && ((
<Text c="dimmed" size="xs">
{t("bond.couponDays", { count: coupon.periodDays })}
</Text>
) : null}
{coupon.recordDate ? (
<Text size="xs" c="dimmed">
{t("stock.record")}: {formatDate(coupon.recordDate)}
))}
{!!(coupon.recordDate) && ((
<Text c="dimmed" size="xs">
{t("stock.record")}
:
{" "}
{formatDate(coupon.recordDate)}
</Text>
) : null}
))}
</Group>
</Paper>
);