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; source?: InvestmentResourceMeta; state: "loaded"; totalVisible: boolean; } | { onReset: () => void; readRetry: ReturnType; 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 };