react-cm-ui
Version:
React UI for Healthy Church
577 lines (505 loc) • 25.6 kB
JSX
/* 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;