128 lines
4.1 KiB
TypeScript
128 lines
4.1 KiB
TypeScript
import { Accordion, Alert, Stack, Text } from "@mantine/core";
|
|
import type { FC } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import type { BrokerageAccount } from "@/entities/brokerage-account";
|
|
import { BrokerageEventsPreview } from "@/entities/brokerage-event";
|
|
import type { Portfolio } from "@/entities/portfolio";
|
|
import { formatSnapshotTime } from "@/shared/lib";
|
|
import classes from "../AccountPage.module.css";
|
|
import type {
|
|
AccountPageIncomeSummary,
|
|
AccountPagePositionSection,
|
|
AccountPageRecentEvents,
|
|
AccountPageRecentOperations,
|
|
} from "../AccountPage.vm";
|
|
import { AccountHeading } from "./AccountHeading.view";
|
|
import { CurrencyCards } from "./CurrencyCards.view";
|
|
import { IncomeSummary } from "./IncomeSummary.view";
|
|
import { PortfolioRefreshState } from "./PortfolioRefreshState.view";
|
|
import { PortfolioStructure } from "./PortfolioStructure";
|
|
import { PositionSection } from "./PositionSection.view";
|
|
import { RecentOperations } from "./RecentOperations.view";
|
|
|
|
type AccountPageLoadedProps = {
|
|
account?: BrokerageAccount;
|
|
accountId?: string;
|
|
portfolio: Portfolio;
|
|
positionSections: AccountPagePositionSection[];
|
|
refreshing?: boolean;
|
|
refreshError?: boolean;
|
|
retry?: () => void;
|
|
recentOperations: AccountPageRecentOperations;
|
|
recentEvents: AccountPageRecentEvents;
|
|
incomeSummary?: AccountPageIncomeSummary;
|
|
};
|
|
|
|
const AccountPageLoaded: FC<AccountPageLoadedProps> = (props) => {
|
|
const { t } = useTranslation();
|
|
return (
|
|
<Stack gap="lg">
|
|
<AccountHeading account={props.account} accountId={props.accountId} />
|
|
<PortfolioRefreshState
|
|
refreshing={props.refreshing ?? false}
|
|
refreshError={props.refreshError ?? false}
|
|
retry={props.retry}
|
|
/>
|
|
{props.portfolio.isStale ? (
|
|
<Alert color="blue">{t("portfolio.staleWarning")}</Alert>
|
|
) : null}
|
|
<Text c="dimmed" size="sm">
|
|
{t(
|
|
props.accountId === "all"
|
|
? "portfolio.allUpdatedAt"
|
|
: "portfolio.updatedAt",
|
|
{
|
|
date: formatSnapshotTime(props.portfolio.lastSuccessfulAt),
|
|
},
|
|
)}
|
|
</Text>
|
|
<CurrencyCards amounts={props.portfolio.totalsByCurrency} />
|
|
<PortfolioStructure
|
|
key={props.accountId}
|
|
structure={props.portfolio.structure}
|
|
/>
|
|
<Accordion
|
|
multiple
|
|
defaultValue={[
|
|
...props.positionSections.map((section) => section.kind),
|
|
"cash",
|
|
"recentOperations",
|
|
"recentEvents",
|
|
"incomeSummary",
|
|
]}
|
|
classNames={{
|
|
control: classes.accordionControl,
|
|
label: classes.accordionLabel,
|
|
chevron: classes.accordionChevron,
|
|
panel: classes.accordionPanel,
|
|
}}
|
|
>
|
|
{props.positionSections.map((section) => (
|
|
<Accordion.Item key={section.kind} value={section.kind}>
|
|
<Accordion.Control>
|
|
{t(positionSectionTitleKey(section.kind))}
|
|
</Accordion.Control>
|
|
<Accordion.Panel>
|
|
<PositionSection section={section} />
|
|
</Accordion.Panel>
|
|
</Accordion.Item>
|
|
))}
|
|
<Accordion.Item value="cash">
|
|
<Accordion.Control>{t("portfolio.cashBalances")}</Accordion.Control>
|
|
<Accordion.Panel>
|
|
<CurrencyCards amounts={props.portfolio.cashBalances} />
|
|
</Accordion.Panel>
|
|
</Accordion.Item>
|
|
<Accordion.Item value="recentOperations">
|
|
<Accordion.Control>{t("ledger.recentTitle")}</Accordion.Control>
|
|
<Accordion.Panel>
|
|
<RecentOperations operations={props.recentOperations} />
|
|
</Accordion.Panel>
|
|
</Accordion.Item>
|
|
<Accordion.Item value="recentEvents">
|
|
<Accordion.Control>{t("events.recentTitle")}</Accordion.Control>
|
|
<Accordion.Panel>
|
|
<BrokerageEventsPreview events={props.recentEvents} />
|
|
</Accordion.Panel>
|
|
</Accordion.Item>
|
|
<Accordion.Item value="incomeSummary">
|
|
<Accordion.Control>{t("income.summaryTitle")}</Accordion.Control>
|
|
<Accordion.Panel>
|
|
{props.incomeSummary ? (
|
|
<IncomeSummary {...props.incomeSummary} />
|
|
) : null}
|
|
</Accordion.Panel>
|
|
</Accordion.Item>
|
|
</Accordion>
|
|
</Stack>
|
|
);
|
|
};
|
|
|
|
function positionSectionTitleKey(kind: AccountPagePositionSection["kind"]) {
|
|
if (kind === "stocks") return "portfolio.stocks";
|
|
if (kind === "bonds") return "portfolio.bonds";
|
|
return "portfolio.otherPositions";
|
|
}
|
|
|
|
export { AccountPageLoaded };
|