import React, { useState, useRef, useEffect } from 'react'; import { TextInput, Surface, Divider, HelperText, Searchbar, Caption, Chip, Text, Avatar, Provider as PaperProvider, useTheme, } from 'react-native-paper'; import { View, Dimensions, Platform, FlatList, ActivityIndicator, // ScrollView, } from 'react-native'; import Modal from 'react-native-modal'; import Lo from 'lodash'; import MultiselectItem from '../Components/MultiselectItem'; import { colors as ConsColors, defaultDropdownProps, ITEMLAYOUT, } from '../constants'; import type { IDropdownData, IMultiselectDropdownProps } from '../types'; import styles from '../styles'; import { deviceWidth, deviceHeight } from '../util'; import EmptyList from '../Components/EmptyList'; import PressableTouch from '../Components/PressableTouch'; // const theme = { // ...DefaultTheme, // roundness: 2, // colors: { // ...DefaultTheme.colors, // colors: { // primary: '#6200ee', // accent: '#03dac4', // background: '#f6f6f6', // surface: '#FFFFFF', // error: '#B00020', // text: '#000000', // onBackground: '#000000', // onSurface: '#000000', // placeholder: 'rgba(0,0,0,0.54)', // disabled: 'rgba(0,0,0,0.26)', // }, // }, // dark: true, // }; const defaultAvatar = require('../assets/ddicon.png'); const MultiselectDropdown: React.FC = props => { const { error, value, label, required, disabled, data, onChange, floating, enableSearch, primaryColor = ConsColors.primary, elevation, borderRadius, activityIndicatorColor, searchPlaceholder, rippleColor, helperText, errorColor, itemTextStyle, itemContainerStyle, showLoader, animationIn = 'fadeIn', animationOut = 'fadeOut', supportedOrientations = ['portrait', 'landscape'], animationInTiming, animationOutTiming, parentDDContainerStyle, emptyListText, disableSort, enableAvatar, avatarSize, defaultSortOrder = 'asc', chipType = 'flat', chipTextStyle = {}, onBlur, emptySelectionText, paperTheme, textInputStyle, chipStyle = {}, mainContainerStyle, underlineColor, disableSelectionTick, selectedItemTextStyle, selectedItemViewStyle, removeLabel, mode = 'flat', selectedItemsText, disabledItemTextStyle, disabledItemViewStyle, hideChip = false, dropdownIcon = 'menu-down', dropdownIconSize = 30, itemSelectIcon, itemSelectIconSize, multiline = false, searchInputTheme, } = props; const { colors } = useTheme(); const [selectedItems, setSelectedItems] = useState([]); const [labelv, setLabelV] = useState(''); const [isVisible, setIsVisible] = useState(false); const [iconColor, setIconColor] = useState('grey'); const [options, setOptions] = useState([]); const [hasError, setError] = useState(false); const [contMeasure, setConMeasure] = useState({ vx: 0, vy: 0, vWidth: 0, vHeight: 0, }); const [dimension, setDimension] = useState({ dw: deviceWidth, dh: deviceHeight, }); const [searchQuery, setSearchQuery] = useState(''); const pViewRef = useRef(); const listRef = useRef(); useEffect(() => { Dimensions.addEventListener('change', () => { setIsVisible(false); const { width, height } = Dimensions.get('window'); setDimension({ dw: width, dh: height }); setIconColor('grey'); }); return () => { Dimensions.removeEventListener('change', () => {}); }; }, []); useEffect(() => { if (!Lo.isEmpty(data) && value) { setLabelV(`${value.length} ${selectedItemsText || 'selected'}`); setSelectedItems(Lo.filter(data, d => value.includes(d.value))); } }, [value, data, selectedItemsText]); useEffect(() => { if (value) { setLabelV(`${value.length} ${selectedItemsText || 'selected'}`); setSelectedItems(Lo.filter(data, d => value.includes(d.value))); } }, [value, data, selectedItemsText]); useEffect(() => { if (disabled) { setIconColor('lightgrey'); } }, [disabled]); useEffect(() => { if (isVisible && listRef) { listRef.current.flashScrollIndicators(); } }, [isVisible]); useEffect(() => { if (!disableSort) setOptions(Lo.orderBy(data, ['label'], [defaultSortOrder])); else setOptions(data); }, [data, disableSort, defaultSortOrder]); useEffect(() => { if (required && error) { setError(true); setIconColor(errorColor); } else { setError(false); setIconColor('grey'); } }, [required, error, errorColor]); const onTextInputFocus = () => { if (hasError) { setIconColor('red'); } else { setIconColor(primaryColor); } pViewRef.current.measureInWindow( (vx: number, vy: number, vWidth: number, vHeight: number) => { const ddTop = vy + vHeight; const bottomMetric = dimension.dh - vy; if (bottomMetric < 300) { setConMeasure({ vx, vy: ddTop - 217, vWidth, vHeight }); } else { setConMeasure({ vx, vy: ddTop, vWidth, vHeight, }); } } ); setIsVisible(true); }; const androidOnLayout = () => { if (Platform.OS === 'android') { pViewRef.current.measureInWindow( (vx: number, vy: number, vWidth: number, vHeight: number) => { const ddTop = vy + vHeight; const bottomMetric = dimension.dh - vy; if (bottomMetric < 300) { setConMeasure({ vx, vy: ddTop - 217, vWidth, vHeight }); } else { setConMeasure({ vx, vy: ddTop, vWidth, vHeight }); } } ); } }; const onModalBlur = () => { setIsVisible(false); if (hasError) { setIconColor('red'); } else { setIconColor('grey'); } if (onBlur && typeof onBlur === 'function') onBlur(); }; const handleOptionSelect = (v: string | number) => { if (onChange && typeof onChange === 'function') { if (value.includes(v)) { onChange(Lo.remove(value, s => s !== v)); } else { onChange([...value, v]); } if (hasError) { setIconColor('red'); } else { setIconColor('grey'); } } setSearchQuery(''); if (!disableSort) setOptions(Lo.orderBy(data, ['label'], [defaultSortOrder])); else setOptions(data); }; const onChangeSearch = (query: string) => { setSearchQuery(query); if (!Lo.isEmpty(data) && query) { const lFilter = data.filter(opt => opt.label .toString() .toLowerCase() .trim() .includes(query.toString().toLowerCase()) ); if (lFilter.length === 0) { setOptions([]); } else { setOptions(lFilter); } } else if (!Lo.isEmpty(data) && !query && !disableSort) { setOptions(Lo.sortBy(data, 'label')); } else setOptions(data); }; const removeChip = (rmV: string | number) => { if (!showLoader) { if (onChange && typeof onChange === 'function') { onChange(Lo.remove(value, s => s !== rmV)); } } }; const getEmptyComponent = () => { if (typeof emptyListText === 'string') return ; else return <>{emptyListText}; }; const labelAction = () => { if (removeLabel) { return ''; } else { return required ? `${label}*` : label; } }; return ( } mode={mode} /> {required && hasError ? ( {helperText ? helperText : `${label} is required`} ) : null} {!hideChip && ( Math.random().toString()} renderItem={({ item }) => ( removeChip(item.value)} avatar={ enableAvatar && ( {item.avatarComponent ? ( item.avatarComponent ) : ( )} ) } > {item.label} )} /> )} {showLoader ? ( ) : null} {!hideChip && ( Math.random().toString()} renderItem={({ item }) => ( {item.avatarComponent ? ( item.avatarComponent ) : ( )} ) } onClose={() => removeChip(item.value)} > {item.label} )} ListEmptyComponent={{emptySelectionText}} /> )} ) : null } stickyHeaderIndices={enableSearch ? [0] : undefined} renderItem={({ item }) => ( )} keyExtractor={() => Math.random().toString()} ItemSeparatorComponent={() => ( )} getItemLayout={(_d, index) => ({ length: ITEMLAYOUT, offset: ITEMLAYOUT * index, index, })} ListEmptyComponent={getEmptyComponent()} /> ); }; MultiselectDropdown.defaultProps = defaultDropdownProps; export default MultiselectDropdown;