import { FunctionComponent, useState, ReactNode } from 'react' import { useTheme } from 'next-themes' import dayjs from 'dayjs' import { AreaChart, Area, Cell, XAxis, YAxis, Tooltip, BarChart, Bar, ReferenceLine, } from 'recharts' import useDimensions from 'react-cool-dimensions' import { numberCompactFormatter } from '../utils' interface ChartProps { data: any daysRange?: number hideRangeFilters?: boolean title?: string xAxis: string yAxis: string yAxisWidth?: number type: string labelFormat: (x) => ReactNode tickFormat?: (x) => any showAll?: boolean titleValue?: number useMulticoloredBars?: boolean zeroLine?: boolean } const Chart: FunctionComponent = ({ title, xAxis, yAxis, data, daysRange, labelFormat, tickFormat, type, hideRangeFilters, yAxisWidth, showAll = false, titleValue, useMulticoloredBars, zeroLine, }) => { const [mouseData, setMouseData] = useState(null) const [daysToShow, setDaysToShow] = useState(daysRange || 30) const { observe, width, height } = useDimensions() const { theme } = useTheme() const handleMouseMove = (coords) => { if (coords.activePayload) { setMouseData(coords.activePayload[0].payload) } } const handleMouseLeave = () => { setMouseData(null) } const handleDaysToShow = (time) => { const startFrom = time ? new Date(Date.now() - time * 24 * 60 * 60 * 1000).getTime() : null return startFrom ? data.filter((d) => new Date(d.time).getTime() > startFrom) : data } const formatDateAxis = (date) => { if (daysToShow === 1) { return dayjs(date).format('h:mma') } else { return dayjs(date).format('D MMM') } } return (
{title}
{mouseData ? ( <>
{labelFormat(mouseData[yAxis])}
{new Date(mouseData[xAxis]).toDateString()}
) : data.length > 0 ? ( <>
{titleValue ? labelFormat(titleValue) : labelFormat(data[data.length - 1][yAxis])}
{titleValue ? '' : new Date(data[data.length - 1][xAxis]).toDateString()}
) : ( <>
)}
{!hideRangeFilters ? (
{showAll ? ( ) : null}
) : null}
{width > 0 && type === 'area' ? ( } /> 0 ? false : true} dy={10} minTickGap={20} tick={{ fill: theme === 'Light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.35)', fontSize: 10, }} tickLine={false} tickFormatter={(v) => formatDateAxis(v)} /> 0 ? false : true} dx={-10} domain={['dataMin', 'dataMax']} tick={{ fill: theme === 'Light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.35)', fontSize: 10, }} tickLine={false} tickFormatter={ tickFormat ? (v) => tickFormat(v) : (v) => numberCompactFormatter.format(v) } type="number" width={yAxisWidth || 50} /> {zeroLine ? ( ) : null} ) : null} {width > 0 && type === 'bar' ? ( } /> {data.map((entry, index) => ( 0 ? 'url(#greenGradientBar)' : 'url(#redGradientBar)' : 'url(#defaultGradientBar)' } /> ))} 0 ? false : true} dy={10} minTickGap={20} tick={{ fill: theme === 'Light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.35)', fontSize: 10, }} tickLine={false} tickFormatter={(v) => formatDateAxis(v)} /> 0 ? false : true} dx={-10} tick={{ fill: theme === 'Light' ? 'rgba(0,0,0,0.4)' : 'rgba(255,255,255,0.35)', fontSize: 10, }} tickLine={false} tickFormatter={ tickFormat ? (v) => tickFormat(v) : (v) => numberCompactFormatter.format(v) } type="number" width={yAxisWidth || 50} /> {zeroLine ? ( ) : null} ) : null}
) } export default Chart