UsageChartTooltips.tsx112 lines · main
| 1 | import type { Payload, ValueType } from 'recharts/types/component/DefaultTooltipContent' |
| 2 | import { cn } from 'ui' |
| 3 | |
| 4 | import { Attribute, COLOR_MAP } from './Usage.constants' |
| 5 | |
| 6 | export interface SingleAttributeTooltipContentProps { |
| 7 | name: string |
| 8 | unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' |
| 9 | value: any |
| 10 | isAfterToday: boolean |
| 11 | tooltipFormatter?: (value: any) => any |
| 12 | } |
| 13 | |
| 14 | export const SingleAttributeTooltipContent = ({ |
| 15 | name, |
| 16 | unit, |
| 17 | value, |
| 18 | isAfterToday, |
| 19 | tooltipFormatter, |
| 20 | }: SingleAttributeTooltipContentProps) => { |
| 21 | const formattedValue = unit === 'percentage' ? Number(value).toFixed(2) : Number(value) |
| 22 | return ( |
| 23 | <> |
| 24 | <p className="text-xs text-foreground-light">{name}</p> |
| 25 | {isAfterToday ? ( |
| 26 | <p className="text-foreground-light text-lg">No data yet</p> |
| 27 | ) : ( |
| 28 | <p className="text-xl"> |
| 29 | {tooltipFormatter !== undefined ? tooltipFormatter(formattedValue) : formattedValue} |
| 30 | </p> |
| 31 | )} |
| 32 | </> |
| 33 | ) |
| 34 | } |
| 35 | |
| 36 | export interface MultiAttributeTooltipContentProps { |
| 37 | attributes: Attribute[] |
| 38 | values: Payload<ValueType, string | number>[] |
| 39 | isAfterToday: boolean |
| 40 | tooltipFormatter?: (value: any) => any |
| 41 | unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' |
| 42 | } |
| 43 | |
| 44 | const AttributeContent = ({ |
| 45 | attribute, |
| 46 | attributeMeta, |
| 47 | sumValue, |
| 48 | tooltipFormatter, |
| 49 | unit, |
| 50 | }: { |
| 51 | attribute: Attribute |
| 52 | attributeMeta?: Payload<ValueType, string | number> |
| 53 | sumValue: number |
| 54 | tooltipFormatter?: (value: any) => any |
| 55 | unit: 'bytes' | 'percentage' | 'absolute' | 'hours' | 'gigabytes' |
| 56 | }) => { |
| 57 | const attrValue = Number(attributeMeta?.value ?? 0) |
| 58 | const percentageContribution = ((attrValue / sumValue) * 100).toFixed(1) |
| 59 | |
| 60 | return ( |
| 61 | <div key={attribute.name} className="flex items-center justify-between"> |
| 62 | <div className="flex items-center space-x-2 w-[175px]"> |
| 63 | <div className={cn('w-3 h-3 rounded-full border', COLOR_MAP[attribute.color].marker)} /> |
| 64 | <p className="text-xs prose"> |
| 65 | {attribute.name} ({percentageContribution}%):{' '} |
| 66 | </p> |
| 67 | </div> |
| 68 | <p className="text-xs tabular-nums"> |
| 69 | {tooltipFormatter !== undefined |
| 70 | ? tooltipFormatter(attrValue) |
| 71 | : `${attrValue}${unit === 'hours' ? ' H' : ''}`} |
| 72 | </p> |
| 73 | </div> |
| 74 | ) |
| 75 | } |
| 76 | |
| 77 | export const MultiAttributeTooltipContent = ({ |
| 78 | attributes, |
| 79 | values, |
| 80 | isAfterToday, |
| 81 | tooltipFormatter, |
| 82 | unit, |
| 83 | }: MultiAttributeTooltipContentProps) => { |
| 84 | const sumValue = values.reduce((a, b) => a + Number(b.value), 0) |
| 85 | return ( |
| 86 | <> |
| 87 | {isAfterToday ? ( |
| 88 | <p className="text-foreground-light text-lg">No data yet</p> |
| 89 | ) : ( |
| 90 | <div className="space-y-1 pb-1"> |
| 91 | {attributes.flatMap((attr) => { |
| 92 | const attributeMeta = values.find((x) => x.dataKey === attr.key) |
| 93 | |
| 94 | // Filter out empty attributes |
| 95 | if (Number(attributeMeta?.value ?? 0) === 0) return [] |
| 96 | |
| 97 | return ( |
| 98 | <AttributeContent |
| 99 | key={attr.name} |
| 100 | attribute={attr} |
| 101 | attributeMeta={attributeMeta} |
| 102 | sumValue={sumValue} |
| 103 | tooltipFormatter={tooltipFormatter} |
| 104 | unit={unit} |
| 105 | /> |
| 106 | ) |
| 107 | })} |
| 108 | </div> |
| 109 | )} |
| 110 | </> |
| 111 | ) |
| 112 | } |