feat: simplify income page filters and payments

This commit is contained in:
2026-09-09 13:50:41 +03:00
parent ab1b53680d
commit 26f229ba3e
13 changed files with 668 additions and 513 deletions
@@ -2,52 +2,62 @@ import {
Alert,
Button,
Group,
Loader,
Stack,
Text,
TextInput,
Title,
} from "@mantine/core";
import type { FC } from "react";
import { FormProvider } from "react-hook-form";
import { useTranslation } from "react-i18next";
import { StateView } from "@/shared/ui";
import classes from "../AccountIncomePage.module.css";
import type { AccountIncomePageViewModel } from "../AccountIncomePage.vm";
import { IncomeBreakdown } from "./IncomeBreakdown.view";
import { IncomeComparisons } from "./IncomeComparisons.view";
import { IncomeForecast } from "./IncomeForecast.view";
import { IncomePayments } from "./IncomePayments.view";
import { IncomePeriodForm } from "./IncomePeriodForm.view";
import { IncomeSummary } from "./IncomeSummary.view";
import { IncomeTrend } from "./IncomeTrend.view";
type LoadedProps = Extract<AccountIncomePageViewModel, { state: "loaded" }>;
const AccountIncomePageLoaded: FC<LoadedProps> = (props) => {
const { analytics, display, form, forecast, onSubmit, onReset } = props;
const {
analytics,
display,
form,
refreshing,
refreshError,
retry,
onSubmit,
onReset,
} = props;
const { t } = useTranslation();
return (
<Stack maw={960} gap="lg">
<Stack maw={960} gap="lg" className={classes.page}>
<Title order={1}>{t("income.title")}</Title>
<form onSubmit={form.handleSubmit(onSubmit)}>
<Group align="end">
<TextInput
error={form.formState.errors.from?.message}
label={t("income.from")}
type="date"
{...form.register("from")}
/>
<TextInput
error={form.formState.errors.to?.message}
label={t("income.to")}
type="date"
{...form.register("to")}
/>
<Button type="submit">{t("income.apply")}</Button>
<Button onClick={onReset} variant="subtle">
{t("income.reset")}
</Button>
<FormProvider {...form}>
<IncomePeriodForm
key={props.formRevision}
onSubmit={form.handleSubmit(onSubmit)}
onReset={onReset}
/>
</FormProvider>
{refreshing ? (
<Group gap="xs" role="status" aria-label={t("income.refreshing")}>
<Loader size="sm" />
<Text>{t("income.refreshing")}</Text>
</Group>
</form>
<Text c="dimmed">
{analytics.period.from} — {analytics.period.to}
</Text>
) : null}
{refreshError ? (
<Alert color="orange">
<Stack gap="sm">
<Text>{t("income.refreshError")}</Text>
<Button onClick={retry} variant="default">
{t("income.retry")}
</Button>
</Stack>
</Alert>
) : null}
{analytics.totalsByCurrency.length ? (
<IncomeSummary totals={analytics.totalsByCurrency} />
) : (
@@ -58,9 +68,7 @@ const AccountIncomePageLoaded: FC<LoadedProps> = (props) => {
)}
<Alert color="blue">{t("income.taxBoundary")}</Alert>
<IncomeComparisons analytics={analytics} />
<IncomeTrend trend={display.trend} />
<IncomeBreakdown instruments={display.instruments} />
<IncomeForecast forecast={forecast} />
<IncomePayments entries={display.entries} />
</Stack>
);
};