UNPKG

@zohodesk/components

Version:

In this Package, we Provide Some Basic Components to Build Web App

489 lines (418 loc) • 16.8 kB
/***** Libraries *****/ import { createSelector } from 'reselect'; import { getIsEmptyValue, getSearchString } from "./Common"; export const dummyArray = []; export const dummyObj = {}; export const getOptions = props => props.options || dummyArray; const getOptionsOrder = props => props.optionsOrder || dummyArray; const getSelectedOptionsSel = props => props.selectedOptions || dummyArray; const getSearchStr = props => props.searchStr || ''; export const getValueField = props => props.valueField || ''; export const getSecondaryField = props => props.secondaryField || ''; export const getTextField = props => props.textField || ''; export const getImageField = props => props.imageField || ''; export const getIconName = props => props.iconName || ''; export const getIconSize = props => props.iconSize || ''; export const getOptionType = props => props.optionType || ''; const getNeedSearch = props => props.needSearch; const getIsDefaultSelectValue = props => props.isDefaultSelectValue; const getSelectedOptionsLength = props => getIsEmptyValue(props.selectedOptionsLength) ? '' : props.selectedOptionsLength; const getNormalizedFormatOptions = props => props.normalizedFormatOptions || dummyObj; const getSelectedValue = props => getIsEmptyValue(props.selectedValue) ? '' : props.selectedValue; const getSelectedFormatOptions = props => props.selectedFormatOptions || dummyObj; export const getPrefixText = props => props.prefixText || ''; const getIsStartWithSearch = props => props.isStartsWithSearch; const getKeepSelectedOptions = props => props.keepSelectedOptions; const getDisabledOptions = props => props.disabledOptions || dummyArray; const getListItemProps = props => props.listItemProps || ''; const getSearchFields = props => { return props.searchFields || ['value']; }; // const isObjectContainsSearchString = (searchFields = [], searchStr = '', obj) => { // const matchedFields = searchFields.filter(element => { // return getSearchString(obj[element]).indexOf(searchStr) !== -1 // }); // return matchedFields.length !== 0; // } const isObjectContainsSearchString = function () { let searchFields = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : []; let searchStr = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ''; let obj = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; return searchFields.some(field => { const val = obj[field]; if (val === null || val === undefined) return false; const str = getSearchString(val); return str && str.indexOf(searchStr) !== -1; }); }; const getAllowValueFallback = props => props.allowValueFallback !== false; export const makeGetMultiSelectFilterSuggestions = () => createSelector([getOptions, getSelectedOptionsSel, getSearchStr, getNeedSearch, getIsStartWithSearch, getKeepSelectedOptions, getSearchFields], (options, selectedOptions, searchStr, needSearch, isStartsWithSearch, keepSelectedOptions, searchFields) => { const suggestions = []; const suggestionIds = []; options.forEach(option => { const searchString = getSearchString(searchStr); const { value = '' } = option; const valueString = getSearchString(value); const isMatch = needSearch ? isStartsWithSearch ? valueString.startsWith(searchString) : isObjectContainsSearchString(searchFields, searchString, option) : true; if (selectedOptions.indexOf(option.id) === -1 && isMatch || keepSelectedOptions) { suggestions.push(option); suggestionIds.push(option.id); } }); return { suggestions, suggestionIds }; }); export const optionIdGrouping = (id, prefixText) => { if (getIsEmptyValue(id)) { return ''; } if (getIsEmptyValue(prefixText)) { return id; } const prefixType = typeof prefixText === 'number' ? 'Int' : 'Str'; const idType = typeof id === 'number' ? 'Int' : 'Str'; return `${prefixType}_${prefixText}_${idType}_${id}`; }; export const extractOptionId = id => { if (getIsEmptyValue(id)) { return { id: '' }; } if (typeof id === 'number') { return { id }; } const splitedOption = id.split && id.split('_'); if (splitedOption.length === 1) { return splitedOption[0]; } if (splitedOption.length === 4) { let [prefixType, prefixText, idType, id] = splitedOption; id = idType === 'Int' ? Number.parseInt(id) : id; prefixText = prefixType === 'Int' ? Number.parseInt(prefixText) : prefixText; return { id, groupId: prefixText }; } }; export const extractOptionIdFromJson = (id, localData) => localData[id] || {}; export const makeFormatOptions = () => createSelector([getOptions, getValueField, getTextField, getImageField, getPrefixText, getIconName, getIconSize, getOptionType, getDisabledOptions, getListItemProps, getAllowValueFallback, getSearchFields, getSecondaryField], (options, valueField, textField, imageField, prefixText, iconName, iconSize, optionType, disabledOptions, listItemProps, allowValueFallback, searchFields, secondaryField) => { const revampOptions = []; const remvampOptionIds = []; const normalizedAllOptions = {}; const normalizedFormatOptions = {}; options.forEach(option => { if (!getIsEmptyValue(option)) { //For group multiSelect - grouping selectedOptions case const { valueField: impValueField, textField: impTextField, imageField: impImageField, secondaryField: impSecondaryField, optionType: impOptionType, iconName: impIconName, iconSize: impIconSize, listItemProps: listStyle } = option; let id = typeof option === 'object' ? option[impValueField || valueField] : option; const value = typeof option === 'object' ? option[impTextField || textField] : allowValueFallback ? option : ''; const secondaryValue = typeof option === 'object' ? option[impSecondaryField || secondaryField] : ''; const photoURL = typeof option === 'object' ? option[impImageField || imageField] : ''; // grouping options (group select/MultiSelect) id = !getIsEmptyValue(id) ? optionIdGrouping(id, prefixText) : ''; const additionalSearchFieldData = searchFields.reduce((value, item) => { if (typeof option === 'object' && option.hasOwnProperty(item)) { value[item] = option[item]; } return value; }, {}); if (remvampOptionIds.indexOf(id) === -1 && !getIsEmptyValue(id) && !getIsEmptyValue(value)) { remvampOptionIds.push(id); const optionDetails = { // ...option, ...additionalSearchFieldData, id, value, secondaryValue, optionType: impOptionType || optionType }; if (imageField) { optionDetails.photoURL = photoURL; } if (impIconName || iconName) { optionDetails.icon = impIconName || iconName; } if (impIconSize || iconSize) { optionDetails.iconSize = impIconSize || iconSize; } if (disabledOptions.length) { optionDetails.isDisabled = disabledOptions.indexOf(id) >= 0; } if (listStyle || listItemProps) { optionDetails.listItemProps = listStyle || listItemProps; } normalizedFormatOptions[id] = optionDetails; normalizedAllOptions[id] = { ...option, groupId: prefixText }; revampOptions.push(optionDetails); } } }); return { allOptions: revampOptions, normalizedAllOptions, normalizedFormatOptions, optionsOrder: remvampOptionIds }; }); export const makeGetMultiSelectSelectedOptions = () => createSelector([getSelectedOptionsSel, getNormalizedFormatOptions, getSelectedOptionsLength, getAllowValueFallback], (selectedOptions, normalizedFormatOptions, selectedOptionsLength, allowValueFallback) => { const output = []; const revampSelectedOptions = []; const normalizedSelectedOptions = {}; selectedOptionsLength = !getIsEmptyValue(selectedOptionsLength) ? selectedOptionsLength : selectedOptions.length; for (let i = 0; i < selectedOptionsLength; i++) { const option = selectedOptions[i]; const { id } = normalizedFormatOptions[option] || {}; if (revampSelectedOptions.indexOf(id) === -1 && !getIsEmptyValue(id)) { revampSelectedOptions.push(id); output.push(normalizedFormatOptions[option]); normalizedSelectedOptions[id] = normalizedFormatOptions[option]; } else if (allowValueFallback && getIsEmptyValue(id) && !getIsEmptyValue(option) && revampSelectedOptions.indexOf(option) === -1) { //fallback case const newObj = { id: option, value: option }; output.push(newObj); normalizedSelectedOptions[option] = newObj; revampSelectedOptions.indexOf(option) === -1 ? revampSelectedOptions.push(option) : null; } } return { formatSelectedOptions: output, normalizedSelectedOptions, selectedOptionIds: revampSelectedOptions }; }); export const makeGetSelectedValueText = () => createSelector([getOptionsOrder, getNormalizedFormatOptions, getSelectedValue, getSelectedFormatOptions, getIsDefaultSelectValue, getValueField, getTextField], (optionsOrder, normalizedFormatOptions, selectedValue, selectedFormatOptions, isDefaultSelectValue, valueField, textField) => { let selectedValueIndex = optionsOrder.indexOf(selectedValue); let isSelfValueChanged = false; if (getIsEmptyValue(selectedValue) && isDefaultSelectValue) { [selectedValue] = optionsOrder; isSelfValueChanged = true; } const allOptions = Object.assign({}, selectedFormatOptions, normalizedFormatOptions); const details = allOptions[selectedValue]; let hoverIndex = selectedValueIndex !== -1 ? selectedValueIndex : 0; let selectedValueDetails = details ? { [selectedValue]: details } : dummyObj; let { value: selectedValueText = '', id: selectedId } = details || dummyObj; //selectedValue is not included in options case if (getIsEmptyValue(selectedId)) { if (typeof selectedValue === 'object') { const id = selectedValue[valueField]; const text = selectedValue[textField]; selectedValueDetails = { id, value: text }; selectedValueText = text; selectedId = id; selectedValueIndex = optionsOrder.indexOf(selectedId); hoverIndex = selectedValueIndex !== -1 ? selectedValueIndex : 0; } else { selectedValueText = selectedValue; selectedId = selectedValue; } } return { selected: selectedValueText, hoverIndex, selectedValueDetails, selectedId, isSelfValueChanged }; }); const getObj1 = props => props.obj1 || dummyObj; const getObj2 = props => props.obj2 || dummyObj; export const makeObjectConcat = () => createSelector([getObj1, getObj2], (obj1, obj2) => Object.assign({}, obj1, obj2)); /***** Group Select *****/ const getGroupedOptions = props => props.groupedOptions || dummyArray; const getFormatOptions = makeFormatOptions(); export const makeGetGroupSelectOptions = () => createSelector([getGroupedOptions, getAllowValueFallback], (groupedOptions, allowValueFallback) => { const revampedGroups = []; let allOptionIds = []; let allNormalizedOptions = {}; //all group normalized options let allNormalizedFormatOptions = {}; const groupIds = []; const normalizedGroupedOptions = {}; groupedOptions.forEach(group => { const { options, id: groupId, name, valueField, textField } = group; if (!getIsEmptyValue(groupId) && groupIds.indexOf(groupId) === -1) { groupIds.push(groupId); normalizedGroupedOptions[groupId] = group; const { allOptions, normalizedAllOptions, normalizedFormatOptions, optionsOrder } = getFormatOptions({ options, valueField, textField, prefixText: groupId, allowValueFallback }); if (optionsOrder.length) { revampedGroups.push({ id: groupId, name, options: allOptions }); allOptionIds = [...allOptionIds, ...optionsOrder]; allNormalizedOptions = Object.assign({}, allNormalizedOptions, normalizedAllOptions); allNormalizedFormatOptions = Object.assign({}, allNormalizedFormatOptions, normalizedFormatOptions); } } }); return { revampedGroups, normalizedAllOptions: allNormalizedOptions, normalizedFormatOptions: allNormalizedFormatOptions, allOptionIds, groupIds, normalizedGroupedOptions }; }); const getGroups = props => props.revampedGroups; const getFilterSuggestions = makeGetMultiSelectFilterSuggestions(); export const makeGetGroupSelectFilterSuggestions = () => createSelector([getGroups, getSearchStr, getNeedSearch, getIsStartWithSearch], (groups, searchStr, needSearch, isStartsWithSearch) => { const suggestionGroups = []; let suggestionOptionIds = []; groups.forEach(group => { const { options } = group; const { suggestions, suggestionIds } = getFilterSuggestions({ options, needSearch, searchStr, isStartsWithSearch }); if (suggestionIds.length) { suggestionGroups.push(Object.assign({}, group, { options: suggestions })); suggestionOptionIds = [...suggestionOptionIds, ...suggestionIds]; } }); return { suggestionGroups, suggestionOptionIds }; }); export const makeGetOptionIdChange = () => createSelector([getOptions, getValueField, getPrefixText, getTextField, getImageField, getIconName, getIconSize, getOptionType], (options, valueField, prefixText, textField, imageField, iconName, iconSize, optionType) => { const newOptions = []; return options.reduce((changedOptions, option) => { let newOption; const id = typeof option === 'object' ? option[valueField] : option; if (typeof option === 'object' && !getIsEmptyValue(id)) { newOption = Object.assign({}, option, { [valueField]: optionIdGrouping(id, prefixText), valueField, textField, optionType }); if (imageField) { newOption.imageField = imageField; } changedOptions.push(newOption); } else if (!getIsEmptyValue(id)) { newOption = { id: optionIdGrouping(id, prefixText), text: id, valueField: 'id', textField: 'text', iconName, optionType, iconSize }; changedOptions.push(newOption); } return changedOptions; }, newOptions); }); export const filterSelectedOptions = function () { let { selectedOptions = dummyArray, propSelectedOptions = dummyArray, disabledOptions = dummyArray } = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; // eslint-disable-next-line no-param-reassign selectedOptions = selectedOptions || dummyArray; // eslint-disable-next-line no-param-reassign propSelectedOptions = propSelectedOptions || dummyArray; // eslint-disable-next-line no-param-reassign disabledOptions = disabledOptions || dummyArray; const newlyAddedOptions = selectedOptions.filter(selectedOption => propSelectedOptions.indexOf(selectedOption) === -1); // eslint-disable-next-line max-len const oldValidSelectedOptions = propSelectedOptions.filter(selectedOption => { const isRemoved = selectedOptions.indexOf(selectedOption) === -1; const isDisabled = disabledOptions.indexOf(selectedOption) >= 0; if (isDisabled) { return true; } else if (isRemoved) { return false; } return true; }); return { newSelectedOptions: [...oldValidSelectedOptions, ...newlyAddedOptions] }; }; export const makeGetIsShowClearIcon = () => createSelector([getSelectedOptionsSel, getDisabledOptions], (selectedOptions, disabledOptions) => { let countForShowClear = 2; let enabledOptionsLength = 0; let isShowClearIcon = selectedOptions.length >= countForShowClear; if (disabledOptions.length) { let isHaveEnabledOptions = false; let isAllDisabled = disabledOptions.length === selectedOptions.length; if (!isAllDisabled) { isHaveEnabledOptions = selectedOptions.some(option => { let { isDisabled = false } = option || {}; if (!isDisabled) { enabledOptionsLength += 1; if (enabledOptionsLength === countForShowClear) { return true; } return false; } return false; }); } return { isShowClearIcon: isAllDisabled ? !isAllDisabled : isHaveEnabledOptions }; } return { isShowClearIcon }; });