feat: replace paired date inputs with range pickers

This commit is contained in:
2026-09-12 22:41:40 +03:00
parent aba4cf1ce8
commit 24d332e063
8 changed files with 137 additions and 175 deletions
@@ -55,7 +55,7 @@ describe("Upcoming event date filters", () => {
);
render(
<QueryClientProvider client={createTestQueryClient()}>
<MantineProvider>
<MantineProvider env="test">
<MemoryRouter
initialEntries={[
`/accounts/${accountId}/events?from=2099-02-01&to=2099-02-28`,
@@ -72,31 +72,37 @@ describe("Upcoming event date filters", () => {
</MantineProvider>
</QueryClientProvider>,
);
const from = await screen.findByLabelText("С");
const to = screen.getByLabelText("По");
expect(from).toHaveValue("01.02.2099");
expect(to).toHaveValue("28.02.2099");
const from = await screen.findByLabelText("Период");
expect(from).toHaveTextContent("01.02.2099 – 28.02.2099");
expect(screen.getByRole("button", { name: "Применить" })).toBeDisabled();
expect(searches).toEqual(["?from=2099-02-01&to=2099-02-28"]);
fireEvent.change(from, { target: { value: "10.02.2099" } });
fireEvent.blur(from);
fireEvent.click(from);
fireEvent.click(
await screen.findByRole("button", { name: /10 February 2099/i }),
);
fireEvent.click(
await screen.findByRole("button", { name: /28 February 2099/i }),
);
expect(searches).toHaveLength(1);
fireEvent.click(screen.getByRole("button", { name: "Применить" }));
await waitFor(() =>
expect(searches.at(-1)).toBe("?from=2099-02-10&to=2099-02-28"),
);
expect(await screen.findByLabelText("С")).toHaveValue("10.02.2099");
expect(await screen.findByLabelText("Период")).toHaveTextContent(
"10.02.2099 – 28.02.2099",
);
fireEvent.click(screen.getByRole("button", { name: "History back" }));
await waitFor(() =>
expect(screen.getByLabelText("С")).toHaveValue("01.02.2099"),
expect(screen.getByLabelText("Период")).toHaveTextContent(
"01.02.2099 – 28.02.2099",
),
);
expect(screen.getByLabelText("URL")).toHaveTextContent(
"?from=2099-02-01&to=2099-02-28",
);
fireEvent.click(screen.getByRole("button", { name: "Сбросить" }));
await waitFor(() => expect(searches.at(-1)).toBe(""));
expect(await screen.findByLabelText("С")).toHaveValue("");
expect(screen.getByLabelText("По")).toHaveValue("");
expect(await screen.findByLabelText("Период")).toHaveTextContent("");
expect(screen.getByRole("button", { name: "Применить" })).toBeDisabled();
expect(
screen.getByText("За выбранный период событий не найдено"),
@@ -7,22 +7,13 @@ import {
Text,
Title,
} from "@mantine/core";
import { DateInput } from "@mantine/dates";
import dayjs from "dayjs";
import customParseFormat from "dayjs/plugin/customParseFormat";
import { DatePickerInput } from "@mantine/dates";
import type { FC } from "react";
import { useTranslation } from "react-i18next";
import { BrokerageEventCard } from "@/entities/brokerage-event";
import type { AccountEventsPageViewModel } from "../AccountEventsPage.vm";
import { AccountEventsPageEmpty } from "./AccountEventsPageEmpty.view";
dayjs.extend(customParseFormat);
const parseDate = (value: string) => {
const date = dayjs(value, "DD.MM.YYYY", true);
return date.isValid() ? date.format("YYYY-MM-DD") : null;
};
type AccountEventsPageLoadedProps = Extract<
AccountEventsPageViewModel,
{ state: "loaded" }
@@ -46,25 +37,22 @@ const AccountEventsPageLoaded: FC<AccountEventsPageLoadedProps> = (props) => {
) : null}
<Text c="dimmed">{t("events.hint")}</Text>
<Group align="end">
<DateInput
label={t("ledger.from")}
value={props.draftFrom}
onChange={props.onDraftFromChange}
maxDate={props.draftTo ?? undefined}
<DatePickerInput
type="range"
allowSingleDateInRange
clearable
clearButtonProps={{ "aria-label": t("ledger.clearPeriod") }}
label={t("ledger.period")}
value={[props.draftFrom, props.draftTo]}
onChange={([from, to]) => {
props.onDraftFromChange(from);
props.onDraftToChange(to);
}}
valueFormat="DD.MM.YYYY"
dateParser={parseDate}
allowDeselect
popoverProps={{ middlewares: { shift: { crossAxis: true } } }}
/>
<DateInput
label={t("ledger.to")}
value={props.draftTo}
onChange={props.onDraftToChange}
minDate={props.draftFrom ?? undefined}
valueFormat="DD.MM.YYYY"
dateParser={parseDate}
allowDeselect
popoverProps={{ middlewares: { shift: { crossAxis: true } } }}
popoverProps={{
returnFocus: true,
middlewares: { shift: { crossAxis: true } },
}}
/>
</Group>
<Group>