import React, { ChangeEvent } from "react"; import ButtonWithOverlay from "../../shared/buttons/ButtonWithOverlay.component"; import "../../scss/components/SelectCheckboxList.scss"; import { isNullOrUndefined } from "util"; interface IPropsSelectCheckboxList { isReadingOnly?: boolean; isCategoryDisabled?: boolean; isRadio?: boolean; badgeContent?: "all" | "off" | "number"; name?: string; text: string; values: number[]; onChange: (newValues: number[]) => void; options: IOptionsSelectCheckboxList[]; hasSearchBox?: boolean; className?: string; renderText?: (checkedOptions: IOptionsSelectCheckboxList[]) => JSX.Element; hasOptionAll?: boolean; hasBadge?: boolean; } interface IStateSelectCheckboxList { searchText: string; } export interface IOptionsSelectCheckboxList { label: string; isCategory?: boolean; values: number[]; } class SelectCheckboxList extends React.Component { state: IStateSelectCheckboxList; props: IPropsSelectCheckboxList = { onChange: (): void => {}, options: [], text: "", values: [] }; static defaultProps: Partial = { className: "", hasSearchBox: true, badgeContent: "all", isCategoryDisabled: false, isRadio: false, isReadingOnly: false, hasOptionAll: true, name: `${Math.random()}`, hasBadge: true }; constructor(props: IPropsSelectCheckboxList) { super(props); this.state = { searchText: "" }; } handleChangeSearchText(event: ChangeEvent): void { this.setState({ searchText: event.target.value }); } getSelectOption(option: IOptionsSelectCheckboxList): JSX.Element { return (
{!(option.isCategory && this.props.isCategoryDisabled) && this.props.isReadingOnly === false && (
)}
{option.label}
); } isChecked(optionValues: number[]): boolean { return ( this.props.values.length > 0 && optionValues .map((e): boolean => this.props.values.indexOf(e) !== -1) .reduce((p, c): boolean => p && c, true) ); } toggleOption(option: IOptionsSelectCheckboxList): void { let isCategoryDisabled = this.props.isCategoryDisabled; if (!(option.isCategory && isCategoryDisabled)) { let optionValue = option.values; let isChecked = this.isChecked(optionValue); if (this.props.isRadio) { if (!isChecked) { this.props.onChange(optionValue); } } else { if (option.values && Array.isArray(option.values) && option.values.length > 0) { let values = Object.assign( [], this.props.values.filter((e): boolean => option.values.map((val): boolean => val !== e).reduce((p, c): boolean => p && c, true) ) ); if (values.length === this.props.values.length) { values.push(...option.values); } else if (option.values.length > this.props.values.length) { values = Object.assign([], option.values); } this.props.onChange(values); } else { let values = Object.assign( [], this.props.values.filter((e): boolean => option.values.indexOf(e) !== -1) ); if (values.length === this.props.values.length) { values.concat(option.values); } this.props.onChange(values); } } } } areAllChecked(): boolean { return this.props.options .map((e): boolean => this.isChecked(e.values) || (!isNullOrUndefined(e.isCategory) && e.isCategory)) .reduce((p, c): boolean => p && c, true); } render(): JSX.Element { let options = this.props.options; let isReadingOnly = this.props.isReadingOnly; let innerOverlay = (
{!isReadingOnly && this.props.hasSearchBox ? (
) : null} {this.hasOptionAll() === true ? this.getSelectOption({ label: "Toutes les cases", isCategory: true, values: this.props.options .map((e): number[] => e.values) .reduce((p, c): number[] => p.concat(c), []) }) : null} {options .filter( (e): boolean => this.state.searchText === "" || e.label.toLocaleLowerCase().indexOf(this.state.searchText.toLocaleLowerCase()) !== -1 ) .map(this.getSelectOption.bind(this))}
); let text = this.renderText(); return ( ); } hasOptionAll(): boolean { let hasOptionAll = this.props.hasOptionAll; let isReadingOnly = this.props.isReadingOnly; let isNotSearching = !this.state.searchText || this.state.searchText == ""; let hasCategory = false; let options = this.props.options; for (let i = 0; i < options.length; i++) { if (options[i].isCategory) { hasCategory = true; } } return hasOptionAll === true && !isReadingOnly && isNotSearching && !this.props.isRadio && !hasCategory; } renderText(): JSX.Element { let checkedOptions = this.props.options.filter((e): boolean => this.isChecked(e.values) && !e.isCategory); if (this.props.renderText) { return this.props.renderText(checkedOptions); } let icon = null; let length = checkedOptions.length; if (this.props.hasBadge === true) { if (length > 0) { icon = ( {length} ); } if (this.areAllChecked()) { if (this.props.badgeContent === "all") { icon = ( Tous ); } else if (this.props.badgeContent === "number") { icon = ( {length} ); } else if (this.props.badgeContent === "off") { icon = null; } } } return ( {this.props.text} {icon} ); } } export default SelectCheckboxList;