import { ReactNode } from 'react'; import { FixedSizeList } from 'react-window'; import { useSpring, config } from '@react-spring/web'; import { Grid, Row, Column, Text } from '@umami/react-zen'; import { AnimatedDiv } from '@/components/common/AnimatedDiv'; import { Empty } from '@/components/common/Empty'; import { useMessages, useMobile } from '@/components/hooks'; import { formatLongCurrency, formatLongNumber } from '@/lib/format'; const ITEM_SIZE = 30; interface ListData { label: string; count: number; percent: number; } export interface ListTableProps { data?: ListData[]; title?: string; metric?: string; className?: string; renderLabel?: (data: ListData, index: number) => ReactNode; renderChange?: (data: ListData, index: number) => ReactNode; animate?: boolean; virtualize?: boolean; showPercentage?: boolean; itemCount?: number; currency?: string; } export function ListTable({ data = [], title, metric, renderLabel, renderChange, animate = true, virtualize = false, showPercentage = true, itemCount = 10, currency, }: ListTableProps) { const { formatMessage, labels } = useMessages(); const { isPhone } = useMobile(); const getRow = (row: ListData, index: number) => { const { label, count, percent } = row; return ( ); }; const ListTableRow = ({ index, style }) => { return
{getRow(data[index], index)}
; }; return ( {title} {metric} {data?.length === 0 && } {virtualize && data.length > 0 ? ( {ListTableRow} ) : ( data.map(getRow) )} ); } const AnimatedRow = ({ label, value = 0, percent, change, animate, showPercentage = true, currency, isMobile, }) => { const props = useSpring({ width: percent, y: !isNaN(value) ? value : 0, from: { width: 0, y: 0 }, config: animate ? config.default : { duration: 0 }, }); return ( {label} {change} {currency ? props.y?.to(n => formatLongCurrency(n, currency)) : props.y?.to(formatLongNumber)} {showPercentage && ( {props.width.to(n => `${n?.toFixed?.(0)}%`)} )} ); };