Files
frontend/src/pages/account-events/ui/AccountEventsPage/AccountEventsPage.vm.ts
T
ksv741 f9f0f6921e
Frontend verify / commits (pull_request) Failing after 1m19s
Frontend verify / security (pull_request) Skipped
Frontend verify / verify (pull_request) Skipped
refactor: clarify frontend module ownership
2026-09-29 07:07:36 +03:00

114 lines
2.8 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 { isValidPeriod, useUrlPeriod } from "@/shared/lib";
type AccountEventsPageViewModel
= | {
canApply: boolean;
draftPeriod: [null | string, null | string];
events: BrokerageEvent[];
lastSuccessfulAt?: null | string;
onApply: () => void;
onPeriodChange: (value: [null | string, null | string]) => void;
onReset: () => void;
partial?: boolean;
refreshError: boolean;
refreshing: boolean;
retry: () => void;
sourceError?: boolean;
state: "loaded";
}
| { onReset: () => void; retry: () => void; state: "error" }
| { state: "loading" };
function useAccountEventsPageViewModel(): 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 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 }),
});
const sync = useScreenSync(
{
accountId,
screen: "events",
...(appliedFrom && { from: appliedFrom }),
...(appliedTo && { to: appliedTo }),
},
[events],
);
if (events.isLoading) return { state: "loading" };
const onReset = () => {
setDraftPeriod([null, null]);
setSearchParameters({});
};
if ((events.isError || events.meta?.sync.state === "failed") && !events.data)
return {
onReset,
retry: () => {
void sync.retry();
},
state: "error",
};
if (!events.data) return { state: "loading" };
return {
canApply:
(draftFrom !== appliedFrom || draftTo !== appliedTo)
&& isValidPeriod(draftFrom, draftTo),
draftPeriod,
events: events.data.events,
lastSuccessfulAt: events.meta?.lastSuccessfulAt,
onApply: () => {
if (!isValidPeriod(draftFrom, draftTo)) return;
setSearchParameters({
...(draftFrom && { from: draftFrom }),
...(draftTo && { to: draftTo }),
});
},
onPeriodChange: setDraftPeriod,
onReset,
partial: events.meta?.availability !== "complete",
refreshError: events.isError || sync.sourceError || sync.transportError,
refreshing: events.isFetching || sync.refreshing,
retry: () => {
void sync.retry();
},
sourceError: sync.sourceError,
state: "loaded",
};
}
export { type AccountEventsPageViewModel, useAccountEventsPageViewModel };