web: Components: AdvancedSelector refactoring: removed useless code and optimized group displaying

This commit is contained in:
Alexey Safronov 2019-10-29 18:02:16 +03:00
parent 74b741f3c7
commit a572c6118d
6 changed files with 597 additions and 600 deletions

View File

@ -1,190 +1,193 @@
/* eslint-disable react/prop-types */
import React from "react";
import { storiesOf } from "@storybook/react";
import { action } from '@storybook/addon-actions';
import { withKnobs, text, number, boolean, select } from "@storybook/addon-knobs/react";
import { action } from "@storybook/addon-actions";
import {
withKnobs,
text,
number,
boolean,
select
} from "@storybook/addon-knobs/react";
import withReadme from "storybook-readme/with-readme";
import Readme from "./README.md";
import AdvancedSelector from "./";
import Section from "../../../.storybook/decorators/section";
import { BooleanValue } from "react-values";
import Button from "../button";
import { isEqual, slice } from "lodash";
import { name } from "faker";
//import ADSelectorMainBody from "./sub-components/sections/main/body";
import { FixedSizeList as List } from "react-window";
import InfiniteLoader from "react-window-infinite-loader";
import Loader from "../loader";
import { Text } from "../text";
import CustomScrollbarsVirtualList from "../scrollbar/custom-scrollbars-virtual-list";
import ADSelectorMainBody from "./sub-components/sections/main/body";
function getRandomInt(min, max) {
return Math.floor(Math.random() * (max - min)) + min;
}
const groups = [
{
key: "group-all",
label: "All groups",
total: 0
},
{
key: "group-dev",
label: "Development",
total: 0
},
{
key: "group-management",
label: "Management",
total: 0
},
{
key: "group-marketing",
label: "Marketing",
total: 0
},
{
key: "group-mobile",
label: "Mobile",
total: 0
},
{
key: "group-support",
label: "Support",
total: 0
},
{
key: "group-web",
label: "Web",
total: 0
},
{
key: "group-1",
label: "Group1",
total: 0
},
{
key: "group-2",
label: "Group2",
total: 0
},
{
key: "group-3",
label: "Group3",
total: 0
},
{
key: "group-4",
label: "Group4",
total: 0
},
{
key: "group-5",
label: "Group5",
total: 0
}
];
const sizes = ["compact", "full"];
const displayTypes = ['dropdown', 'aside'];
const displayTypes = ["dropdown", "aside"];
class ADSelectorExample extends React.Component {
constructor(props) {
super(props);
const { total, isOpen } = props;
const { isOpen, total } = props;
this.state = {
const groups = this.generateGroups();
const users = this.generateUsers(total, groups);
this.state = this.getDefaultState(isOpen, groups, users);
}
getDefaultState = (isOpen, groups, allOptions) => {
return {
isOpen: isOpen,
allOptions,
options: [],
groups,
hasNextPage: true,
isNextPageLoading: false
}
};
};
this.AllOptions = Array.from({ length: total }, (v, index) => {
generateGroups = () => {
return [
{
key: "group-all",
label: "All groups",
total: 0
},
{
key: "group-dev",
label: "Development",
total: 0
},
{
key: "group-management",
label: "Management",
total: 0
},
{
key: "group-marketing",
label: "Marketing",
total: 0
},
{
key: "group-mobile",
label: "Mobile",
total: 0
},
{
key: "group-support",
label: "Support",
total: 0
},
{
key: "group-web",
label: "Web",
total: 0
}
];
};
generateUsers = (count, groups) => {
return Array.from({ length: count }, (v, index) => {
const additional_group = groups[getRandomInt(1, 6)];
groups[0].total++;
additional_group.total++;
return {
key: `user${index}`,
groups: ["group-all", additional_group.key],
label: `User${index} ${name.findName()}`
label: `${name.findName()} (User${index})`
};
});
}
};
loadNextPage = (startIndex, stopIndex) => {
console.log(`loadNextPage(startIndex=${startIndex}, stopIndex=${stopIndex})`);
console.log(
`loadNextPage(startIndex=${startIndex}, stopIndex=${stopIndex})`
);
this.setState({ isNextPageLoading: true }, () => {
setTimeout(() => {
const { options } = this.state;
const newOptions = [...options].concat(slice(this.AllOptions, startIndex, startIndex+100))
const newOptions = [...options].concat(
slice(this.state.allOptions, startIndex, startIndex + 100)
);
this.setState({
hasNextPage: newOptions.length < this.props.total,
isNextPageLoading: false,
options: newOptions
});
}, 2500);
}, 500);
});
};
componentDidUpdate(prevProps) {
const {total, options, isOpen} = this.props;
if(!isEqual(prevProps.options, options))
{
const { total, options, isOpen } = this.props;
if (!isEqual(prevProps.options, options)) {
this.setState({
options: options
});
}
if(isOpen !== prevProps.isOpen) {
if (isOpen !== prevProps.isOpen) {
this.setState({
isOpen: isOpen
});
}
if(total !== prevProps.total) {
this.setState({
total: total,
option: []
});
if (total !== prevProps.total) {
const groups = this.generateGroups();
const users = this.generateUsers(total, groups);
this.setState(this.getDefaultState(isOpen, groups, users));
}
}
render() {
const { isOpen, options, hasNextPage, isNextPageLoading } = this.state;
return (
<AdvancedSelector
options={options}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={this.loadNextPage}
toggle = () => {
this.setState({
isOpen: !this.state.isOpen
});
};
size={select("size", sizes, "full")}
placeholder={text("placeholder", "Search users")}
onSearchChanged={value => {
action("onSearchChanged")(value);
/*set(
render() {
const {
isOpen,
options,
groups,
selectedOptions,
selectedGroups,
hasNextPage,
isNextPageLoading
} = this.state;
return (
<div style={{position: 'relative'}}>
<Button label="Toggle dropdown" onClick={this.toggle} />
<AdvancedSelector
options={options}
selectedOptions={selectedOptions}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={this.loadNextPage}
size={select("size", sizes, "full")}
placeholder={text("placeholder", "Search users")}
onSearchChanged={value => {
action("onSearchChanged")(value);
/*set(
options.filter(option => {
return option.label.indexOf(value) > -1;
})
);*/
}}
groups={groups}
selectedGroups={[groups[0]]}
isMultiSelect={boolean("isMultiSelect", true)}
buttonLabel={text("buttonLabel", "Add members")}
selectAllLabel={text("selectAllLabel", "Select all")}
onSelect={selectedOptions => {
action("onSelect")(selectedOptions);
//toggle();
}}
//onCancel={toggle}
onChangeGroup={group => {
/*set(
}}
groups={groups}
selectedGroups={selectedGroups}
isMultiSelect={boolean("isMultiSelect", true)}
buttonLabel={text("buttonLabel", "Add members")}
selectAllLabel={text("selectAllLabel", "Select all")}
onSelect={selectedOptions => {
action("onSelect")(selectedOptions);
this.toggle();
}}
//onCancel={toggle}
onGroupSelect={selectedGroups => {
action("onGroupSelect")(selectedGroups);
/*set(
options.filter(option => {
return (
option.groups &&
@ -193,71 +196,25 @@ class ADSelectorExample extends React.Component {
);
})
);*/
}}
allowCreation={boolean("allowCreation", false)}
onAddNewClick={() => action("onSelect") }
isOpen={isOpen}
displayType={select("displayType", displayTypes, "dropdown")}
/>
);
}
}
class MainListExample extends React.PureComponent {
constructor(props) {
super(props);
this.AllOptions = Array.from({ length: props.total }, (v, index) => {
const additional_group = groups[getRandomInt(1, 6)];
groups[0].total++;
additional_group.total++;
return {
key: `user${index}`,
groups: ["group-all", additional_group.key],
label: `User${index} ${name.findName()}`
};
});
}
state = {
hasNextPage: true,
isNextPageLoading: false,
options: []
};
loadNextPage = (startIndex, stopIndex) => {
console.log(`loadNextPage(startIndex=${startIndex}, stopIndex=${stopIndex})`);
this.setState({ isNextPageLoading: true }, () => {
setTimeout(() => {
const { options } = this.state;
const newOptions = [...options].concat(slice(this.AllOptions, startIndex, startIndex+100))
this.setState({
hasNextPage: newOptions.length < this.props.total,
isNextPageLoading: false,
options: newOptions
});
}, 2500);
});
};
render() {
const { hasNextPage, isNextPageLoading, options } = this.state;
return (
<ADSelectorMainBody
options={options}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={this.loadNextPage}
listHeight={488}
listWidth={356}
itemHeight={32}
onRowChecked={(option) => console.log("onRowChecked", option)}
onRowSelect={(option) => console.log("onRowSelect", option)}
/>
}}
onGroupChange={group => {
action("onGroupChange")(group);
/*set(
options.filter(option => {
return (
option.groups &&
option.groups.length > 0 &&
option.groups.indexOf(group.key) > -1
);
})
);*/
}}
allowCreation={boolean("allowCreation", false)}
onAddNewClick={() => action("onSelect")}
isOpen={isOpen}
displayType={select("displayType", displayTypes, "dropdown")}
/>
</div>
);
}
}
@ -268,24 +225,7 @@ storiesOf("Components|AdvancedSelector", module)
.add("base", () => {
return (
<Section>
<BooleanValue
defaultValue={true}
onChange={() => action("isOpen changed")}
>
{({ value: isOpen, toggle }) => (
<div style={{position: "relative"}}>
<Button label="Toggle dropdown" onClick={toggle} />
<ADSelectorExample isOpen={isOpen} total={number("Users count", 1000)} />
</div>
)}
</BooleanValue>
</Section>
);
})
.add("list only", () => {
return (
<Section>
<MainListExample total={number("Users count", 1000)} />
<ADSelectorExample total={number("Users count", 10000)} />
</Section>
);
});

View File

@ -5,6 +5,7 @@ import Aside from "../layout/sub-components/aside";
import ADSelectorBody from "./sub-components/body";
const displayTypes = ["dropdown", "aside"];
const sizes = ["compact", "full"];
class AdvancedSelector extends React.Component {
render() {
@ -24,30 +25,35 @@ class AdvancedSelector extends React.Component {
}
AdvancedSelector.propTypes = {
value: PropTypes.string,
placeholder: PropTypes.string,
isMultiSelect: PropTypes.bool,
size: PropTypes.oneOf(["compact", "full"]),
maxHeight: PropTypes.number,
isDisabled: PropTypes.bool,
onSearchChanged: PropTypes.func,
options: PropTypes.array,
selectedOptions: PropTypes.array,
groups: PropTypes.array,
selectedGroups: PropTypes.array,
selectedAll: PropTypes.bool,
value: PropTypes.string,
placeholder: PropTypes.string,
selectAllLabel: PropTypes.string,
buttonLabel: PropTypes.string,
onSelect: PropTypes.func,
onChangeGroup: PropTypes.func,
onCancel: PropTypes.func,
size: PropTypes.oneOf(sizes),
displayType: PropTypes.oneOf(displayTypes),
maxHeight: PropTypes.number,
isMultiSelect: PropTypes.bool,
isDisabled: PropTypes.bool,
selectedAll: PropTypes.bool,
isOpen: PropTypes.bool,
allowCreation: PropTypes.bool,
onAddNewClick: PropTypes.func,
allowAnyClickClose: PropTypes.bool,
displayType: PropTypes.oneOf(displayTypes),
hasNextPage: PropTypes.bool,
isNextPageLoading: PropTypes.bool,
onSearchChanged: PropTypes.func,
onSelect: PropTypes.func,
onGroupChange: PropTypes.func,
onCancel: PropTypes.func,
onAddNewClick: PropTypes.func,
loadNextPage: PropTypes.func,
};

View File

@ -1,12 +1,9 @@
import React from "react";
import PropTypes from "prop-types";
import styled, { css } from "styled-components";
import CustomScrollbarsVirtualList from "../../scrollbar/custom-scrollbars-virtual-list";
import { FixedSizeList } from "react-window";
import Checkbox from "../../checkbox";
import ComboBox from "../../combobox";
import { Text } from "../../text";
import filter from "lodash/filter";
import isEqual from "lodash/isEqual";
@ -23,33 +20,34 @@ import ADSelectorAdditionalBody from "./sections/additional/body";
/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
const Container = ({
value,
placeholder,
isMultiSelect,
size,
width,
maxHeight,
isDisabled,
onSelect,
onSearchChanged,
options,
selectedOptions,
buttonLabel,
selectAllLabel,
groups,
selectedGroups,
onChangeGroup,
isOpen,
displayType,
containerWidth,
containerHeight,
allowCreation,
onAddNewClick,
allowAnyClickClose,
hasNextPage,
isNextPageLoading,
loadNextPage,
...props
value,
placeholder,
isMultiSelect,
size,
width,
maxHeight,
isDisabled,
onSelect,
onSearchChanged,
options,
selectedOptions,
buttonLabel,
selectAllLabel,
groups,
selectedGroups,
onGroupSelect,
onGroupChange,
isOpen,
displayType,
containerWidth,
containerHeight,
allowCreation,
onAddNewClick,
allowAnyClickClose,
hasNextPage,
isNextPageLoading,
loadNextPage,
...props
}) => <div {...props} />;
/* eslint-enable react/prop-types */
/* eslint-enable no-unused-vars */
@ -73,13 +71,13 @@ const StyledBodyContainer = styled(Container)`
width: 100%;
${props =>
props.displayType === "dropdown" &&
props.size === "full" &&
css`
props.displayType === "dropdown" &&
props.size === "full" &&
css`
margin-right: ${props => (props.allowCreation ? 8 : 16)}px;
`}
/*${props =>
props.allowCreation
props.allowCreation
? css`
width: 272px;
margin-right: 8px;
@ -91,8 +89,8 @@ const StyledBodyContainer = styled(Container)`
.add_new_btn {
${props =>
props.allowCreation &&
css`
props.allowCreation &&
css`
display: inline-block;
vertical-align: top;
height: 32px;
@ -110,14 +108,15 @@ const StyledBodyContainer = styled(Container)`
.data_column_one {
${props =>
props.size === "full" &&
props.displayType === "dropdown" &&
props.groups &&
props.groups.length > 0
? css`
props.groups &&
props.groups.length > 0
? css`
width: 50%;
display: inline-block;
`
: ""}
: ""}
.options_list {
margin-top: 4px;
@ -145,14 +144,14 @@ const StyledBodyContainer = styled(Container)`
.data_column_two {
${props =>
props.displayType === "dropdown" &&
props.groups &&
props.groups.length > 0
? css`
props.groups &&
props.groups.length > 0
? css`
width: 50%;
display: inline-block;
border-left: 1px solid #eceef1;
`
: ""}
: ""}
.group_header {
font-weight: 600;
@ -195,280 +194,334 @@ const StyledBodyContainer = styled(Container)`
`;
class ADSelectorBody extends React.Component {
constructor(props) {
super(props);
constructor(props) {
super(props);
this.ref = React.createRef();
this.ref = React.createRef();
const groups = this.convertGroups(this.props.groups);
const currentGroup = this.getCurrentGroup(groups);
const { groups, selectedOptions, selectedGroups, selectedAll, isOpen } = props;
this.state = {
selectedOptions: this.props.selectedOptions || [],
selectedAll: this.props.selectedAll || false,
groups: groups,
currentGroup: currentGroup
};
const convertedGroups = this.convertGroups(groups);
const currentGroup = this.getCurrentGroup(convertedGroups);
if (props.isOpen) handleAnyClick(true, this.handleClick);
this.state = {
selectedOptions: selectedOptions || [],
selectedAll: selectedAll || false,
groups: convertedGroups,
selectedGroups: selectedGroups || [],
currentGroup: currentGroup
};
if (isOpen) handleAnyClick(true, this.handleClick);
}
handleClick = e => {
const { onCancel, allowAnyClickClose, isOpen } = this.props;
if (
isOpen &&
allowAnyClickClose &&
this.ref &&
this.ref.current &&
!this.ref.current.contains(e.target) &&
e &&
e.target &&
e.target.className &&
typeof e.target.className.indexOf === "function" &&
e.target.className.indexOf("option_checkbox") === -1
) {
onCancel && onCancel();
}
};
componentWillUnmount() {
handleAnyClick(false, this.handleClick);
}
shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
}
componentDidUpdate(prevProps) {
const {
groups,
selectedAll,
isMultiSelect,
selectedOptions,
selectedGroups,
allowAnyClickClose,
isOpen
} = this.props;
if (isOpen !== prevProps.isOpen) {
handleAnyClick(isOpen, this.handleClick);
}
handleClick = e => {
if (
this.props.isOpen &&
this.props.allowAnyClickClose &&
this.ref &&
this.ref.current &&
!this.ref.current.contains(e.target) &&
e &&
e.target &&
e.target.className &&
typeof e.target.className.indexOf === "function" &&
e.target.className.indexOf("option_checkbox") === -1
) {
this.props.onCancel && this.props.onCancel();
}
};
componentWillUnmount() {
handleAnyClick(false, this.handleClick);
if (allowAnyClickClose !== prevProps.allowAnyClickClose) {
handleAnyClick(allowAnyClickClose, this.handleClick);
}
shouldComponentUpdate(nextProps, nextState) {
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
let newState = {};
if (!isEqual(selectedOptions, prevProps.selectedOptions)) {
newState = { selectedOptions };
}
componentDidUpdate(prevProps) {
if (this.props.isOpen !== prevProps.isOpen) {
handleAnyClick(this.props.isOpen, this.handleClick);
}
if (this.props.allowAnyClickClose !== prevProps.allowAnyClickClose) {
handleAnyClick(this.props.allowAnyClickClose, this.handleClick);
}
let newState = {};
if (!isEqual(this.props.selectedOptions, prevProps.selectedOptions)) {
newState = { selectedOptions: this.props.selectedOptions };
}
if (this.props.isMultiSelect !== prevProps.isMultiSelect) {
newState = Object.assign({}, newState, {
selectedOptions: []
});
}
if (this.props.selectedAll !== prevProps.selectedAll) {
newState = Object.assign({}, newState, {
selectedAll: this.props.selectedAll
});
}
if (!isEqual(this.props.groups, prevProps.groups)) {
const groups = this.convertGroups(this.props.groups);
const currentGroup = this.getCurrentGroup(groups);
newState = Object.assign({}, newState, {
groups,
currentGroup
});
}
if (!isEmpty(newState)) {
this.setState({ ...this.state, ...newState });
}
if (!isEqual(selectedGroups, prevProps.selectedGroups)) {
newState = Object.assign({}, newState, { selectedGroups });
}
if (isMultiSelect !== prevProps.isMultiSelect) {
newState = Object.assign({}, newState, {
selectedOptions: []
});
}
convertGroups = groups => {
if (!groups) return [];
const wrappedGroups = groups.map(this.convertGroup);
return wrappedGroups;
};
convertGroup = group => {
return {
key: group.key,
label: `${group.label} (${group.total})`,
total: group.total
};
};
getCurrentGroup = groups => {
const currentGroup = groups.length > 0 ? groups[0] : "No groups";
return currentGroup;
};
onButtonClick = () => {
this.props.onSelect &&
this.props.onSelect(
this.state.selectedAll ? this.props.options : this.state.selectedOptions
);
};
onSelect = option => {
this.props.onSelect && this.props.onSelect(option);
};
onChange = (option, e) => {
const { selectedOptions } = this.state;
const newSelectedOptions = e.target.checked
? [...selectedOptions, option]
: filter(selectedOptions, obj => obj.key !== option.key);
//console.log("onChange", option, e.target.checked, newSelectedOptions);
this.setState({
selectedOptions: newSelectedOptions,
selectedAll: newSelectedOptions.length === this.props.options.length
});
};
onSelectedAllChange = e => {
this.setState({
selectedAll: e.target.checked,
selectedOptions: e.target.checked ? this.props.options : []
});
};
onCurrentGroupChange = group => {
this.setState({
currentGroup: group
});
this.props.onChangeGroup && this.props.onChangeGroup(group);
};
render() {
const {
options,
hasNextPage,
isNextPageLoading,
loadNextPage,
value,
placeholder,
isDisabled,
onSearchChanged,
isMultiSelect,
buttonLabel,
selectAllLabel,
size,
displayType,
onAddNewClick,
allowCreation
} = this.props;
const { selectedOptions, selectedAll, currentGroup, groups } = this.state;
let containerHeight;
let containerWidth;
let listHeight;
let listWidth;
const itemHeight = 32;
const hasGroups = groups && groups.length > 0;
switch (size) {
case "compact":
containerHeight = hasGroups ? "326px" : "100%";
containerWidth = "379px";
listWidth = displayType === "dropdown" ? 356 : 356;
listHeight = hasGroups ? 488 : isMultiSelect ? 176 : 226;
break;
case "full":
default:
containerHeight = "100%";
containerWidth = displayType === "dropdown" ? "690px" : "326px";
listWidth = displayType === "dropdown" ? 320 : 302;
listHeight = 488;
break;
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.
//const itemCount = hasNextPage ? options.length + 1 : options.length;
return (
<StyledBodyContainer
containerHeight={containerHeight}
containerWidth={containerWidth}
{...this.props}
>
<div ref={this.ref}>
<div className="data_container">
<div className="data_column_one">
<ADSelectorMainHeader
value={value}
searchPlaceHolder={placeholder}
isDisabled={isDisabled}
allowCreation={allowCreation}
onAddNewClick={onAddNewClick}
onChange={onSearchChanged}
onClearSearch={onSearchChanged.bind(this, "")}
/>
{displayType === "aside" && groups && groups.length > 0 && (
<ComboBox
className="options_group_selector"
isDisabled={isDisabled}
options={groups}
selectedOption={currentGroup}
dropDownMaxHeight={200}
scaled={true}
scaledOptions={true}
size="content"
onSelect={this.onCurrentGroupChange}
/>
)}
{isMultiSelect && !groups && !groups.length && (
<Checkbox
label={selectAllLabel}
isChecked={
selectedAll || selectedOptions.length === options.length
}
isIndeterminate={!selectedAll && selectedOptions.length > 0}
className="option_select_all_checkbox"
onChange={this.onSelectedAllChange}
/>
)}
<ADSelectorMainBody
options={options}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={loadNextPage}
isMultiSelect={isMultiSelect}
listHeight={listHeight}
listWidth={listWidth}
itemHeight={itemHeight}
onRowChecked={this.onChange}
onRowSelect={this.onSelect}
/>
</div>
{/* {displayType === "dropdown" &&
size === "full" &&
groups &&
groups.length > 0 && (
<ADSelectorAdditionalBody
height={listHeight}
itemSize={itemHeight}
groups={groups}
/>
)} */}
</div>
{isMultiSelect && (
<ADSelectorFooter
buttonLabel={buttonLabel}
isDisabled={
!this.state.selectedOptions ||
!this.state.selectedOptions.length
}
onClick={this.onButtonClick}
/>
)}
</div>
</StyledBodyContainer>
);
if (selectedAll !== prevProps.selectedAll) {
newState = Object.assign({}, newState, {
selectedAll
});
}
if (!isEqual(groups, prevProps.groups)) {
const newGroups = this.convertGroups(groups);
const currentGroup = this.getCurrentGroup(newGroups);
newState = Object.assign({}, newState, {
groups: newGroups,
currentGroup
});
}
if (!isEmpty(newState)) {
this.setState({ ...this.state, ...newState });
}
}
convertGroups = groups => {
if (!groups) return [];
const wrappedGroups = groups.map(this.convertGroup);
return wrappedGroups;
};
convertGroup = group => {
return {
key: group.key,
label: `${group.label} (${group.total})`,
total: group.total
};
};
getCurrentGroup = groups => {
const currentGroup = groups.length > 0 ? groups[0] : "No groups";
return currentGroup;
};
onButtonClick = () => {
this.props.onSelect &&
this.props.onSelect(
this.state.selectedAll ? this.props.options : this.state.selectedOptions
);
};
onSelectedAllChange = e => {
this.setState({
selectedAll: e.target.checked,
selectedOptions: e.target.checked ? this.props.options : []
});
};
onOptionSelect = option => {
this.props.onSelect && this.props.onSelect(option);
};
onOptionChange = (option, e) => {
const { selectedOptions } = this.state;
const newSelectedOptions = e.target.checked
? [...selectedOptions, option]
: filter(selectedOptions, obj => obj.key !== option.key);
//console.log("onChange", option, e.target.checked, newSelectedOptions);
this.setState({
selectedOptions: newSelectedOptions,
selectedAll: newSelectedOptions.length === this.props.options.length
});
};
onGroupSelect = option => {
this.props.onGroupSelect && this.props.onGroupSelect(option);
};
onGroupChange = group => {
this.setState({
currentGroup: group
});
this.props.onGroupChange && this.props.onGroupChange(group);
};
render() {
const {
options,
hasNextPage,
isNextPageLoading,
loadNextPage,
value,
placeholder,
isDisabled,
onSearchChanged,
isMultiSelect,
buttonLabel,
selectAllLabel,
size,
displayType,
onAddNewClick,
allowCreation
} = this.props;
const { selectedOptions, selectedAll, currentGroup, groups, selectedGroups } = this.state;
let containerHeight;
let containerWidth;
let listHeight;
let listWidth;
const itemHeight = 32;
const hasGroups = groups && groups.length > 0;
switch (size) {
case "compact":
containerHeight = hasGroups ? "326px" : "100%";
containerWidth = "379px";
listWidth = displayType === "dropdown" ? 356 : 356;
listHeight = hasGroups ? 488 : isMultiSelect ? 176 : 226;
break;
case "full":
default:
containerHeight = "100%";
containerWidth = displayType === "dropdown" ? "690px" : "326px";
listWidth = displayType === "dropdown" ? 320 : 300;
listHeight = 488;
break;
}
// If there are more items to be loaded then add an extra row to hold a loading indicator.
//const itemCount = hasNextPage ? options.length + 1 : options.length;
return (
<StyledBodyContainer
containerHeight={containerHeight}
containerWidth={containerWidth}
{...this.props}
>
<div ref={this.ref}>
<div className="data_container">
<div className="data_column_one">
<ADSelectorMainHeader
value={value}
searchPlaceHolder={placeholder}
isDisabled={isDisabled}
allowCreation={allowCreation}
onAddNewClick={onAddNewClick}
onChange={onSearchChanged}
onClearSearch={onSearchChanged.bind(this, "")}
/>
{displayType === "aside" && groups && groups.length > 0 && (
<ComboBox
className="options_group_selector"
isDisabled={isDisabled}
options={groups}
selectedOption={currentGroup}
dropDownMaxHeight={200}
scaled={true}
scaledOptions={true}
size="content"
onSelect={this.onCurrentGroupChange}
/>
)}
{isMultiSelect && !groups && !groups.length && (
<Checkbox
label={selectAllLabel}
isChecked={
selectedAll || selectedOptions.length === options.length
}
isIndeterminate={!selectedAll && selectedOptions.length > 0}
className="option_select_all_checkbox"
onChange={this.onSelectedAllChange}
/>
)}
<ADSelectorMainBody
options={options}
hasNextPage={hasNextPage}
isNextPageLoading={isNextPageLoading}
loadNextPage={loadNextPage}
isMultiSelect={isMultiSelect}
listHeight={listHeight}
listWidth={listWidth}
itemHeight={itemHeight}
onRowChecked={this.onOptionChange}
onRowSelect={this.onOptionSelect}
selectedOptions={selectedOptions}
selectedAll={selectedAll}
/>
</div>
{displayType === "dropdown" &&
size === "full" &&
groups &&
groups.length > 0 && (
<ADSelectorAdditionalBody
options={groups}
selectedOptions={selectedGroups}
listHeight={listHeight}
itemHeight={itemHeight}
onRowChecked={this.onGroupChange}
onRowSelect={this.onGroupSelect}
/>
)}
</div>
{isMultiSelect && (
<ADSelectorFooter
buttonLabel={buttonLabel}
isDisabled={
!this.state.selectedOptions ||
!this.state.selectedOptions.length
}
onClick={this.onButtonClick}
/>
)}
</div>
</StyledBodyContainer>
);
}
}
export default ADSelectorBody;
ADSelectorBody.propTypes = {
isOpen: PropTypes.bool,
options: PropTypes.array,
groups: PropTypes.array,
hasNextPage: PropTypes.bool,
isNextPageLoading: PropTypes.bool,
loadNextPage: PropTypes.func,
value: PropTypes.string,
placeholder: PropTypes.string,
isDisabled: PropTypes.bool,
onSearchChanged: PropTypes.func,
isMultiSelect: PropTypes.bool,
buttonLabel: PropTypes.string,
selectAllLabel: PropTypes.string,
size: PropTypes.string,
displayType: PropTypes.oneOf(["dropdown", "aside"]),
onAddNewClick: PropTypes.func,
allowCreation: PropTypes.bool,
onSelect: PropTypes.func,
onChange: PropTypes.func,
onGroupSelect: PropTypes.func,
onGroupChange: PropTypes.func,
selectedOptions: PropTypes.array,
selectedGroups: PropTypes.array,
selectedAll: PropTypes.bool,
onCancel: PropTypes.func,
allowAnyClickClose: PropTypes.bool,
};
export default ADSelectorBody;

View File

@ -2,28 +2,28 @@ import React from "react";
import PropTypes from "prop-types";
import Button from "../../button";
const ADSelectorFooter = (props) => {
const { buttonLabel, isDisabled, onButtonClick } = props;
const ADSelectorFooter = props => {
const { buttonLabel, isDisabled, onClick } = props;
return (
<div className="button_container">
<Button
className="add_members_btn"
primary={true}
size="big"
label={buttonLabel}
scale={true}
isDisabled={isDisabled}
onClick={onButtonClick}
/>
</div>
);
return (
<div className="button_container">
<Button
className="add_members_btn"
primary={true}
size="big"
label={buttonLabel}
scale={true}
isDisabled={isDisabled}
onClick={onClick}
/>
</div>
);
};
ADSelectorFooter.propTypes = {
buttonLabel: PropTypes.string,
isDisabled: PropTypes.bool,
onButtonClick: PropTypes.func
}
buttonLabel: PropTypes.string,
isDisabled: PropTypes.bool,
onClick: PropTypes.func
};
export default ADSelectorFooter;
export default ADSelectorFooter;

View File

@ -7,58 +7,57 @@ import ADSelectorRow from "../../row";
import findIndex from "lodash/findIndex";
class ADSelectorAdditionalBody extends React.Component {
renderRow = ({ data, index, style }) => {
const option = data[index];
var isChecked = this.props.isMultiSelect
? this.props.selectedAll ||
findIndex(this.props.selectedOptions, { key: option.key }) > -1
: undefined;
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
return (
<ADSelectorRow
key={option.key}
label={option.label}
isChecked={isChecked}
style={style}
onChange={this.props.onRowChecked.bind(this, option)}
onSelect={this.props.onRowSelect.bind(this, option)}
/>
);
};
renderRow = ({ data, index, style }) => {
const option = data[index];
var isChecked = this.props.isMultiSelect ? (
this.state.selectedAll ||
findIndex(this.state.selectedOptions, { key: option.key }) > -1) : undefined;
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
return (
<ADSelectorRow
key={option.key}
label={option.label}
isChecked={isChecked}
style={style}
onChange={this.props.onRowChecked.bind(this, option)}
onSelect={this.props.onRowSelect.bind(this, option)}
/>
);
};
render() {
const { groups, listHeight, itemHeight } = this.props;
return (
<div className="data_column_two">
<Text.Body
as="p"
className="group_header"
fontSize={15}
isBold={true}
>
Groups
</Text.Body>
<FixedSizeList
className="group_list"
height={listHeight}
itemSize={itemHeight}
itemCount={groups.length}
itemData={groups}
outerElementType={CustomScrollbarsVirtualList}
>
{this.renderRow.bind(this)}
</FixedSizeList>
</div>
);
}
render() {
const { options, listHeight, itemHeight } = this.props;
return (
<div className="data_column_two">
<Text.Body as="p" className="group_header" fontSize={15} isBold={true}>
Groups
</Text.Body>
<FixedSizeList
className="group_list"
height={listHeight}
itemSize={itemHeight}
itemCount={options.length}
itemData={options}
outerElementType={CustomScrollbarsVirtualList}
>
{this.renderRow.bind(this)}
</FixedSizeList>
</div>
);
}
}
ADSelectorAdditionalBody.propTypes = {
groups: PropTypes.array,
listHeight: PropTypes.number,
itemHeight: PropTypes.number
}
options: PropTypes.array,
selectedOptions: PropTypes.array,
selectedAll: PropTypes.bool,
isMultiSelect: PropTypes.bool,
listHeight: PropTypes.number,
itemHeight: PropTypes.number,
onRowChecked: PropTypes.func,
onRowSelect: PropTypes.func
};
export default ADSelectorAdditionalBody;
export default ADSelectorAdditionalBody;

View File

@ -9,11 +9,6 @@ import { Text } from "../../../../text";
import findIndex from "lodash/findIndex";
class ADSelectorMainBody extends React.Component {
state = {
selectedAll: false,
selectedOptions: []
};
renderRow = ({ index, style }) => {
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
@ -33,10 +28,11 @@ class ADSelectorMainBody extends React.Component {
</div>
);
} else {
const option = this.props.options[index];
var isChecked = this.props.isMultiSelect
? this.state.selectedAll ||
findIndex(this.state.selectedOptions, { key: option.key }) > -1
const {options, isMultiSelect, selectedAll, selectedOptions} = this.props;
const option = options[index];
var isChecked = isMultiSelect
? selectedAll ||
findIndex(selectedOptions, { key: option.key }) > -1
: undefined;
content = (
@ -104,7 +100,10 @@ ADSelectorMainBody.propTypes = {
isNextPageLoading: PropTypes.bool,
loadNextPage: PropTypes.func,
selectedOptions: PropTypes.array,
selectedAll: PropTypes.bool,
isMultiSelect: PropTypes.bool,
listHeight: PropTypes.number,
listWidth: PropTypes.number,
itemHeight: PropTypes.number,