import { useState } from "react"; import { useParams } from "react-router"; import type { InvestmentResourceMeta } from "@/shared/api"; import { type BrokerageEvent, useBrokerageEvents, } from "@/entities/brokerage-event"; import { useScreenSync } from "@/features/tbank-connection"; import { defaultPeriod, isValidPeriod, moscowDate, useInitialAvailability, useUrlPeriod, } from "@/shared/lib"; type AccountEventsPageViewModel = | { canApply: boolean; draftPeriod: [null | string, null | string]; events: BrokerageEvent[]; maxDate: string; onApply: () => void; onPeriodChange: (value: [null | string, null | string]) => void; onPeriodPopoverOpen: () => void; onReset: () => void; partial?: boolean; source?: InvestmentResourceMeta; state: "loaded"; } | { onReset: () => 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 [maxDate, setMaxDate] = 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, }); 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, state: "error", }; if (!events.data) return availability === "unavailable" ? { onReset, state: "error" } : { state: "loading" }; return { canApply: (draftFrom !== appliedFrom || draftTo !== appliedTo) && isValidPeriod(draftFrom, draftTo), draftPeriod, events: events.data.events, maxDate, 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: () => setMaxDate(moscowDate(new Date())), onReset, partial: events.meta?.completeness === "incomplete", source: events.meta, state: "loaded", }; } export { type AccountEventsPageViewModel, useAccountEventsPageViewModel };