97 lines
2.3 KiB
TypeScript
97 lines
2.3 KiB
TypeScript
import type { FC } from "react";
|
|
|
|
import { EntryCard } from "@wealthledger/ui";
|
|
import { useTranslation } from "react-i18next";
|
|
|
|
import {
|
|
formatSnapshotDay,
|
|
instrumentLogoUrl,
|
|
sumMoney,
|
|
totalText,
|
|
} from "@/shared/lib";
|
|
import { AccountCardRow, EntryGroup, EntryGroupTotal } from "@/shared/ui";
|
|
|
|
import type { BrokerageOperation } from "../api/useBrokerageOperations";
|
|
|
|
import {
|
|
entryLabelKey,
|
|
isZeroDecimal,
|
|
operationLabelKey,
|
|
paymentPresentation,
|
|
} from "../model/display";
|
|
|
|
type OperationGroupProps = {
|
|
entries: { key: string; operation: BrokerageOperation }[];
|
|
totalVisible: boolean;
|
|
};
|
|
|
|
const OperationGroup: FC<OperationGroupProps> = (props) => {
|
|
const { t } = useTranslation();
|
|
const operations = props.entries.map(entry => entry.operation);
|
|
const first = operations.at(0);
|
|
|
|
// groupItems only emits groups of at least two entries.
|
|
if (!first) return null;
|
|
|
|
const typeLabel = t(first.category === "income"
|
|
? entryLabelKey(first)
|
|
: operationLabelKey(first.type));
|
|
|
|
const instrument
|
|
= first.ticker ?? first.instrumentType ?? t("ledger.noInstrument");
|
|
|
|
const amounts = operations.flatMap(operation =>
|
|
operation.payment ? [operation.payment] : [],
|
|
);
|
|
|
|
const isAmountsKnown = amounts.length === operations.length
|
|
&& amounts.every(amount => !isZeroDecimal(amount.value));
|
|
|
|
const totals = isAmountsKnown && props.totalVisible
|
|
? sumMoney(amounts)
|
|
: null;
|
|
|
|
const date = formatSnapshotDay(first.occurredAt);
|
|
const title = `${typeLabel} · ${instrument}`;
|
|
const totalsText = totalText(totals, true);
|
|
|
|
const accessibleName = [
|
|
title,
|
|
t("payout.executedAt", { date }),
|
|
totalsText || t("entryGroup.totalUnavailable"),
|
|
].join(", ");
|
|
|
|
return (
|
|
<EntryGroup
|
|
header={(
|
|
<EntryCard
|
|
imageSrc={instrumentLogoUrl(first.logoName)}
|
|
initial={(first.ticker?.trim()[0] ?? "?").toUpperCase()}
|
|
metadata={t("payout.executedAt", { date })}
|
|
title={title}
|
|
tone="neutral"
|
|
value={<EntryGroupTotal isSigned totals={totals} />}
|
|
valueLabel={typeLabel}
|
|
wrap
|
|
/>
|
|
)}
|
|
label={accessibleName}
|
|
>
|
|
{props.entries.map(({ key, operation }) => {
|
|
const payment = paymentPresentation(operation);
|
|
|
|
return (
|
|
<AccountCardRow
|
|
accountName={operation.account?.name ?? "—"}
|
|
key={key}
|
|
value={payment.amount}
|
|
valueLabel={t(payment.label)}
|
|
/>
|
|
);
|
|
})}
|
|
</EntryGroup>
|
|
);
|
|
};
|
|
|
|
export { OperationGroup };
|