import React, { useCallback, useEffect, useRef, useState } from 'react' import { type Meta, type StoryObj } from '@storybook/react-vite' import { Cell, Row } from 'react-sticky-table' import { DocsTemplate } from '../../../.storybook' import CustomTable from './CustomTable' import { activeCellClass, hasStickyColumnStyle, } from '../../services/HelperServiceTyped' import JavascriptDisplay from '../JavascriptDisplay/JavascriptDisplay' const meta: Meta = { title: 'Components/Tables/CustomTable', component: CustomTable, parameters: { layout: 'padded', design: { type: 'figma', url: 'https://www.figma.com/design/RvhKD82948FMQnh5MyCi0o/Web-Design-System?node-id=121-349&t=CdMnrLNv0lNFwXr0-0', }, docs: { page: () => (
CustomTable is a component that allows you to display data in a table format. It is a wrapper around the{' '} react-sticky-table {' '} library. The biggest difference here is that the table does not fit all the standards set by the StandardTable, so a custom solution is necessary. Though the UI may look exactly the same, some custom functionality is needed for a requirement, making this component necessary. If at all possible, the recommendation is to use the StandardTable{' '} component.

Some important notes to keep in mind while implementing the{' '} CustomTable:
} /> ), }, }, } export default meta type Story = StoryObj type DataItem = { isTotalRow: boolean name: string asin: string multiple: { value: number; change: number } is_map: string is_enabled: string price: number map_price: number } const tableDummyData = (pageNum: number): DataItem[] => { const data: DataItem[] = [] for (let i = 1; i <= 20; i++) { const num = pageNum > 1 ? (pageNum - 1) * 20 + i : i data.push({ isTotalRow: i === 1 && num === 1, name: `Product Name ${num}`, asin: `Test ASIN ${num}`, multiple: { value: 32 + num, change: (num % 3 ? 1 : -1) * i }, is_map: num % 2 ? 'Yes' : num % 3 ? 'No' : '', is_enabled: num % 2 ? 'Disabled' : 'Enabled', price: 12 * num + 1, map_price: 12 * num + 2, }) } return data } type TableColumnType = { cellName: keyof DataItem cellIndex: number } const tableHeaders = [ { id: 1, name: 'name', label: 'Name', }, { id: 2, name: 'asin', label: 'ASIN' }, { id: 3, label: 'Multiple Values Example', options: [ { name: 'multiple', label: 'Main Value', }, { name: 'change__multiple', label: 'Change Value', }, ], }, { id: 4, name: 'is_map', label: 'MAP' }, { id: 5, name: 'is_enabled', label: 'Status' }, { id: 6, name: 'price', label: 'Price' }, { id: 7, name: 'map_price', label: 'MAP Price' }, ] const tableColumns: TableColumnType[] = [ { cellName: 'name', cellIndex: 1, }, { cellName: 'asin', cellIndex: 2, }, { cellName: 'multiple', cellIndex: 3, }, { cellName: 'is_map', cellIndex: 4, }, { cellName: 'is_enabled', cellIndex: 5, }, { cellName: 'price', cellIndex: 6, }, { cellName: 'map_price', cellIndex: 7, }, ] const Template: Story = { render: function Render(args) { const [state, setState] = useState<{ data: DataItem[] loading: boolean pageNumber: number }>({ data: [], loading: false, pageNumber: 1, }) const { data, loading, pageNumber } = state const [sort, setSort] = useState({ prop: 'name', flip: false, }) const dataTimeout = useRef>() const getData = useCallback((pageNum: number) => { if (pageNum === 1) { setState((prevState) => ({ ...prevState, loading: true, })) } dataTimeout.current = setTimeout(() => { setState((prevState) => ({ ...prevState, data: prevState.data.concat(tableDummyData(pageNum)), pageNumber: pageNum + 1, loading: false, })) }, 500) }, []) const setSortBy = (sortObj: { activeColumn: string direction: boolean }) => { setSort({ prop: sortObj.activeColumn, flip: sortObj.direction, }) } useEffect(() => { getData(1) }, [getData]) useEffect(() => { return () => { clearTimeout(dataTimeout.current as ReturnType) } }, []) const tableProps = { ...args, hasData: args.hasData ?? data?.length > 0, hasMore: true, successStatus: true, loading: args.loading ?? loading, tableId: 'demo-table', noDataFields: { primaryText: `No Data Found`, secondaryText: `We could not find any data for the selected criteria.`, }, getData: () => getData(pageNumber), ...(args.tableHeaderProps ? { tableHeaderProps: args.tableHeaderProps } : {}), } let sortProps = {} if (!args.noSort) { sortProps = { sort: setSortBy, sortBy: sort } } return ( {data.map((e) => ( {tableColumns.map((tc) => { const value = tc.cellName === 'multiple' ? (
{e.multiple.value}
{e.multiple.change}
) : ( {e[tc.cellName]} ) return ( {value} ) })}
))}
) }, } export const Basic: Story = { ...Template, args: { headers: tableHeaders, stickyTableConfig: { left: 1, right: 0, }, }, } export const CustomHeight: Story = { ...Template, args: { headers: tableHeaders, customHeight: '300px', }, } export const CustomWidth: Story = { ...Template, args: { headers: tableHeaders, customWidth: '400px', customHeight: '400px', }, } export const StickyColumns: Story = { ...Template, args: { headers: tableHeaders, customHeight: '400px', stickyTableConfig: { left: 2, right: 1, }, }, } export const NoData: Story = { ...Template, args: { headers: tableHeaders, customHeight: '400px', hasData: false, }, } export const TableHeader: Story = { ...Template, args: { headers: tableHeaders, tableHeaderProps: { leftSectionChildren:
Custom Table
, tooltip: { tooltipContent: 'This is a custom table', }, }, }, } export const NoSort: Story = { ...Template, args: { headers: tableHeaders, noSort: true, }, }