Skip to content

Commit

Permalink
Merge pull request #346 from openboxes/select-refactor
Browse files Browse the repository at this point in the history
Fix Select on Partial Receiving Page by refactoring SelectField
  • Loading branch information
jmiranda committed Jul 6, 2018
2 parents bc50f00 + 44f7673 commit 076fbd2
Show file tree
Hide file tree
Showing 4 changed files with 96 additions and 94 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"react-overlays": "^0.8.3",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-select": "^1.2.1",
"react-select-plus": "^1.2.0",
"react-spinners": "^0.3.2",
"react-table": "^6.8.6",
Expand Down
89 changes: 7 additions & 82 deletions src/js/components/form-elements/SelectField.jsx
Original file line number Diff line number Diff line change
@@ -1,92 +1,17 @@
import _ from 'lodash';
import React from 'react';
import Select, { Async } from 'react-select-plus';
import { Overlay } from 'react-overlays';
import PropTypes from 'prop-types';

import 'react-select-plus/dist/react-select-plus.css';

import BaseField from './BaseField';

// eslint-disable-next-line react/prop-types
const Dropdown = ({ children, style, width }) => (
<div style={{ ...style, position: 'absolute', width }}>
{children}
</div>
);
import Select from '../../utils/Select';

const SelectField = (props) => {
const renderInput = ({ objectValue, ...attributes }) => {
const options = _.map(attributes.options, (value) => {
if (typeof value === 'string') {
return { value, label: value };
} else if (objectValue) {
return { ...value, value: JSON.stringify(value.value) };
}

return value;
});

const onChange = (selectValue) => {
if (attributes.multi) {
const values = _.map(selectValue, val => (objectValue ? JSON.parse(val.value) : val.value));
attributes.onChange(values);
} else if (selectValue !== null && selectValue !== undefined) {
attributes.onChange(objectValue ? JSON.parse(selectValue.value) : selectValue.value);
} else {
attributes.onChange(null);
}
};

const delimiter = attributes.delimiter || ';';
let { value } = attributes;

if (objectValue) {
value = attributes.multi ? _.map(attributes.value, val => JSON.stringify(val))
: JSON.stringify(attributes.value);
}

renderInput.propTypes = {
objectValue: PropTypes.bool,
};

renderInput.defaultProps = {
objectValue: false,
};

const SelectType = attributes.async ? Async : Select;

// eslint-disable-next-line react/prop-types
const dropdownComponent = ({ children }) => {
const target = document.getElementById(`${attributes.id}-container`);
return (
<Overlay
show
placement="bottom"
target={target}
container={document.getElementById('root')}
>
<Dropdown width={target.offsetWidth}>
{children}
</Dropdown>
</Overlay>
);
};

return (
<div id={`${attributes.id}-container`}>
<SelectType
name={attributes.id}
{...attributes}
options={options}
delimiter={delimiter}
value={attributes.multi ? _.join(value, delimiter) : value}
onChange={onChange}
dropdownComponent={dropdownComponent}
/>
</div>
);
};
const renderInput = attributes => (
<Select
name={attributes.id}
{...attributes}
/>
);

return (
<BaseField
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ exports[`SelectField component is correctly rendering renders correctly 1`] = `
className="col-md-4"
>
<div
id="test-field-container"
id="select-id_1-container"
>
<div
className="Select is-clearable is-searchable Select--single"
Expand Down
98 changes: 88 additions & 10 deletions src/js/utils/Select.jsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,121 @@
import _ from 'lodash';
import React, { Component } from 'react';
import ReactSelect from 'react-select';
import ReactSelect, { Async } from 'react-select-plus';
import { Overlay } from 'react-overlays';
import PropTypes from 'prop-types';

// eslint-disable-next-line react/prop-types
const Dropdown = ({ children, style, width }) => (
<div style={{ ...style, position: 'absolute', width }}>
{children}
</div>
);

class Select extends Component {
constructor(props) {
super(props);

this.state = {
value: null,
id: _.uniqueId('select-id_'),
};

this.handleChange = this.handleChange.bind(this);
}

handleChange(value) {
this.setState({ value });

if (this.props.onChange) {
this.props.onChange(value);
if (this.props.multi) {
const values = _.map(value, val =>
(this.props.objectValue ? JSON.parse(val.value) : val.value));
this.setState({ value: values });
this.props.onChange(values);
} else if (value !== null && value !== undefined) {
const val = this.props.objectValue ? JSON.parse(value.value) : value.value;
this.props.onChange(val);
this.setState({ value: val });
} else {
this.props.onChange(null);
this.setState({ value: null });
}
}

render() {
const {
options: selectOptions, value: selectValue = this.state.value,
objectValue = false, multi = false, delimiter = ';', async = false, ...attributes
} = this.props;

const options = _.map(selectOptions, (value) => {
if (typeof value === 'string') {
return { value, label: value };
} else if (objectValue) {
return { ...value, value: JSON.stringify(value.value) };
}

return value;
});

let value = selectValue;

if (objectValue) {
value = multi ? _.map(selectValue, val => JSON.stringify(val))
: JSON.stringify(selectValue);
}

const SelectType = async ? Async : ReactSelect;

// eslint-disable-next-line react/prop-types
const dropdownComponent = ({ children }) => {
const target = document.getElementById(`${this.state.id}-container`);
return (
<Overlay
show
placement="bottom"
target={target}
container={document.getElementById('root')}
>
<Dropdown width={target.offsetWidth}>
{children}
</Dropdown>
</Overlay>
);
};

return (
<ReactSelect
value={this.state.value}
{...this.props}
onChange={this.handleChange}
/>
<div id={`${this.state.id}-container`}>
<SelectType
name={this.state.id}
{...attributes}
options={options}
delimiter={delimiter}
value={multi ? _.join(value, delimiter) : value}
onChange={this.handleChange}
dropdownComponent={dropdownComponent}
/>
</div>
);
}
}

export default Select;

Select.propTypes = {
options: PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.string,
PropTypes.shape({})])).isRequired,
value: PropTypes.oneOfType([PropTypes.string,
PropTypes.shape({}), PropTypes.any]),
onChange: PropTypes.func,
objectValue: PropTypes.bool,
multi: PropTypes.bool,
async: PropTypes.bool,
delimiter: PropTypes.string,
};

Select.defaultProps = {
value: undefined,
onChange: null,
objectValue: false,
multi: false,
async: false,
delimiter: ';',
};

0 comments on commit 076fbd2

Please sign in to comment.