Files
frontend/src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.vm.ts
T
ksv741 e5b4bb3ea3
Frontend verify / commits (pull_request) Successful in 37s
Frontend verify / security (pull_request) Successful in 16s
Frontend verify / verify (pull_request) Successful in 6m59s
refactor: normalize view models and share breadcrumbs and titles (WealthLedger/frontend#143)
2026-11-04 20:48:25 +03:00

140 lines
3.5 KiB
TypeScript

import { useState } from "react";
import { useParams } from "react-router";
import {
type BrokerageEvent,
useBrokerageEvents,
} from "@/entities/brokerage-event";
import { useScreenSync } from "@/features/tbank-connection";
import { type InvestmentResourceMeta, readRetry } from "@/shared/api";
import {
defaultPeriod,
isValidPeriod,
moscowDate,
useInitialAvailability,
useUrlPeriod,
} from "@/shared/lib";
type AccountEventsPageViewModel
= | {
allAccounts: boolean;
canApply: boolean;
draftPeriod: [null | string, null | string];
events: BrokerageEvent[];
minDate: string;
onApply: () => void;
onPeriodChange: (value: [null | string, null | string]) => void;
onPeriodPopoverOpen: () => void;
onReset: () => void;
partial?: boolean;
readRetry: ReturnType<typeof readRetry>;
source?: InvestmentResourceMeta;
state: "loaded";
totalVisible: boolean;
}
| {
onReset: () => void;
readRetry: ReturnType<typeof readRetry>;
state: "error";
}
| { state: "loading" };
function useAccountEventsPageVm(): AccountEventsPageViewModel {
const { accountId = "" } = useParams();
const {
from: appliedFrom,
setParameters: setSearchParameters,
to: appliedTo,
} = useUrlPeriod();
const [draftPeriod, setDraftPeriod] = useState<[
null | string,
null | string,
]>([appliedFrom, appliedTo]);
const [draftFrom, draftTo] = draftPeriod;
const [minDate, setMinDate] = useState(() => moscowDate(new Date()));
const scope = JSON.stringify([accountId, appliedFrom, appliedTo]);
const [previousScope, setPreviousScope] = useState(scope);
if (previousScope !== scope) {
setPreviousScope(scope);
setDraftPeriod([appliedFrom, appliedTo]);
}
const events = useBrokerageEvents(accountId, {
...(appliedFrom && { from: appliedFrom }),
...(appliedTo && { to: appliedTo }),
});
useScreenSync(
{
accountId,
screen: "events",
...(appliedFrom && { from: appliedFrom }),
...(appliedTo && { to: appliedTo }),
},
[events],
);
const availability = useInitialAvailability({
hasContent: !!events.data,
identity: scope,
isError: events.isError || events.meta?.lastAttempt.state === "failed",
isFetching: events.isFetching,
});
const retry = readRetry([events]);
if (availability === "loading" && events.isLoading)
return { state: "loading" };
const onReset = () => {
setDraftPeriod([appliedFrom, appliedTo]);
setSearchParameters({});
};
if ((events.isError || events.meta?.lastAttempt.state === "failed") && !events.data)
return {
onReset,
readRetry: retry,
state: "error",
};
if (!events.data)
return availability === "unavailable"
? { onReset, readRetry: retry, state: "error" }
: { state: "loading" };
return {
allAccounts: accountId === "all",
canApply:
(draftFrom !== appliedFrom || draftTo !== appliedTo)
&& isValidPeriod(draftFrom, draftTo),
draftPeriod,
events: events.data.events,
minDate,
onApply: () => {
if (!isValidPeriod(draftFrom, draftTo)) return;
setSearchParameters({
...(draftFrom && { from: draftFrom }),
...(draftTo && { to: draftTo }),
});
},
onPeriodChange: value => setDraftPeriod(
value[0] === null && value[1] === null ? defaultPeriod() : value,
),
onPeriodPopoverOpen: () => setMinDate(moscowDate(new Date())),
onReset,
partial: events.meta?.completeness === "incomplete",
readRetry: retry,
source: events.meta,
state: "loaded",
totalVisible: events.meta?.completeness === "complete",
};
}
export { type AccountEventsPageViewModel, useAccountEventsPageVm };