Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/range match search #2

Merged
merged 26 commits into from
Oct 25, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
698b8f9
Fix validation for UBRN search
ONS-Tom Oct 23, 2017
419b49d
Add ONS inputs for Match search, used SDC styles
ONS-Tom Oct 23, 2017
bf735e0
Add inputs for Match search
ONS-Tom Oct 23, 2017
a032270
Add code for working Match search
ONS-Tom Oct 23, 2017
c0f1c01
Fix reload of Match data
ONS-Tom Oct 24, 2017
63f9fe4
Fix issue with clearing of Select boxes
ONS-Tom Oct 24, 2017
8dd6f17
Remove UPRN field from Match page
ONS-Tom Oct 24, 2017
95b1e00
Add react-select input with working aria-hidden
ONS-Tom Oct 24, 2017
9acea67
Refactor MatchForm, use seperate Components
ONS-Tom Oct 24, 2017
7dde3aa
Add scroll to results on search for Match
ONS-Tom Oct 24, 2017
76457a9
Fix scroll to bottom on search feature
ONS-Tom Oct 24, 2017
494f813
Fix focus on first input after resetting the form
ONS-Tom Oct 24, 2017
1731a01
Add minor fixes to UBRN page, naming etc.
ONS-Tom Oct 24, 2017
70a3e2d
Fix naming of SearchRefForm -> UBRNForm
ONS-Tom Oct 24, 2017
df74aea
Use CheckBoxInput component in Match
ONS-Tom Oct 24, 2017
12c7fc8
Add fixed code for RangeSearch query
ONS-Tom Oct 25, 2017
c0e42c1
Fix persistance of multiple select input values
ONS-Tom Oct 25, 2017
04ea066
Fix bug for Clear button not clearing all the data
ONS-Tom Oct 25, 2017
98419f2
Move SelectMultipleInput code to seperate file
ONS-Tom Oct 25, 2017
cb7bb69
Add TextInputInline component for dual inputs
ONS-Tom Oct 25, 2017
4b13d4d
Fix use of filter props in RangeForm
ONS-Tom Oct 25, 2017
4bbccb0
Add working RangeQuery search
ONS-Tom Oct 25, 2017
a5fe761
Fix formatRangeQuery, remove debugging statements
ONS-Tom Oct 25, 2017
a75cc4e
Fix showFilter bug, shows after new search
ONS-Tom Oct 25, 2017
dbecf5f
Transform businessName to upper case
ONS-Tom Oct 25, 2017
381dd49
Add encodeSpecialChars method to formQuery
ONS-Tom Oct 25, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
"react/forbid-prop-types": "off",
"arrow-body-style": "off",
"no-return-assign": "off",
"arrow-parens": "off"
"arrow-parens": "off",
"react/no-did-mount-set-state": "off"
},
"env": {
"browser": true
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
"react-redux": "^5.0.5",
"react-router": "^2.6.1",
"react-router-bootstrap": "^0.23.1",
"react-select": "^1.0.0-rc.10",
"react-stepper-horizontal": "^1.0.9",
"react-table": "^6.5.3",
"react-toggle": "^4.0.1",
Expand Down
15 changes: 12 additions & 3 deletions src/actions/ApiActions.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { ADD_MOST_RECENT_ERROR, REMOVE_LAST_ERROR, SET_UBRN_ERROR_MESSAGE, SENDING_UBRN_REQUEST, SET_UBRN_RESULTS, SET_UBRN_QUERY, SET_UBRN_HEADERS, SET_RANGE_HEADERS, SET_RANGE_ERROR_MESSAGE, SENDING_RANGE_REQUEST, SET_RANGE_RESULTS, SET_RANGE_QUERY, SET_PERIOD, SET_MATCH_RESULTS, SET_MATCH_HEADERS, SENDING_MATCH_REQUEST, SET_MATCH_QUERY, SET_MATCH_ERROR_MESSAGE } from '../constants/ApiConstants';
import { SET_MATCH_FORMATTED_QUERY, SET_RANGE_FORMATTED_QUERY, ADD_MOST_RECENT_ERROR, REMOVE_LAST_ERROR, SET_UBRN_ERROR_MESSAGE, SENDING_UBRN_REQUEST, SET_UBRN_RESULTS, SET_UBRN_QUERY, SET_UBRN_HEADERS, SET_RANGE_HEADERS, SET_RANGE_ERROR_MESSAGE, SENDING_RANGE_REQUEST, SET_RANGE_RESULTS, SET_RANGE_QUERY, SET_PERIOD, SET_MATCH_RESULTS, SET_MATCH_HEADERS, SENDING_MATCH_REQUEST, SET_MATCH_QUERY, SET_MATCH_ERROR_MESSAGE } from '../constants/ApiConstants';
import apiSearch from '../utils/apiSearch';
import { formMatchQuery, formRangeQuery } from '../utils/formQuery';
import periods from '../config/periods';

/**
Expand All @@ -15,7 +16,9 @@ export function matchSearch(query) {
dispatch(sendingRequest(SENDING_MATCH_REQUEST, true));
dispatch(setResults(SET_MATCH_RESULTS, { results: [] }));
dispatch(setQuery(SET_MATCH_QUERY, query));
apiSearch.match(query, (success, data) => {
const formattedQuery = formMatchQuery(query);
dispatch(setFormattedQuery(SET_MATCH_FORMATTED_QUERY, formattedQuery));
apiSearch.match(formattedQuery, (success, data) => {
dispatch(sendingRequest(SENDING_MATCH_REQUEST, false));
if (success) {
dispatch(setResults(SET_MATCH_RESULTS, {
Expand Down Expand Up @@ -44,7 +47,9 @@ export function rangeSearch(query) {
dispatch(sendingRequest(SENDING_RANGE_REQUEST, true));
dispatch(setResults(SET_RANGE_RESULTS, { results: [] }));
dispatch(setQuery(SET_RANGE_QUERY, query));
apiSearch.match(query, (success, data) => {
const formattedQuery = formRangeQuery(query);
dispatch(setFormattedQuery(SET_RANGE_FORMATTED_QUERY, formattedQuery));
apiSearch.match(formattedQuery, (success, data) => {
dispatch(sendingRequest(SENDING_RANGE_REQUEST, false));
if (success) {
dispatch(setResults(SET_RANGE_RESULTS, {
Expand Down Expand Up @@ -109,6 +114,10 @@ export function setQuery(type, query) {
return { type, query };
}

export function setFormattedQuery(type, query) {
return { type, query };
}

export function setHeaders(type, newState) {
return { type, newState };
}
Expand Down
22 changes: 22 additions & 0 deletions src/components/CheckBoxInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import PropTypes from 'prop-types';

const CheckBoxInput = ({ id, label, onChangeFilter, value }) => {
return (
<div className="sdc-isolation field field--checkbox field--multiplechoice">
<div className="field__item js-focusable-box">
<input onChange={onChangeFilter} value={value} className="input input--checkbox js-focusable" type="checkbox" id={id} />
<label className="label label--inline venus" htmlFor="checkbox">{label}</label>
</div>
</div>
);
};

CheckBoxInput.propTypes = {
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
onChangeFilter: PropTypes.func.isRequired,
value: PropTypes.string.isRequired,
};

export default CheckBoxInput;
47 changes: 47 additions & 0 deletions src/components/MatchForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'registers-react-library';
import { employmentBands, legalStatusBands, turnoverBands, tradingStatusBands } from '../utils/convertBands';
import TextInput from './TextInput';
import SelectInput from './SelectInput';
import CheckBoxInput from './CheckBoxInput';

class MatchForm extends React.Component {
// For the id of each input, we use the same name as the business-index-api input
render() {
return (
<form>
<TextInput ref={ip => (this.childTextInput = ip)} value={this.props.initialValues.BusinessName} label="Business Name" id="BusinessName" autoFocus onChange={this.props.onChange} /><br />
<TextInput value={this.props.initialValues.VatRefs} label="VAT Number" id="VatRefs" onChange={this.props.onChange} /><br />
<TextInput value={this.props.initialValues.PayeRefs} label="PAYE Number" id="PayeRefs" onChange={this.props.onChange} /><br />
<TextInput value={this.props.initialValues.CompanyNo} label="Company Number" id="CompanyNo" onChange={this.props.onChange} /><br />
<TextInput value={this.props.initialValues.IndustryCode} label="Industry Code" id="IndustryCode" onChange={this.props.onChange} /><br />
<SelectInput value={this.props.initialValues.EmploymentBands} label="Employment Bands" id="EmploymentBands" onChange={this.props.onChange} bands={employmentBands} /><br />
<SelectInput value={this.props.initialValues.LegalStatus} label="Legal Status" id="LegalStatus" onChange={this.props.onChange} bands={legalStatusBands} /><br />
<SelectInput value={this.props.initialValues.Turnover} label="Turnover" id="Turnover" onChange={this.props.onChange} bands={turnoverBands} /><br />
<SelectInput value={this.props.initialValues.TradingStatus} label="Trading Status" id="TradingStatus" onChange={this.props.onChange} bands={tradingStatusBands} /><br />
<TextInput label="Post Code" id="PostCode" onChange={this.props.onChange} /><br />
<Button id="loginButton" size="wide" text="Search" onClick={!this.props.currentlySending ? this.props.onSubmit : null} ariaLabel="Login Button" type="submit" loading={this.props.currentlySending} />
&nbsp;
<Button id="clearButton" size="wide" text="Clear" onClick={this.props.onClear} ariaLabel="Clear Button" type="reset" />
<br /><br />
{this.props.showFilter &&
<CheckBoxInput value={this.props.filter} label="Filter Results" id="FilterCheckbox" onChangeFilter={this.props.onChangeFilter} />
}
</form>
);
}
}

MatchForm.propTypes = {
currentlySending: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onChangeFilter: PropTypes.func.isRequired,
filter: PropTypes.bool.isRequired,
showFilter: PropTypes.bool.isRequired,
initialValues: PropTypes.object.isRequired,
};

export default MatchForm;
47 changes: 47 additions & 0 deletions src/components/RangeForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Button } from 'registers-react-library';
import Select from 'react-select';
import 'react-select/dist/react-select.min.css';
import { employmentBands, legalStatusBands, turnoverBands, tradingStatusBands } from '../utils/convertBands';
import TextInput from './TextInput';
import CheckBoxInput from './CheckBoxInput';
import SelectMultipleInput from './SelectMultipleInput';
import TextInputInline from './TextInputInline';

class RangeForm extends React.Component {
// For the id of each input, we use the same name as the business-index-api input
render() {
return (
<form>
<TextInputInline autoFocus ref={ip => (this.childTextInput = ip)} placeholderMin="Industry Code Min" placeholderMax="Industry Code Max" value={this.props.initialValues.IndustryCode} label="Industry Code" id="IndustryCode" onChange={this.props.onChange} /><br />
<TextInput value={this.props.initialValues.PostCode} label="Post Code" id="PostCode" onChange={this.props.onChange} /><br />
<SelectMultipleInput value={this.props.initialValues.EmploymentBands} id="EmploymentBands" onChange={this.props.onChange} label="Employment Bands" bands={employmentBands} /><br />
<SelectMultipleInput value={this.props.initialValues.LegalStatus} id="LegalStatus" onChange={this.props.onChange} label="Legal Status Bands" bands={legalStatusBands} /><br />
<SelectMultipleInput value={this.props.initialValues.Turnover} id="Turnover" onChange={this.props.onChange} label="Turnover Bands" bands={turnoverBands} /><br />
<SelectMultipleInput value={this.props.initialValues.TradingStatus} id="TradingStatus" onChange={this.props.onChange} label="Trading Status Bands" bands={tradingStatusBands} /><br />
<br />
<Button id="loginButton" size="wide" text="Search" onClick={!this.props.currentlySending ? this.props.onSubmit : null} ariaLabel="Login Button" type="submit" loading={this.props.currentlySending} />
&nbsp;
<Button id="clearButton" size="wide" text="Clear" onClick={this.props.onClear} ariaLabel="Clear Button" type="reset" />
<br /><br />
{this.props.showFilter &&
<CheckBoxInput value={this.props.filter} label="Filter Results" id="FilterCheckbox" onChangeFilter={this.props.onChangeFilter} />
}
</form>
);
}
}

RangeForm.propTypes = {
currentlySending: PropTypes.bool.isRequired,
onSubmit: PropTypes.func.isRequired,
onChange: PropTypes.func.isRequired,
onClear: PropTypes.func.isRequired,
onChangeFilter: PropTypes.func.isRequired,
filter: PropTypes.bool.isRequired,
showFilter: PropTypes.bool.isRequired,
initialValues: PropTypes.object.isRequired,
};

export default RangeForm;
28 changes: 28 additions & 0 deletions src/components/SelectInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import PropTypes from 'prop-types';

const SelectInput = ({ id, label, bands, onChange, value }) => {
if (value === undefined) {
value = '';
}
return (
<div className="sdc-isolation field field--select">
<label className="label" htmlFor="select">{label}
</label>
<select id={id} value={value} className="input input--select" name="select" onInput={onChange} style={{ padding: '0.3rem', fontSize: '1rem' }}>
<option value="">Select an option</option>
{ Object.keys(bands).map(band => (<option key={band} value={band}>{band} [{bands[band]}]</option>))}
</select>
</div>
);
};

SelectInput.propTypes = {
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
bands: PropTypes.object.isRequired,
value: PropTypes.string.isRequired,
};

export default SelectInput;
85 changes: 85 additions & 0 deletions src/components/SelectMultipleInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import PropTypes from 'prop-types';
import Select from 'react-select';
import 'react-select/dist/react-select.min.css';

class SelectMultipleInput extends React.Component {
constructor(props) {
super(props);
this.state = {
values: this.formValues(this.props.value),
inputsJson: this.formProperJson(this.props.bands),
};
this.handleSelectChange = this.handleSelectChange.bind(this);
// Look at index.css for .Select-menu-outer for a 'position' fix
// to push down items below when the options menu is open
}
componentWillReceiveProps(nextProps) {
if (this.props.value !== nextProps.value) {
this.setState({ values: this.formValues(nextProps.value) });
}
}
componentDidUpdate() {
// This is to fix a bug with react-select where the little cross symbol does
// not appear due to an aria-hidden attribute.
const elements = document.getElementsByClassName('Select-value-icon');
for (let i = 0; i <= elements.length; i += 1) {
if (document.getElementsByClassName('Select-value-icon')[i] !== undefined) {
document.getElementsByClassName('Select-value-icon')[i].setAttribute('aria-hidden', 'false');
}
}
}
formValues(value) {
if (value === undefined) {
return [];
}
return value.join(',');
}
formProperJson(json) {
const arr = Object.keys(json).map((key) => {
return { label: `${key} [${json[key]}]`, value: key };
});
return arr;
}
handleSelectChange(values) {
this.setState({ values });
// Make our lives easier by mimicking the exact json of an input event
const evt = {
target: {
id: this.props.id,
value: values.split(','),
},
};
this.props.onChange(evt);
}
render() {
return (
<div id={this.props.id}>
<div className="sdc-isolation">
<label className="label" htmlFor="select">{this.props.label}</label>
</div>
<Select
style={{ width: '400px' }}
closeOnSelect={false}
disabled={false}
multi
onChange={this.handleSelectChange}
options={this.state.inputsJson}
placeholder=""
simpleValue
value={this.state.values}
/>
</div>
);
}
}

SelectMultipleInput.propTypes = {
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
bands: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired,
value: PropTypes.array.isRequired,
};

export default SelectMultipleInput;
34 changes: 34 additions & 0 deletions src/components/TextInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import PropTypes from 'prop-types';

class TextInput extends React.Component {
render() {
// This is to fix an issue where if this.props.value is undefined, the previous
// value of this.props.value is used.
let value = this.props.value;
if (this.props.value === undefined) {
value = '';
}
return (
<div className="sdc-isolation field">
<label className="label" htmlFor="text-input">{this.props.label}
</label>
<input ref={ip => (this.myInput = ip)} value={value} autoFocus={this.props.autoFocus} className="input input--text" onChange={this.props.onChange} type="text" id={this.props.id} />
</div>
);
}
}

TextInput.defaultProps = {
autoFocus: false,
};

TextInput.propTypes = {
id: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
autoFocus: PropTypes.bool.isRequired,
value: PropTypes.string.isRequired,
};

export default TextInput;
Loading