UNPKG

react-cm-ui

Version:
577 lines (505 loc) 25.6 kB
/* eslint-disable */ import _ from 'lodash'; import ClassNames from 'classnames'; import MediaQuery from 'react-responsive'; import PropTypes from 'prop-types'; import React from 'react'; import Button from '../../inputs/button'; import Drawer from '../../surfaces/drawer'; import Dropdown from '../../inputs/dropdown/dropdown'; import Header from '../../dataDisplay/header'; import Icon from '../../dataDisplay/icon'; import Label from '../../dataDisplay/label'; class MultiSelectLabel extends React.PureComponent { constructor() { super(); this.onClearClick = this.onClearClick.bind(this); } onClearClick() { const { onItemChange, selectedOption, value } = this.props; const filteredOptions = _.differenceBy(value, [ selectedOption ], 'value'); onItemChange(filteredOptions); } render() { const { color, label } = this.props; return ( <Label color={color || 'highlight'} onClearClick={this.onClearClick} style={{ marginRight: '5px', marginTop: '11px', }} > {label} </Label> ); } } MultiSelectLabel.propTypes = { color: PropTypes.string, label: PropTypes.string.isRequired, onItemChange: PropTypes.func.isRequired, selectedOption: PropTypes.shape({}).isRequired, value: PropTypes.array.isRequired, }; class NestedTogglesLabel extends React.PureComponent { constructor() { super(); this.onClick = this.onClick.bind(this); } onClick() { const { nestedTogglesData, onClick } = this.props; onClick(nestedTogglesData); } render() { const { nestedTogglesData: { label } } = this.props; const containerClasses = ClassNames('page_deprecated_filters_drawer--nested_toggles_label'); return ( <div className={containerClasses} onClick={this.onClick} > <span>{label}</span> <Icon compact type="chevron-right" /> </div> ); } } NestedTogglesLabel.propTypes = { nestedTogglesData: PropTypes.shape({}).isRequired, onClick: PropTypes.func.isRequired, }; class NestedTogglesWingOptionLabel extends React.PureComponent { constructor() { super(); this.onClick = this.onClick.bind(this); } onClick() { const { onClick, option } = this.props; onClick(option); } render() { const { isSelected, option: { label } } = this.props; const containerClasses = ClassNames('page_deprecated__wing--option', { 'page_deprecated_filters_drawer_wing--option-selected': isSelected, }); return ( <div className={containerClasses} onClick={this.onClick} > <span>{label}</span> {isSelected && <Icon compact inverse type="check" />} </div> ); } } NestedTogglesWingOptionLabel.propTypes = { isSelected: PropTypes.bool, onClick: PropTypes.func.isRequired, option: PropTypes.shape({}).isRequired, }; class NestedTogglesValueLabel extends React.PureComponent { constructor() { super(); this.onClick = this.onClick.bind(this); } onClick() { const { nestedTogglesData, onClick, option } = this.props; onClick(nestedTogglesData, option); } render() { const { option: { label } } = this.props; const containerClasses = ClassNames('page_deprecated_filters_drawer--nested_toggles_value_label'); return ( <div className={containerClasses} > <span>{label}</span> <Icon onClick={this.onClick} size="xsmall" type="times" /> </div> ); } } NestedTogglesValueLabel.propTypes = { nestedTogglesData: PropTypes.shape({}).isRequired, onClick: PropTypes.func.isRequired, option: PropTypes.shape({}).isRequired, }; class PageFiltersDrawer extends React.Component { constructor() { super(); this.state = { nestedTogglesData: {}, // This object is only to be populated when props.rows.items.nestedToggles is true and a label onClick event handler is triggered. }; this.onApplyClick = this.onApplyClick.bind(this); this.onClearClick = this.onClearClick.bind(this); this.onMultiSelectLabelClearClick = this.onMultiSelectLabelClearClick.bind(this); this.onMultiSelectChange = this.onMultiSelectChange.bind(this); this.onNestedTogglesCloseWingClick = this.onNestedTogglesCloseWingClick.bind(this); this.onNestedTogglesLabelClick = this.onNestedTogglesLabelClick.bind(this); this.onNestedTogglesWingOptionLabelClick = this.onNestedTogglesWingOptionLabelClick.bind(this); this.onNestedTogglesValueLabelClick = this.onNestedTogglesValueLabelClick.bind(this); } onApplyClick() { const { onApply } = this.props; onApply(); } onClearClick() { const { onClear } = this.props; onClear(); } onMultiSelectLabelClearClick(onItemChange, value, selectedOption) { const filteredOptions = _.differenceBy(value, [ selectedOption ], 'value'); onItemChange(filteredOptions); } onMultiSelectChange(onItemChange, value, selectedOption) { const filteredOptions = _.union(value, [ selectedOption ]); onItemChange(filteredOptions); } onNestedTogglesCloseWingClick() { const { nestedTogglesData } = this.state; this.setState({ nestedTogglesData: {}, }, () => { nestedTogglesData.onChange(nestedTogglesData.value); }); } onNestedTogglesLabelClick(nestedTogglesData) { this.setState({ nestedTogglesData: _.cloneDeep(nestedTogglesData), }); } onNestedTogglesValueLabelClick(nestedTogglesData, selectedOption) { const selectedOptions = _.filter(nestedTogglesData.value, d => d.value !== selectedOption.value); nestedTogglesData.onChange(selectedOptions); } onNestedTogglesWingOptionLabelClick(selectedOption) { const { nestedTogglesData } = this.state; let selectedOptions; if (_.some(nestedTogglesData.value, selectedOption)) { // Subtract selectedOptions = _.filter(nestedTogglesData.value, d => d.value !== selectedOption.value); } else { // Add selectedOptions = _.sortBy([ ...nestedTogglesData.value, selectedOption ], [ 'value' ]); } const newNestedTogglesData = _.mapValues(nestedTogglesData, (d, key) => { if (key === 'value') { d = selectedOptions; } return d; }); this.setState({ nestedTogglesData: _.cloneDeep(newNestedTogglesData), }); } render() { const { children, className, isDirty, isFiltering, isOpen, onClose, rows, style, } = this.props; const { nestedTogglesData } = this.state; const containerClasses = ClassNames('ui', 'page--deprecated_filters_drawer', className); const canClear = isFiltering || isDirty; const clearFiltersClasses = ClassNames('clear-filters', 'font-size-xsmall', 'font-weight-semibold'); const isNestedTogglesOptionsEmpty = _.isEmpty(nestedTogglesData); let rowKeyNum = 1; let itemKeyNum = 1; let multiSelectLabelKeyNum = 1; let nestedTogglesValueLabelKeyNum = 1; let nestedTogglesOptionLabelKeyNum = 1; return ( <MediaQuery maxWidth={767} > <Drawer className={containerClasses} isOpen={isOpen} onClose={onClose} style={style} wing={ <Drawer.Wing className="page_deprecated_filters_drawer--nested_toggles_wing" isOpen={!isNestedTogglesOptionsEmpty} > <Drawer.TitleBar className="nested_toggles_wing--title_bar" title={ <Icon className="nested_toggles_wing--close_button" onClick={this.onNestedTogglesCloseWingClick} size="medium" type="chevron-left" /> } /> <Drawer.Content className="nested_toggles_wing--content" > <Header className="nested_toggles_wing--title" size="small" weight="bold" > {nestedTogglesData.label} </Header> <div className="nested_toggles_wing--options" > {!isNestedTogglesOptionsEmpty && _.map(nestedTogglesData.options, option => { const isSelected = _.some(nestedTogglesData.value, option); return ( <NestedTogglesWingOptionLabel key={nestedTogglesOptionLabelKeyNum++} isSelected={isSelected} onClick={this.onNestedTogglesWingOptionLabelClick} option={option} /> ); })} </div> </Drawer.Content> </Drawer.Wing> } > <Drawer.TitleBar className="page_deprecated_filters_drawer--title_bar" closeButton={ <Icon className="page_deprecated_filters_drawer--close_button" compact onClick={onClose} type="times" /> } title={ <div className="page_deprecated_filters_drawer--actions" title="Filters"> <div className="page_deprecated_filters_drawer--clear_column" > {canClear ? ( <a className={clearFiltersClasses} onClick={this.onClearClick} > Clear Filters </a> ) : ( <Icon color="static" compact size="medium" type="filter" /> )} </div> <div className="page_deprecated_filters_drawer--apply_column" > {isDirty && <Button color="success" icon innerStyle={{ height: '32px', width: '32px', }} onClick={this.onApplyClick} style={{ height: '32px', minHeight: '32px', width: '32px', }} > <Icon compact type="check" /> </Button> } </div> </div> } /> <Drawer.Content> {_.map(rows, row => { return ( <div className="page_deprecated_filters_drawer--row" key={`page--filters-drawer-row-${rowKeyNum++}`} > {row.header && <Header className="page_deprecated_filters_drawer--header" weight="bold" > {row.header} </Header> } <div className="page_deprecated_filters_drawer--items" > {_.isArray(row.items) && _.map(row.items, item => { const { dropdown, jsx, multiSelect, nestedToggles, } = item; const className = ClassNames('page_deprecated_filters_drawer--item', { 'page_deprecated_filters_drawer--item-dropdown': dropdown, 'page_deprecated_filters_drawer--item-jsx': jsx, 'page_deprecated_filters_drawer--item-multi_select': multiSelect, 'page_deprecated_filters_drawer--item-nested_toggles': nestedToggles, }); const itemKey = `page_deprecated_filters_drawer--item-${itemKeyNum++}`; if (!jsx && !dropdown && !nestedToggles && !multiSelect) { console.warn( '<Page.FiltersDrawer>\'s rows.items must have one of the ' + 'following properties: dropdown, labels, multiSelect or jsx.' ); } else if (!jsx && dropdown && !nestedToggles && !multiSelect) { // Dropdown return ( <div className={className} key={itemKey} > <Dropdown clearable={false} className={dropdown.className} fluid id={dropdown.id} onChange={(selectedOption) => dropdown.onChange(selectedOption)} options={dropdown.options} searchable={false} selection selectionOptionComponent={dropdown.selectionCustomComponent} style={dropdown.style} value={dropdown.value} /> </div> ); } else if (!jsx && !dropdown && nestedToggles && !multiSelect) { // Nested Toggles return ( <div className={className} key={itemKey} > <NestedTogglesLabel onClick={this.onNestedTogglesLabelClick} nestedTogglesData={nestedToggles} /> {!_.isEmpty(nestedToggles.value) && <div> {_.map(nestedToggles.value, option => { return ( <NestedTogglesValueLabel key={`nested-toggles-selected-filter-${nestedTogglesValueLabelKeyNum++}`} nestedTogglesData={nestedToggles} onClick={this.onNestedTogglesValueLabelClick} option={option} /> ); })} </div> } </div> ); } else if (!jsx && !dropdown && !nestedToggles && multiSelect) { // Multi Select const modifiedOptions = _.differenceBy( multiSelect.options, multiSelect.value, 'value' ); return ( <div className={className} key={itemKey} > <Dropdown clearable={false} className={multiSelect.className} fluid iconType="plus" id={multiSelect.id} onChange={ (selectedOption) => this.onMultiSelectChange( multiSelect.onChange, multiSelect.value, selectedOption ) } options={modifiedOptions} placeholder={multiSelect.placeholder} searchable={false} selection selectionOptionComponent={multiSelect.selectionCustomComponent} style={multiSelect.style} value={''} /> {!_.isEmpty(multiSelect.value) && _.map(multiSelect.value, v => { const selectedOption = v; return ( <MultiSelectLabel color={multiSelect.labelColor} key={`multi-select-label-${multiSelectLabelKeyNum++}`} onItemChange={multiSelect.onChange} label={v.label} selectedOption={selectedOption} value={multiSelect.value} /> ); }) } </div> ); // JSX } else if (jsx && !dropdown && !nestedToggles && !multiSelect) { return ( <div className={className} key={itemKey} > {jsx} </div> ); } })} </div> </div> ); })} {children} </Drawer.Content> </Drawer> </MediaQuery> ); } } PageFiltersDrawer.propTypes = { className: PropTypes.string, isDirty: PropTypes.bool.isRequired, isFiltering: PropTypes.bool.isRequired, isOpen: PropTypes.bool.isRequired, onApply: PropTypes.func.isRequired, onClear: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired, rows: PropTypes.array, style: PropTypes.shape({}), }; export default PageFiltersDrawer;