123 lines
3.2 KiB
TypeScript
123 lines
3.2 KiB
TypeScript
import type { FC } from "react";
|
|
|
|
import { Anchor, Card, Group, Stack, Text } from "@mantine/core";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Link } from "react-router";
|
|
|
|
import { formatMoney } from "@/shared/lib";
|
|
|
|
import type { AccountPagePositionGroup, AccountPagePositionSection } from "../../../model/positions";
|
|
|
|
import classes from "../AccountPage.module.css";
|
|
import { PositionLogo } from "./PositionLogo.view";
|
|
|
|
type PositionGroupCardProps = {
|
|
group: AccountPagePositionGroup;
|
|
kind: AccountPagePositionSection["kind"];
|
|
};
|
|
|
|
const PositionGroupCard: FC<PositionGroupCardProps> = (props) => {
|
|
const { group, kind } = props;
|
|
const { t } = useTranslation();
|
|
const identity = group.positions[0];
|
|
const instrumentTo = identity.instrumentTo;
|
|
|
|
return (
|
|
<Card className={classes.tile} withBorder>
|
|
<Group gap="sm" wrap="nowrap">
|
|
{kind !== "other" && (
|
|
<PositionLogo
|
|
key={identity.logoSrc ?? "no-logo"}
|
|
label={identity.displayName}
|
|
src={identity.logoSrc}
|
|
to={instrumentTo}
|
|
/>
|
|
)}
|
|
|
|
<Stack gap={2} miw={0}>
|
|
{instrumentTo
|
|
? (
|
|
<Anchor c="inherit" component={Link} fw={600} to={instrumentTo}>
|
|
{identity.displayName}
|
|
</Anchor>
|
|
)
|
|
: <Text fw={600}>{identity.displayName}</Text>}
|
|
|
|
<Text c="dimmed" size="xs">
|
|
{identity.ticker ?? identity.isin ?? identity.figi}
|
|
</Text>
|
|
</Stack>
|
|
</Group>
|
|
|
|
<Stack
|
|
aria-label={t("portfolio.byAccount")}
|
|
className={classes.accountPositions}
|
|
component="ul"
|
|
gap={0}
|
|
>
|
|
{group.positions.map((position) => {
|
|
const appearanceClass = position.returnTone
|
|
? classes[position.returnTone]
|
|
: undefined;
|
|
|
|
return (
|
|
<Stack
|
|
className={classes.accountPosition}
|
|
component="li"
|
|
gap={4}
|
|
key={position.account?.id}
|
|
>
|
|
<Group align="flex-start" gap="xs" justify="space-between">
|
|
{!!position.account && (
|
|
<Anchor
|
|
className={classes.accountPositionName}
|
|
component={Link}
|
|
size="sm"
|
|
to={`/accounts/${encodeURIComponent(position.account.id)}`}
|
|
>
|
|
{position.account.name}
|
|
</Anchor>
|
|
)}
|
|
|
|
<Text fw={600} size="sm">
|
|
{t("portfolio.quantity", { value: position.quantity })}
|
|
</Text>
|
|
</Group>
|
|
|
|
<Group gap="xs" justify="space-between">
|
|
{!!position.currentValue && <Text size="sm">{formatMoney(position.currentValue)}</Text>}
|
|
|
|
{!!position.returnText && (
|
|
<Text className={appearanceClass} size="sm">
|
|
{kind === "other"
|
|
? t("portfolio.return", { value: position.returnText })
|
|
: position.returnText}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
|
|
<Group gap="xs">
|
|
{!!position.averagePurchasePrice && (
|
|
<Text c="dimmed" size="xs">
|
|
{t("portfolio.avgPrice", {
|
|
value: formatMoney(position.averagePurchasePrice),
|
|
})}
|
|
</Text>
|
|
)}
|
|
|
|
{!!position.shareText && (
|
|
<Text c="dimmed" size="xs">
|
|
{t("portfolio.share", { value: position.shareText })}
|
|
</Text>
|
|
)}
|
|
</Group>
|
|
</Stack>
|
|
);
|
|
})}
|
|
</Stack>
|
|
</Card>
|
|
);
|
|
};
|
|
|
|
export { PositionGroupCard };
|