import React, {
Fragment,
ReactNode,
useEffect,
useMemo,
useState,
} from 'react';
import { Box } from '@wix/design-system';
import { FilterElement } from './filterElement';
import { useFiltersLayout } from './useFiltersLayout';
import { useToolbarCollectionContext } from '../ToolbarCollectionContext';
import { AppliedFiltersTagList } from '../AppliedFiltersTagList';
import { observer } from 'mobx-react-lite';
import { ToolbarItemBox } from '../ToolbarItemBox';
import { AppliedFiltersTagListState } from '../AppliedFiltersTagList/AppliedFiltersTagListState';
import { CollectionToolbarFiltersState } from './CollectionToolbarFiltersState';
import { getFieldTypeIcon } from '../../utils/fieldTypePrefixIcons';
import { CollectionFilter } from '../CollectionFilter';
import { FiltersPanelSidePanelEntry } from './FiltersPanelSidePanelEntry';
import { MoreFiltersCTA } from '../MoreFiltersCTA';
import { useWixPatternsContainer } from '@wix/bex-core/react';
import { useFiltersSyncProps } from './useFiltersSyncProps';
export interface CollectionToolbarFiltersProps {
/**
* Number of filter controls to be rendered inside the table toolbar
*/
inline?: 0 | 1 | 2 | 3;
/**
* A flag that indicates whether Patterns should use a new filters layout our not.
*/
useNewFilters?: true;
maxInlineFilters?: number;
maxInlineLabels?: number;
/**
* Title of the filters panel
* @external
*/
panelTitle?: string | ReactNode;
/**
* `React` children elements, that must accept [FilterProps](./?path=/story/features-filter-props--filterprops), such as:
* - [MultiSelectCheckboxFilter](./?path=/story/features-filter-components--multiselectcheckboxfilter)
* - [Custom Filters](./?path=/story/features-filter-factories--customfilter)
* @external
*/
children:
| (FilterElement | undefined | boolean)
| (FilterElement | undefined | boolean)[];
onPanelClearButtonClicked?: () => unknown;
onSearchAppliedFilterTagRemove?: (item: string) => unknown;
onSubToolbarClearButtonClicked?: () => unknown;
hideAppliedFiltersTagList?: boolean;
}
function _CollectionToolbarFilters(props: CollectionToolbarFiltersProps) {
const {
children,
inline = 2,
maxInlineFilters,
maxInlineLabels,
panelTitle,
onPanelClearButtonClicked,
onSearchAppliedFilterTagRemove,
onSubToolbarClearButtonClicked,
hideAppliedFiltersTagList,
useNewFilters,
} = props;
const childrenArr = useFiltersSyncProps(children);
const state = useToolbarCollectionContext();
const [toolbarFiltersState] = useState(() => {
state.toolbarFiltersState ??= new CollectionToolbarFiltersState({
toolbar: state,
});
state.setToolbarFiltersStateInitialized(true);
return state.toolbarFiltersState;
});
useEffect(() => {
state.panels.registerSidePanel('filters', FiltersPanelSidePanelEntry);
}, []);
useEffect(() => {
toolbarFiltersState.onClearButtonClicked = onPanelClearButtonClicked;
}, [onPanelClearButtonClicked]);
const forceShowSidePanel = useMemo(
() =>
!!childrenArr.slice(0, inline).find((filter) => {
return (
filter.type.displayName &&
[
'DateRangeFilter',
'MultiSelectCollectionFilter',
'RadioGroupFilter',
'MultiInlineCheckboxFilter',
].includes(filter.type.displayName)
);
}),
[childrenArr],
);
const { viewsProps, collection } = state;
const customInlineElements = viewsProps ? 1 : 0;
const { showFiltersPanelButton, totalInlineFilters, showLabels } =
useFiltersLayout({
useNewFilters,
filters: childrenArr.length,
totalFilters: childrenArr.length + customInlineElements,
inline,
maxInlineFilters,
maxInlineLabels,
customInlineElements,
forceShowSidePanel,
});
useEffect(() => {
toolbarFiltersState.panelTitle.set(panelTitle);
}, [panelTitle]);
useEffect(() => {
toolbarFiltersState.totalInlineFilters.set(totalInlineFilters);
}, [totalInlineFilters]);
useEffect(() => {
toolbarFiltersState.filterElements.set(childrenArr);
}, [childrenArr]);
const container = useWixPatternsContainer();
const { filters } = collection;
const filtersProps = useMemo(() => {
// share essential filter props globally
return [
...childrenArr.map(({ props: filterChildProps, type }) => {
const {
filter,
onAppliedFilterTagRemove,
renderToolbarTag,
toolbarTagProps,
accordionItemProps,
} = filterChildProps;
return {
filter,
onAppliedFilterTagRemove,
toolbarTagProps,
accordionItemProps,
renderToolbarTag:
renderToolbarTag ??
type.renderPresetToolbarTag?.(container, {
filterProps: filterChildProps,
}),
};
}),
{
filter: filters.search,
onAppliedFilterTagRemove: onSearchAppliedFilterTagRemove,
},
];
}, [
childrenArr.length,
...childrenArr.map(({ props: { filter } }) => filter),
]);
useEffect(() => {
state.setFilterTagsPropsIfChanged(filtersProps);
return () => {
state.setFilterTagsPropsIfChanged(null);
};
}, [filtersProps]);
useEffect(() => {
if (showFiltersPanelButton) {
state.featuredComponents.moreFiltersButton.set(() => );
return () => {
state.featuredComponents.moreFiltersButton.set(null);
};
}
state.featuredComponents.moreFiltersButton.set(null);
return;
}, [showFiltersPanelButton]);
const [tagListState] = useState(
() =>
new AppliedFiltersTagListState({
table: state,
}),
);
useEffect(() => {
const disposers = [tagListState.init()];
if (hideAppliedFiltersTagList) {
state.featuredComponents.appliedFiltersTagList.set(null);
} else {
state.featuredComponents.appliedFiltersTagList.set({
state: tagListState,
component: () => (
),
});
}
return () => {
disposers.forEach((d) => d());
state.featuredComponents.appliedFiltersTagList.set(null);
};
}, [hideAppliedFiltersTagList]);
const showFieldTypeIcons = state.showFieldTypeIcons;
return (
// workaround to support bad enzyme version not detecting this as a valid fragment component
// https://wix.slack.com/archives/C02K83200PL/p1671962461443749
{childrenArr.slice(0, totalInlineFilters).map((element, index) => {
const { props: filterProps } = element;
const toolbarLabel = filterProps.toolbarItemProps?.label;
let label: React.ReactNode = showLabels && toolbarLabel;
if (showFieldTypeIcons && showLabels && toolbarLabel) {
const toolbarIcon = getFieldTypeIcon({ fieldType: filterProps.fieldType, size: 'medium' });
label = {toolbarIcon}{toolbarLabel};
}
return (
{filterProps.filter ? (
{element}
) : (
element
)}
);
})}
);
}
export const CollectionToolbarFilters = observer(_CollectionToolbarFilters);