import React, { ReactElement, useCallback, useEffect, useState } from 'react'; import { observer } from 'mobx-react-lite'; import { CustomModalContent, PickerModalState } from '../../hooks'; import { ComputedQuery, FiltersMap } from '@wix/bex-core'; import { Box, FloatingNotification, FloatingNotificationProps, IconElement, Text, TextButton, } from '@wix/design-system'; import { CollectionSearch } from '../CollectionSearch'; import { Picker, PickerProps } from '../Picker'; import { CollectionProvider } from '../CollectionContext'; import { BulkSelectionMaxSelectionLabel, MaxSelectionLabelProps, MultipleSelection, reachedMaxSelection, showMaxSelectionLabel, } from '../MaxSelection'; import { PickerContentState } from '../../state'; import { MaybeTooltip } from '../MaybeTooltip'; import { PickerListItemProps } from '../PickerListItemProps'; import { SelectAllCheckbox } from './SelectAllCheckbox'; import { MultiCollectionSupportProvider } from '../MultiCollectionSupportProvider'; import { PickerContentBaseWrapped, PickerContentBaseWrappedProps, } from './PickerContentBaseWrapped'; import { FilterRenderingContextProvider } from '../FilterRenderingContext'; import { CollectionSearchElement } from '../assertComponentType'; import { isValidElement } from '../isValidElement'; export interface PickerContentItemsSelectionProps extends Partial { modalState: PickerModalState; customContentButtonText?: string; customContentButtonPrefixIcon?: IconElement; /** * A callback to be called when the custom content button is clicked */ customContentButtonOnClick?: (param: { onClose: (newItems?: T[]) => void; }) => void; customContent?: CustomModalContent; /** * Shows "Select All" checkbox as a side action (overrides "customContent" prop). * If `multiple={number}` or `multiple={false}` are used, this prop does nothing. */ showSelectAllCheckbox?: boolean; multiple?: MultipleSelection; /** * Shows a SingleSelectFilter component in a picker modal to filter items; */ filterComponent?: ReactElement; /** * A function that render a item row in the selector list */ renderItem: (item: T, index: number) => Partial; /** * A render function to be rendered when there're no items to show in the table.
* You can use the built in [``](./?path=/story/features-display-empty-states--collectionemptystate).
* The function accepts the following parameters * * `hasAvailableItems`: Indicates whether other items might have been shown using other filtering / search * * `query`: An instance of [ComputedQuery](./?path=/story/common-types--computedquery) that represents the query that resulted with an empty state */ renderEmptyState?: (params: { hasAvailableItems: boolean; query: ComputedQuery; }) => ReactElement | null | undefined; renderError: PickerProps['renderError']; /** * When set to `true`, the modal primary button will be always enabled. */ enablePrimaryButton?: boolean; /** * Displays a search input in the picker modal. * Accepts a boolean or a custom CollectionSearch element as a parameter. * When passing `false`, no search input is displayed. * @default true * @external */ search?: boolean | CollectionSearchElement; /** * @deprecated Use search={false} instead * Hides the search input of the picker */ hideSearch?: boolean; /** * Function that returns label for multi selection like: * '2 items selected (24 max)` * This function accepts argument {num: number, max: number} */ customMaxSelectionLabel?: MaxSelectionLabelProps['customLabel']; /** * Function that returns custom notification that will be displayed in the picker modal. * Useful to describe additional information about the selection (for instance how to increase limit of selected items). * @param data.selected - number of selected items * @param data.total - total number of items */ renderCustomNotification?: (data: { selected?: number; total?: number; }) => ReactElement; /** Displays count of selected items in `sideActions` */ showSelectedCount?: boolean; } interface PickerContentItemsSelectionStateProps { state: PickerContentState; renderPickerContent: (params: { state: PickerContentState; renderItem: PickerContentItemsSelectionProps['renderItem']; }) => ReactElement; } export type PickerContentItemsSelectionFullProps< T, F extends FiltersMap = FiltersMap, > = PickerContentItemsSelectionProps & PickerContentItemsSelectionStateProps; function _PickerContentItemsSelection( props: PickerContentItemsSelectionFullProps, ) { const { modalState, primaryButtonProps, renderEmptyState, renderError, state, multiple, customContentButtonText, customContentButtonPrefixIcon, customContentButtonOnClick, customContent, showSelectAllCheckbox, enablePrimaryButton, search, hideSearch, renderPickerContent, customMaxSelectionLabel, renderCustomNotification, filterComponent, showSelectedCount, ...rest } = props; const { _customContent } = modalState; const { picker } = state; const { collection } = picker; const { bulkSelect, translate: t, showInitialLoader } = collection; const { isEmpty: isSelectEmpty } = bulkSelect; useEffect(() => { _customContent.value = () => customContent; }, []); const reachedMax = reachedMaxSelection({ collection, multiple, }); const [filterRenderingContextValue] = useState(() => ({ location: 'modal' as const, })); const onCustomContentButtonClick = useCallback(() => { state.onCreateNewButtonClick(customContentButtonOnClick); }, [customContentButtonOnClick]); const renderItem: (typeof props)['renderItem'] = (item, index) => { const renderedItem = props.renderItem(item, index); const key = collection.itemKey(item); return { ...renderedItem, disabled: (reachedMax && !collection.bulkSelect.selectedIds.includes(key)) || renderedItem.disabled, }; }; const searchElement = isValidElement(search) ? ( React.cloneElement(search as CollectionSearchElement, { minWidthPixels: '100%', }) ) : search !== false ? ( ) : null; const shouldShowSearch = search !== undefined ? search !== false : !hideSearch; const resolvedSearchElement = shouldShowSearch ? searchElement : null; const renderSideActions = () => { if ( showSelectAllCheckbox && !showInitialLoader && (multiple === true || multiple === Infinity) ) { return ; } const shouldShowCustomContentButton = customContent || customContentButtonOnClick; if (shouldShowCustomContentButton) { return (
{customContentButtonText ?? t('cairo.picker.createNew.button')}
); } if (showSelectedCount) { return ( {t('cairo.selector.modal.items.selected', { total: collection.bulkSelect.selectedCount, })} ); } return null; }; const renderFiltersComponent = () => { return ( {filterComponent} {resolvedSearchElement && <>{resolvedSearchElement}} ); }; const showMaxSelection = showMaxSelectionLabel(multiple); return ( {(resolvedSearchElement || filterComponent || renderCustomNotification || showMaxSelection) && ( {filterComponent ? renderFiltersComponent() : resolvedSearchElement} {renderCustomNotification ? ( {renderCustomNotification({ selected: collection.bulkSelect.selectedCount, total: collection.result.total, })} ) : null} {showMaxSelection && ( )} )} {renderPickerContent?.({ state, renderItem })} ); } export const PickerContentItemsSelection = observer( _PickerContentItemsSelection, );