140 lines
3.5 KiB
TypeScript
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 };
|