feat: group all-account rows by instrument and day (WealthLedger/main#47) (#126)
This commit was merged in pull request #126.
This commit is contained in:
@@ -237,4 +237,79 @@ describe("AccountEventsPage", () => {
|
||||
screen.queryByText("За выбранный период событий не найдено"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("groups same-day instrument events only in all-account mode", () => {
|
||||
const events = [
|
||||
{
|
||||
account: { id: "broker", name: "Брокерский" },
|
||||
date: "2026-08-20",
|
||||
dateKind: "event",
|
||||
displayName: "ОФЗ 26238",
|
||||
figi: "FIGI",
|
||||
instrumentUid: "UID",
|
||||
isin: "RU000A0JX0J2",
|
||||
logoName: null,
|
||||
projectedAmount: { currency: "RUB", value: "200" },
|
||||
ticker: "OFZ",
|
||||
type: "coupon",
|
||||
},
|
||||
{
|
||||
account: { id: "iis", name: "ИИС" },
|
||||
date: "2026-08-20",
|
||||
dateKind: "event",
|
||||
displayName: "ОФЗ 26238",
|
||||
figi: "FIGI",
|
||||
instrumentUid: "UID",
|
||||
isin: "RU000A0JX0J2",
|
||||
logoName: null,
|
||||
projectedAmount: { currency: "RUB", value: "100" },
|
||||
ticker: "OFZ",
|
||||
type: "coupon",
|
||||
},
|
||||
] as const;
|
||||
|
||||
query.mockReturnValue({
|
||||
data: {
|
||||
accountId: "all",
|
||||
calculatedAt: "2026-08-14T00:00:00Z",
|
||||
events: [...events],
|
||||
},
|
||||
isError: false,
|
||||
isLoading: false,
|
||||
meta: {
|
||||
availability: "available",
|
||||
completeness: "complete",
|
||||
lastAttempt: {
|
||||
finishedAt: null,
|
||||
problems: [],
|
||||
startedAt: null,
|
||||
state: "none",
|
||||
},
|
||||
},
|
||||
refetch: vi.fn(),
|
||||
} as never);
|
||||
|
||||
render(
|
||||
<MantineProvider>
|
||||
<MemoryRouter initialEntries={["/accounts/all/events"]}>
|
||||
<Routes>
|
||||
<Route
|
||||
element={<AccountEventsPage />}
|
||||
path="/accounts/:accountId/events"
|
||||
/>
|
||||
</Routes>
|
||||
</MemoryRouter>
|
||||
</MantineProvider>,
|
||||
);
|
||||
|
||||
expect(screen.getByText("Купон · ОФЗ 26238")).toBeInTheDocument();
|
||||
expect(screen.getByText("300 ₽")).toBeInTheDocument();
|
||||
|
||||
const accounts = within(screen.getByRole("list", {
|
||||
name: /Купон · ОФЗ 26238, 20\.08\.2026, 300 ₽/,
|
||||
}));
|
||||
|
||||
expect(accounts.getByText("Брокерский")).toBeInTheDocument();
|
||||
expect(accounts.getByText("ИИС")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
|
||||
type AccountEventsPageViewModel
|
||||
= | {
|
||||
allAccounts: boolean;
|
||||
canApply: boolean;
|
||||
draftPeriod: [null | string, null | string];
|
||||
events: BrokerageEvent[];
|
||||
@@ -29,6 +30,7 @@ type AccountEventsPageViewModel
|
||||
partial?: boolean;
|
||||
source?: InvestmentResourceMeta;
|
||||
state: "loaded";
|
||||
totalVisible: boolean;
|
||||
}
|
||||
| { onReset: () => void; state: "error" }
|
||||
| { state: "loading" };
|
||||
@@ -100,6 +102,7 @@ function useAccountEventsPageViewModel(): AccountEventsPageViewModel {
|
||||
: { state: "loading" };
|
||||
|
||||
return {
|
||||
allAccounts: accountId === "all",
|
||||
canApply:
|
||||
(draftFrom !== appliedFrom || draftTo !== appliedTo)
|
||||
&& isValidPeriod(draftFrom, draftTo),
|
||||
@@ -121,6 +124,7 @@ function useAccountEventsPageViewModel(): AccountEventsPageViewModel {
|
||||
partial: events.meta?.completeness === "incomplete",
|
||||
source: events.meta,
|
||||
state: "loaded",
|
||||
totalVisible: events.meta?.completeness === "complete",
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
+28
-7
@@ -13,8 +13,11 @@ import { useTranslation } from "react-i18next";
|
||||
|
||||
import {
|
||||
BrokerageEventCard,
|
||||
BrokerageEventGroup,
|
||||
brokerageEventGroupKey,
|
||||
brokerageEventKey,
|
||||
} from "@/entities/brokerage-event";
|
||||
import { groupItems } from "@/shared/lib";
|
||||
import { SourceSyncStatus } from "@/shared/ui";
|
||||
|
||||
import type { AccountEventsPageViewModel } from "../AccountEventsPage.vm";
|
||||
@@ -30,14 +33,32 @@ const AccountEventsPageLoadedEvents: FC<AccountEventsPageLoadedProps> = (
|
||||
props,
|
||||
) => {
|
||||
if (props.events.length > 0) {
|
||||
const entries = groupItems(
|
||||
props.events,
|
||||
props.allAccounts ? brokerageEventGroupKey : () => null,
|
||||
);
|
||||
|
||||
return (
|
||||
<Stack gap="sm">
|
||||
{props.events.map(event => (
|
||||
<BrokerageEventCard
|
||||
event={event}
|
||||
key={brokerageEventKey(event)}
|
||||
/>
|
||||
))}
|
||||
<Stack
|
||||
component="ul"
|
||||
gap="sm"
|
||||
m={0}
|
||||
p={0}
|
||||
style={{ listStyle: "none" }}
|
||||
>
|
||||
{entries.map(entry => entry.type === "group"
|
||||
? (
|
||||
<BrokerageEventGroup
|
||||
events={entry.items}
|
||||
key={entry.key}
|
||||
totalVisible={props.totalVisible}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<li key={brokerageEventKey(entry.item)}>
|
||||
<BrokerageEventCard event={entry.item} />
|
||||
</li>
|
||||
))}
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user