64 lines
2.7 KiB
TypeScript
64 lines
2.7 KiB
TypeScript
import { Fragment } from 'react';
|
|
import { Panel } from '@/components/ui/panel';
|
|
import { formatCompactCurrency, formatScaledNumber } from '@/lib/format';
|
|
import type { CompanyAnalysis } from '@/lib/types';
|
|
|
|
type ValuationFactsTableProps = {
|
|
analysis: CompanyAnalysis;
|
|
};
|
|
|
|
function formatRatio(value: number | null) {
|
|
return value === null ? 'n/a' : `${value.toFixed(2)}x`;
|
|
}
|
|
|
|
function formatShares(value: number | null) {
|
|
return value === null ? 'n/a' : formatScaledNumber(value, { maximumFractionDigits: 2 });
|
|
}
|
|
|
|
export function ValuationFactsTable(props: ValuationFactsTableProps) {
|
|
const items = [
|
|
{ label: 'Source', value: props.analysis.valuationSnapshot.source },
|
|
{ label: 'Market cap', value: props.analysis.valuationSnapshot.marketCap === null ? 'n/a' : formatCompactCurrency(props.analysis.valuationSnapshot.marketCap) },
|
|
{ label: 'Enterprise value', value: props.analysis.valuationSnapshot.enterpriseValue === null ? 'n/a' : formatCompactCurrency(props.analysis.valuationSnapshot.enterpriseValue) },
|
|
{ label: 'Shares outstanding', value: formatShares(props.analysis.valuationSnapshot.sharesOutstanding) },
|
|
{ label: 'Trailing P/E', value: formatRatio(props.analysis.valuationSnapshot.trailingPe) },
|
|
{ label: 'EV / Revenue', value: formatRatio(props.analysis.valuationSnapshot.evToRevenue) },
|
|
{ label: 'EV / EBITDA', value: formatRatio(props.analysis.valuationSnapshot.evToEbitda) }
|
|
];
|
|
const rows = Array.from({ length: Math.ceil(items.length / 2) }, (_, index) => items.slice(index * 2, index * 2 + 2));
|
|
|
|
return (
|
|
<Panel
|
|
title="Valuation"
|
|
className="pt-2"
|
|
>
|
|
<div className="overflow-x-auto">
|
|
<table className="w-full border-collapse table-fixed">
|
|
<tbody>
|
|
{rows.map((row) => (
|
|
<tr key={row.map((item) => item.label).join('-')} className="border-t border-[color:var(--line-weak)]">
|
|
{row.map((item) => (
|
|
<Fragment key={item.label}>
|
|
<th className="w-[18%] py-2 pr-3 text-left align-top text-[11px] font-medium uppercase tracking-[0.14em] text-[color:var(--terminal-muted)]">
|
|
{item.label}
|
|
</th>
|
|
<td className="w-[32%] py-2 pr-4 text-sm text-[color:var(--terminal-bright)]">
|
|
{item.value}
|
|
</td>
|
|
</Fragment>
|
|
))}
|
|
{row.length === 1 ? (
|
|
<>
|
|
<th className="w-[18%] py-2 pr-3" />
|
|
<td className="w-[32%] py-2 pr-4" />
|
|
</>
|
|
) : null}
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</Panel>
|
|
);
|
|
}
|