import { Meta, StoryObj } from '@storybook/react-webpack5'; import React, { useState } from 'react'; import { useTheme } from 'styled-components'; import { Barchart, BarchartProps, BarchartSortFn, BarchartTooltipFn, ChartLegendWrapper, ChartLegend, } from '../../src/lib/components/charts'; import { Button } from '../../src/lib/components/buttonv2/Buttonv2.component'; import { Text } from '../../src/lib/components/text/Text.component'; import { spacing, Stack, Wrap } from '../../src/lib/spacing'; import { CoreUITheme } from '../../src/lib/style/theme'; import { Wrapper } from '../common'; type Story = StoryObj; const meta: Meta = { title: 'Components/Data Display/Charts/Barchartv2', component: Barchart, decorators: [ (story) => ( {story()} ), ], parameters: { layout: 'centered', }, }; export default meta; export const Playground: Story = { render: () => { const theme = useTheme() as CoreUITheme; const exampleData = [ { label: 'Success', data: [ ['category1', 0.001], ['category2', 0.005], ['category3', 0.002], ], }, { label: 'Failed', data: [ ['category1', 0.01], ['category2', 0.05], ['category3', 0.02], ], }, ] as const; return ( ); }, }; const timeData7Days = [ { label: 'Success', data: [ // 7 days ago - aligned to the exact timestamp that generateTimestamps will create [new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), 15], // 6 days ago [new Date(Date.now() - 6 * 24 * 60 * 60 * 1000), 12], // 5 days ago [new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), 30], // 4 days ago [new Date(Date.now() - 4 * 24 * 60 * 60 * 1000), 20], // 3 days ago [new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), 25], // 2 days ago [new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), 18], // 1 day ago [new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), 32], ], }, { label: 'Failed', data: [ // 7 days ago [new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), 5], // 6 days ago [new Date(Date.now() - 6 * 24 * 60 * 60 * 1000), 8], // 5 days ago [new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), 2], // 4 days ago [new Date(Date.now() - 4 * 24 * 60 * 60 * 1000), 12], // 3 days ago [new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), 6], // 2 days ago [new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), 9], // 1 day ago [new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), 7], ], }, ] as const; export const Time7Days: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; const timeData7DaysWithMissingData = [ { label: 'Success', data: [ // 7 days ago [new Date(Date.now() - 7 * 24 * 60 * 60 * 1000 + 12), 15], // 5 days ago [new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), 30], // 4 days ago [new Date(Date.now() - 4 * 24 * 60 * 60 * 1000), 20], // 3 days ago // 2 days ago [new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), 18], // 1 day ago [new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), 32], ], }, { label: 'Failed', data: [ // 7 days ago [new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), 5], // 6 days ago // 5 days ago [new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), 1], // 4 days ago // 3 days ago [new Date(Date.now() - 3 * 24 * 60 * 60 * 1000), 6], // 2 days ago [new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), 9], // 1 day ago [new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), 7], ], }, ] as const; export const Time7DaysWithMissingData: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; const timeDataLast24Hours = [ { label: 'Success', data: [ [new Date(Date.now() - 24 * 60 * 60 * 1000), 15], [new Date(Date.now() - 23 * 60 * 60 * 1000), 12], [new Date(Date.now() - 22 * 60 * 60 * 1000), 30], [new Date(Date.now() - 21 * 60 * 60 * 1000), 20], [new Date(Date.now() - 20 * 60 * 60 * 1000), 25], [new Date(Date.now() - 19 * 60 * 60 * 1000), 18], [new Date(Date.now() - 18 * 60 * 60 * 1000), 32], [new Date(Date.now() - 17 * 60 * 60 * 1000), 19], [new Date(Date.now() - 16 * 60 * 60 * 1000), 10], [new Date(Date.now() - 15 * 60 * 60 * 1000), 11], [new Date(Date.now() - 14 * 60 * 60 * 1000), 12], [new Date(Date.now() - 13 * 60 * 60 * 1000), 13], [new Date(Date.now() - 12 * 60 * 60 * 1000), 11], [new Date(Date.now() - 11 * 60 * 60 * 1000), 17], [new Date(Date.now() - 10 * 60 * 60 * 1000), 16], [new Date(Date.now() - 9 * 60 * 60 * 1000), 13], [new Date(Date.now() - 8 * 60 * 60 * 1000), 15], [new Date(Date.now() - 7 * 60 * 60 * 1000), 16], [new Date(Date.now() - 6 * 60 * 60 * 1000), 17], [new Date(Date.now() - 5 * 60 * 60 * 1000), 18], [new Date(Date.now() - 4 * 60 * 60 * 1000), 19], [new Date(Date.now() - 3 * 60 * 60 * 1000), 20], [new Date(Date.now() - 2 * 60 * 60 * 1000), 21], [new Date(Date.now() - 1 * 60 * 60 * 1000), 22], ], }, { label: 'Failed', data: [ [new Date(Date.now() - 24 * 60 * 60 * 1000), 5], [new Date(Date.now() - 23 * 60 * 60 * 1000), 8], [new Date(Date.now() - 22 * 60 * 60 * 1000), 2], [new Date(Date.now() - 21 * 60 * 60 * 1000), 12], [new Date(Date.now() - 20 * 60 * 60 * 1000), 6], [new Date(Date.now() - 19 * 60 * 60 * 1000), 9], [new Date(Date.now() - 18 * 60 * 60 * 1000), 7], [new Date(Date.now() - 17 * 60 * 60 * 1000), 1], [new Date(Date.now() - 16 * 60 * 60 * 1000), 1], [new Date(Date.now() - 15 * 60 * 60 * 1000), 2], [new Date(Date.now() - 14 * 60 * 60 * 1000), 4], [new Date(Date.now() - 13 * 60 * 60 * 1000), 2], [new Date(Date.now() - 12 * 60 * 60 * 1000), 3], [new Date(Date.now() - 11 * 60 * 60 * 1000), 1], [new Date(Date.now() - 10 * 60 * 60 * 1000), 1], [new Date(Date.now() - 9 * 60 * 60 * 1000), 1], [new Date(Date.now() - 8 * 60 * 60 * 1000), 1], [new Date(Date.now() - 7 * 60 * 60 * 1000), 1], [new Date(Date.now() - 6 * 60 * 60 * 1000), 1], [new Date(Date.now() - 5 * 60 * 60 * 1000), 1], [new Date(Date.now() - 4 * 60 * 60 * 1000), 5], [new Date(Date.now() - 3 * 60 * 60 * 1000), 3], [new Date(Date.now() - 2 * 60 * 60 * 1000), 2], [new Date(Date.now() - 1 * 60 * 60 * 1000), 1], ], }, ] as const; export const TimeLast24Hours: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; const capacityDataWithUnitRange = [ { label: 'Free', data: [ ['category1', 2000000], ['category2', 4000000], ['category3', 6000000], ], }, { label: 'Used', data: [ ['category1', 8000000], ['category2', 10000000], ['category3', 12000000], ], }, ] as const; export const CapacityWithUnitRange: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; const stackedData: BarchartProps< { label: 'Success' | 'Failed' | 'Warning'; data: [string, number][]; }[] >['bars'] = [ { label: 'Success', data: [ ['category1', 25], ['category2', 72], ['category3', 52], ], }, { label: 'Failed', data: [ ['category1', 0], ['category2', 0], ['category3', 0], ], }, { label: 'Warning', data: [ ['category1', 0], ['category2', 0], ['category3', 0], ], }, ]; export const Stacked: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; export const DefaultSort: Story = { render: () => { const theme = useTheme() as CoreUITheme; const defaultSortData = [ { label: 'Success', data: [ ['AZ', 15], ['BB', 10], ['CC', 25], ['DD', 18], ['AA', 22], ['EE', 15], ], }, { label: 'Failed', data: [ ['AZ', 8], ['BB', 1], ['CC', 3], ['DD', 1], ['AA', 5], ['EE', 5], ], }, ] as const; const customSort: BarchartSortFn = ( pointA, pointB, ) => { const totalA = pointA.Success + pointA.Failed; const totalB = pointB.Success + pointB.Failed; return totalA - totalB > 0 ? -1 : totalA - totalB < 0 ? 1 : 0; // Descending order }; return ( ); }, }; export const WithCustomTooltip: Story = { render: () => { const theme = useTheme() as CoreUITheme; const exampleData = [ { label: 'Success', data: [ ['category1', 2], ['category2', 4], ['category3', 6], ], }, { label: 'Failed', data: [ ['category1', 8], ['category2', 10], ['category3', 12], ], }, ] as const; const customTooltip: BarchartTooltipFn = (pointA) => { return ( {pointA.category} {pointA.values.map((point) => ( {point.label}: {point.value} ))} ); }; return ( External Tooltip & Sort Functions Tooltip and sort functions defined outside with full type safety ); }, }; const exampleData = [ { label: 'Success', data: [ ['category1', 1000000], ['category2', 2000000], ['category3', 3000000], ], }, { label: 'Failed', data: [ ['category1', 1000000], ['category2', 2000000], ['category3', 3000000], ], }, ] as const; export const StatusColors: Story = { render: () => { const theme = useTheme() as CoreUITheme; const statusData = [ { label: 'Success Rate', data: [ ['API', 95], ['Database', 87], ['Queue', 92], ], }, { label: 'Failed Requests', data: [ ['API', 5], ['Database', 13], ['Queue', 8], ], }, { label: 'Warning Events', data: [ ['API', 2], ['Database', 4], ['Queue', 1], ], }, ] as const; return ( { const statusOrder: Record = { 'Success Rate': 0, 'Warning Events': 1, 'Failed Requests': 2, }; return statusOrder[a] - statusOrder[b]; }} > ); }, }; export const LegendShapes: Story = { render: () => { const theme = useTheme() as CoreUITheme; const exampleData = [ { label: 'Success', data: [ ['category1', 25], ['category2', 40], ['category3', 35], ], }, { label: 'Failed', data: [ ['category1', 15], ['category2', 20], ['category3', 18], ], }, { label: 'Warning', data: [ ['category1', 8], ['category2', 12], ['category3', 10], ], }, ] as const; return ( Legend Shapes ); }, }; export const BarchartsWithSingleLegend: Story = { render: () => { const theme = useTheme() as CoreUITheme; const exampleData = [ { label: 'Success', data: [ ['category1', 25], ['category2', 40], ['category3', 35], ], }, { label: 'Failed', data: [ ['category1', 15], ['category2', 20], ['category3', 18], ], }, { label: 'Warning', data: [ ['category1', 8], ['category2', 12], ['category3', 10], ], }, ] as const; return ( Barcharts with Single Shared Legend ); }, }; export const ErrorState: Story = { render: () => { const theme = useTheme() as CoreUITheme; return ( ); }, }; export const StackedBarSort: Story = { render: () => { const theme = useTheme() as CoreUITheme; const [sort, setSort] = useState<'default' | 'legend'>('default'); const statusesData = [ { label: 'Success', data: [ ['category1', 100], ['category2', 80], ['category3', 50], ], }, { label: 'Warning', data: [ ['category1', 10], ['category2', 20], ['category3', 30], ], }, { label: 'Failed', data: [ ['category1', 30], ['category2', 40], ['category3', 50], ], }, ] as const; return ( setSort(sort === 'default' ? 'legend' : 'default')} /> } /> ); }, }; export const CompleteExample: Story = { render: () => { const theme = useTheme() as CoreUITheme; const [isLoading, setIsLoading] = useState(true); const [data, setData] = useState< BarchartProps['bars'] | undefined >(undefined); const customTooltip: BarchartTooltipFn = (pointA) => { return ( {pointA.category} {pointA.values.map((point) => ( {point.label}: {point.value} ))} ); }; return (
{ setIsLoading(!isLoading); if (isLoading) { setData(exampleData); } else { setData(undefined); } }} /> } bars={data} tooltip={customTooltip} isLoading={isLoading} height={200} />
); }, }; export const Histogram: Story = { render: () => { const histogramData = [ { label: 'Success', data: [ ['0-10', 1], ['10-20', 5], ['20-30', 15], ['30-40', 40], ['40-50', 45], ['50-60', 50], ['60-70', 40], ['70-80', 15], ['80-90', 5], ['90-100', 1], ], }, ] as const; const theme = useTheme() as CoreUITheme; return (
); }, }; export const ModernPreset: Story = { render: () => { const theme = useTheme() as CoreUITheme; const data = [ { label: 'Success', data: [ ['category1', 25], ['category2', 40], ['category3', 35], ['category4', 28], ['category5', 47], ], }, { label: 'Failed', data: [ ['category1', 8], ['category2', 12], ['category3', 6], ['category4', 15], ['category5', 9], ], }, ] as const; return (
Default preset
Modern preset
); }, }; export const StackedHistogram: Story = { render: () => { const histogramData = [ { label: 'Test 1', data: [ ['0-10', 1], ['10-20', 5], ['20-30', 15], ['30-40', 40], ['40-50', 45], ['50-60', 50], ['60-70', 40], ['70-80', 15], ['80-90', 5], ['90-100', 1], ], }, { label: 'Test 2', data: [ ['0-10', 1], ['10-20', 2], ['20-30', 4], ['30-40', 4], ['40-50', 5], ['50-60', 6], ['60-70', 6], ['70-80', 3], ['80-90', 2], ['90-100', 1], ], }, ] as const; const theme = useTheme() as CoreUITheme; return (
); }, };