@zohodesk/components
Version:
In this Package, we Provide Some Basic Components to Build Web App
489 lines (418 loc) • 16.8 kB
JavaScript
/***** 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
};
});