refactor: enforce frontend view model boundaries
Frontend verify / commits (pull_request) Successful in 28s
Frontend verify / security (pull_request) Successful in 10s
Frontend verify / verify (pull_request) Successful in 8m19s

This commit is contained in:
2026-09-28 18:48:23 +03:00
parent 5b69003516
commit ca0ad4f824
287 changed files with 8558 additions and 4538 deletions
@@ -19,100 +19,186 @@ import type { StockPageVm } from "../StockPage.vm";
import classes from "../StockPage.module.css";
type StockEventsProps = { vm: StockPageVm };
const StockDividends: FC<StockEventsProps> = (props) => {
const { vm } = props;
const { t } = useTranslation();
let upcomingContent;
if (vm.dividends) {
if (vm.upcoming.length > 0) {
upcomingContent = (
vm.upcoming.map(event => (
<div
className={classes.dividend}
key={JSON.stringify([
event.recordDate,
event.paymentDate,
event.perShare,
])}
>
<Group align="start" justify="space-between">
<div>
<Badge color="green" variant="light">
{t("stock.companyEvent")}
</Badge>
<Text fw={650} mt="xs" size="xl">
{formatMoney(event.perShare)}
{" "}
<Text c="dimmed" component="span" size="sm">
{t("stock.perShare")}
</Text>
</Text>
</div>
{!!event.estimatedAmount && (
<div>
<Text c="dimmed" size="xs">
{t("stock.yourEstimate")}
</Text>
<Text fw={600}>
{formatMoney(event.estimatedAmount)}
</Text>
</div>
)}
</Group>
<Group gap="xl" mt="md">
{!!event.lastBuyDate && (
<div>
<Text c="dimmed" size="xs">
{t("stock.lastBuy")}
</Text>
<Text>{formatDate(event.lastBuyDate)}</Text>
</div>
)}
{!!event.recordDate && (
<div>
<Text c="dimmed" size="xs">
{t("stock.record")}
</Text>
<Text>{formatDate(event.recordDate)}</Text>
</div>
)}
{!!event.paymentDate && (
<div>
<Text c="dimmed" size="xs">
{t("stock.payment")}
</Text>
<Text>{formatDate(event.paymentDate)}</Text>
</div>
)}
</Group>
</div>
))
);
}
else {
upcomingContent = (
<Text c="dimmed">
{t("stock.noUpcoming", { to: formatDate(vm.dividends.to) })}
</Text>
);
}
}
let pastDividendsContent;
if (vm.pastDividends.length > 0) {
pastDividendsContent = (
<Stack gap="sm">
{vm.pastDividends.map(event => (
<Paper
key={JSON.stringify([
event.recordDate,
event.paymentDate,
event.perShare,
])}
p="md"
radius="md"
withBorder
>
<Group align="start" justify="space-between">
<div>
<Text c="dimmed" size="xs">
{t("stock.record")}
</Text>
<Text fw={600}>
{event.recordDate
? formatDate(event.recordDate)
: t("stock.dateUnknown")}
</Text>
{!!event.paymentDate && (
<Text c="dimmed" mt="xs" size="xs">
{t("stock.payment")}:{" "}
{formatDate(event.paymentDate)}
</Text>
)}
</div>
<div>
<Text fw={650} size="lg">
{formatMoney(event.perShare)}
</Text>
<Text c="dimmed" size="xs">
{t("stock.perShare")}
</Text>
</div>
</Group>
</Paper>
))}
</Stack>
);
}
else {
pastDividendsContent = (
<Text c="dimmed">{t("stock.noDividends")}</Text>
);
}
return (
<StockSection state={vm.dividendsState} title={t("stock.upcoming")}>
{!!(vm.dividends) && ((
{!!vm.dividends && (
<Stack gap="md">
{!!(vm.dividends.estimateUnavailable || vm.dividends.positionIsStale) && ((
{!!(
vm.dividends.estimateUnavailable || vm.dividends.positionIsStale
) && (
<Alert aria-live="polite" color="orange" role="status">
{t("stock.estimateUnavailable")}
</Alert>
))}
{vm.upcoming.length > 0
? (
vm.upcoming.map(event => (
<div
className={classes.dividend}
key={JSON.stringify([
event.recordDate,
event.paymentDate,
event.perShare,
])}
>
<Group align="start" justify="space-between">
<div>
<Badge color="green" variant="light">
{t("stock.companyEvent")}
</Badge>
<Text fw={650} mt="xs" size="xl">
{formatMoney(event.perShare)}
{" "}
<Text c="dimmed" component="span" size="sm">
{t("stock.perShare")}
</Text>
</Text>
</div>
{!!(event.estimatedAmount) && ((
<div>
<Text c="dimmed" size="xs">
{t("stock.yourEstimate")}
</Text>
<Text fw={600}>{formatMoney(event.estimatedAmount)}</Text>
</div>
))}
</Group>
<Group gap="xl" mt="md">
{!!(event.lastBuyDate) && ((
<div>
<Text c="dimmed" size="xs">
{t("stock.lastBuy")}
</Text>
<Text>{formatDate(event.lastBuyDate)}</Text>
</div>
))}
{!!(event.recordDate) && ((
<div>
<Text c="dimmed" size="xs">
{t("stock.record")}
</Text>
<Text>{formatDate(event.recordDate)}</Text>
</div>
))}
{!!(event.paymentDate) && ((
<div>
<Text c="dimmed" size="xs">
{t("stock.payment")}
</Text>
<Text>{formatDate(event.paymentDate)}</Text>
</div>
))}
</Group>
</div>
))
)
: (
<Text c="dimmed">
{t("stock.noUpcoming", { to: formatDate(vm.dividends.to) })}
</Text>
)}
)}
{upcomingContent}
<Text c="dimmed" size="xs">
{t("stock.dividendNote")}
</Text>
{!!(vm.dividends.positionAt) && ((
{!!vm.dividends.positionAt && (
<Text c="dimmed" size="xs">
{t("stock.snapshotAt", {
date: formatSnapshotTime(vm.dividends.positionAt),
})}
</Text>
))}
)}
<Accordion radius="md" variant="contained">
<Accordion.Item value="history">
<Accordion.Control>
<Text fw={600}>{t("stock.dividendHistory")}</Text>
</Accordion.Control>
<Accordion.Panel>
<Text c="dimmed" my="sm" size="xs">
{t("stock.dividendWindow", {
@@ -120,60 +206,13 @@ const StockDividends: FC<StockEventsProps> = (props) => {
to: formatDate(vm.dividends.to),
})}
</Text>
{vm.pastDividends.length > 0
? (
<Stack gap="sm">
{vm.pastDividends.map(event => (
<Paper
key={JSON.stringify([
event.recordDate,
event.paymentDate,
event.perShare,
])}
p="md"
radius="md"
withBorder
>
<Group align="start" justify="space-between">
<div>
<Text c="dimmed" size="xs">
{t("stock.record")}
</Text>
<Text fw={600}>
{event.recordDate
? formatDate(event.recordDate)
: t("stock.dateUnknown")}
</Text>
{!!(event.paymentDate) && ((
<Text c="dimmed" mt="xs" size="xs">
{t("stock.payment")}
:
{" "}
{formatDate(event.paymentDate)}
</Text>
))}
</div>
<div>
<Text fw={650} size="lg">
{formatMoney(event.perShare)}
</Text>
<Text c="dimmed" size="xs">
{t("stock.perShare")}
</Text>
</div>
</Group>
</Paper>
))}
</Stack>
)
: (
<Text c="dimmed">{t("stock.noDividends")}</Text>
)}
{pastDividendsContent}
</Accordion.Panel>
</Accordion.Item>
</Accordion>
</Stack>
))}
)}
</StockSection>
);
};