import React, { useMemo, useState } from 'react' import { type Meta, type StoryObj } from '@storybook/react-vite' import { type DateRange } from 'react-day-picker' import { DocsTemplate } from '../../../.storybook' import ExposedFilterGroupComponent from './ExposedFilterGroup' import { type MultiSelectDataItemBase } from '../MultiSelect/MultiSelect' import { type MinMaxRange } from '../RangeFilter/RangeFilter' import { type ExposedFilterNameType, type ExposedFilterProps, } from '../ExposedFilter/ExposedFilter.models' import { CheckboxState, type DateCheckState, getFlattenNestedTreeList, } from '../Form/NestedCheckboxHelper' import { generateDummyNestedMultiSelectData } from '../MultiSelect/MultiSelectStoryHelpers' import FormFooter from '../Form/FormFooter' import { type ModalProps } from '../Modal/Modal' import Checkbox from '../Form/Checkbox' interface FilterType extends MultiSelectDataItemBase, ExposedFilterNameType {} const meta: Meta = { title: 'Components/ExposedFilter/ExposedFilterGroup', component: ExposedFilterGroupComponent, parameters: { docs: { page: () => ( The ExposedFilterGroup component can be used to display multiple filters directly on the page. } infoBullets={[ Utilize the ExposedFilterGroup component to display multiple exposed filters without a SideDrawer , ]} /> ), }, }, } export default meta type Story = StoryObj const Template: Story = { render: ({ ...args }) => { return }, } interface FilterStateType { status: FilterType[] category: FilterType[] date?: Date dateRange?: DateRange priority?: FilterType search?: string amount?: MinMaxRange nestedItemStates?: { id: string | number state: CheckboxState }[] modal?: string[] } const ExposedFilterGroup = (args) => { const [filtersState, setFiltersState] = useState({ status: [ { id: 1, name: 'Created' }, { id: 2, name: 'Arrived' }, { id: 3, name: 'Processed' }, ], category: [], date: undefined, dateRange: undefined, priority: undefined, search: '', amount: { min: undefined, max: undefined }, nestedItemStates: [], }) const resetCallout = () => { setFiltersState({ status: [], category: [], date: undefined, dateRange: undefined, priority: undefined, amount: { min: undefined, max: undefined }, nestedItemStates: [], }) } const [tempModalSelection, setTempModalSelection] = useState( filtersState?.modal || [], ) const [isModalOpen, setIsModalOpen] = useState(false) const onChangeCallout: ExposedFilterProps['onChangeCallout'] = ( filterName, value, ) => { setFiltersState((prevState) => ({ ...prevState, [filterName]: value, })) if (filterName === 'modal') { setTempModalSelection((value as string[]) || []) } } const nestedMultiSelectData = generateDummyNestedMultiSelectData() const flattenData = useMemo( () => getFlattenNestedTreeList({ nestedData: nestedMultiSelectData ?? [], childrenKey: 'children', parentKey: 'parent_category_id', idKey: 'id', }), [nestedMultiSelectData], ) const defaultItemStates = useMemo( () => flattenData.map((i) => ({ id: i['id'] as string | number, state: CheckboxState.UNCHECKED, })), [flattenData], ) const identifierKeys = { displayKey: 'name', idKey: 'id', parentKey: 'parent_category_id', } const tableConfig = [ { label: '', dataKey: 'name', children: (data) => {data.name}, }, ] const [itemStates, setItemStates] = useState(defaultItemStates) const statuses = [ { id: 1, name: 'Created' }, { id: 2, name: 'Arrived' }, { id: 3, name: 'Processed' }, { id: 4, name: 'Receiving' }, { id: 5, name: 'Canceled' }, ] const categories = [ { id: 1, name: 'Electronics' }, { id: 2, name: 'Clothing' }, { id: 3, name: 'Food' }, { id: 4, name: 'Home' }, { id: 5, name: 'Beauty' }, ] const priorities = [ { id: 1, name: 'High' }, { id: 2, name: 'Medium' }, { id: 3, name: 'Low' }, ] const statusMultiSelectProps = { options: statuses, searchBarProps: { placeholder: 'Search', }, emptyStateProps: { primaryText: 'No Status Found', secondaryText: 'Try searching for a different status', }, labelKey: 'name', hideSelectAll: true, selectedOptions: filtersState.status, } const categoryMultiSelectProps = { options: categories, searchBarProps: { placeholder: 'Search categories', }, emptyStateProps: { primaryText: 'No Category Found', secondaryText: 'Try searching for a different category', }, labelKey: 'name', hideSelectAll: true, selectedOptions: filtersState.category, } const prioritySelectProps = { options: priorities, searchBarProps: { placeholder: 'Search priorities', }, emptyStateProps: { primaryText: 'No Priority Found', secondaryText: 'Try searching for a different priority', }, labelKey: 'name', selectedOption: filtersState.priority, } const dateProps = { type: 'single', selectedDate: filtersState.date, } const dateRangeProps = { type: 'range', selectedDateRange: filtersState.dateRange, } const withSearch = { type: 'search', stateName: 'search', searchBarProps: { value: filtersState.search, placeholder: 'Search', }, } const amountRangeProps = { selectedValues: filtersState.amount, } const nestedProps = { selectedOptions: filtersState.nestedItemStates, options: nestedMultiSelectData, labelKey: 'name', nestedConfig: { data: flattenData, itemStates, setItemStates, identifierKeys, tableConfig, }, } const modalProps: ModalProps = { isOpen: isModalOpen, closeCallout: () => setIsModalOpen(false), size: 'sm', headerContent: 'Item Filter', footerContent: ( { setFiltersState((prevState) => ({ ...prevState, modal: tempModalSelection, })) setIsModalOpen(false) }, children: 'filter', styleType: 'primary', }} cancelButtonProps={{ onClick: () => { setIsModalOpen(false) }, }} /> ), children: (
{ setTempModalSelection((prev) => prev.includes('P0NEIWB5') ? prev.filter((item) => item !== 'P0NEIWB5') : [...prev, 'P0NEIWB5'], ) }} checkboxColor='blue' type='checkbox' /> { setTempModalSelection((prev) => prev.includes('P0OGSJWM') ? prev.filter((item) => item !== 'P0OGSJWM') : [...prev, 'P0OGSJWM'], ) }} checkboxColor='blue' type='checkbox' />
), } const filters = [ { type: 'multi-select', stateName: 'status', labelName: 'Status', multiSelectProps: statusMultiSelectProps, }, { type: 'multi-select', stateName: 'category', labelName: 'Category', multiSelectProps: categoryMultiSelectProps, }, { type: 'date', dateProps: dateProps, stateName: 'date', labelName: 'Date', }, { type: 'date', dateProps: dateRangeProps, stateName: 'dateRange', labelName: 'Date Range', }, { type: 'select', stateName: 'priority', labelName: 'Priority', selectProps: prioritySelectProps, }, { type: 'range', rangeProps: amountRangeProps, labelName: 'Amount', stateName: 'amount', }, { type: 'multi-select', labelName: 'Nested', stateName: 'nestedItemStates', multiSelectProps: nestedProps, }, { type: 'modal', labelName: 'Modal', stateName: 'modal', openCallout: () => setIsModalOpen(true), selectedOption: filtersState.modal, modalProps: modalProps, }, ] return args.type === 'search' ? ( ) : ( ) } export const Basic: Story = { ...Template, } export const WithSearchBar: Story = { ...Template, args: { type: 'search', }, }