Skip to content
This repository has been archived by the owner on Feb 1, 2024. It is now read-only.

Commit

Permalink
Merge pull request #675 from open-apparel-registry/ki/search-by-oar-id
Browse files Browse the repository at this point in the history
Add `q=` free text param to facilities API endpoint

Connects #121
  • Loading branch information
Kelly Innes committed Jul 17, 2019
2 parents d06ace5 + d201bdd commit 41820e7
Show file tree
Hide file tree
Showing 13 changed files with 97 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Enable administrators to split facility matches into new facilities [#633](https://github.com/open-apparel-registry/open-apparel-registry/pull/633)
- Log requests made with token authentication [#646](https://github.com/open-apparel-registry/open-apparel-registry/pull/646)
- `./scripts/resetdb` to expedite refreshing application data during development [#672](https://github.com/open-apparel-registry/open-apparel-registry/pull/672)
- Enable searching by OAR ID from the facility search tab [#675](https://github.com/open-apparel-registry/open-apparel-registry/pull/675)

### Changed
- Require a token for all API endpoints [#644](https://github.com/open-apparel-registry/open-apparel-registry/pull/644)
Expand Down
16 changes: 8 additions & 8 deletions src/app/src/__tests__/utils.tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ it('gets the value from a React Select option object', () => {

it('creates a querystring from a set of filter selection', () => {
const emptyFilterSelections = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [],
contributorTypes: [],
countries: [],
Expand All @@ -163,7 +163,7 @@ it('creates a querystring from a set of filter selection', () => {
.toEqual(expectedEmptySelectionQSMatch);

const multipleFilterSelections = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [
{ value: 'foo', label: 'foo' },
{ value: 'bar', label: 'bar' },
Expand All @@ -181,7 +181,7 @@ it('creates a querystring from a set of filter selection', () => {
.toEqual(expectedMultipleFilterSelectionsMatch);

const allFilters = {
facilityName: 'hello',
facilityFreeTextQuery: 'hello',
contributors: [
{ value: 'hello', label: 'hello' },
{ value: 'world', label: 'hello' },
Expand All @@ -195,7 +195,7 @@ it('creates a querystring from a set of filter selection', () => {
};

const expectedAllFiltersMatch =
'name=hello&contributors=hello&contributors=world'
'q=hello&contributors=hello&contributors=world'
.concat('&contributor_types=foo&countries=bar');
expect(createQueryStringFromSearchFilters(allFilters))
.toEqual(expectedAllFiltersMatch);
Expand Down Expand Up @@ -230,7 +230,7 @@ it('checks whether the filters object has only empty values', () => {
it('creates a set of filters from a querystring', () => {
const contributorsString = '?contributors=1&contributors=2';
const expectedContributorsMatch = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [
{
value: 1,
Expand All @@ -252,7 +252,7 @@ it('creates a set of filters from a querystring', () => {

const typesString = '?contributor_types=Union&contributor_types=Service Provider';
const expectedTypesMatch = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [],
contributorTypes: [
{
Expand All @@ -274,7 +274,7 @@ it('creates a set of filters from a querystring', () => {

const countriesString = '?countries=US&countries=CN';
const expectedCountriesMatch = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [],
contributorTypes: [],
countries: [
Expand All @@ -296,7 +296,7 @@ it('creates a set of filters from a querystring', () => {

const stringWithCountriesMissing = '?contributor_types=Union&countries=';
const expectedMissingCountriesMatch = {
facilityName: '',
facilityFreeTextQuery: '',
contributors: [],
contributorTypes: [
{
Expand Down
26 changes: 24 additions & 2 deletions src/app/src/actions/facilities.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { createAction } from 'redux-act';
import noop from 'lodash/noop';
import get from 'lodash/get';

import apiRequest from '../util/apiRequest';

import {
logErrorAndDispatchFailure,
makeGetFacilitiesURLWithQueryString,
makeGetFacilityByOARIdURL,
makeFacilityDetailLink,
createQueryStringFromSearchFilters,
} from '../util/util';

Expand All @@ -19,7 +22,7 @@ export const failFetchSingleFacility = createAction('FAIL_FETCH_SINGLE_FACILITY'
export const completeFetchSingleFacility = createAction('COMPLETE_FETCH_SINGLE_FACILITY');
export const resetSingleFacility = createAction('RESET_SINGLE_FACILITY');

export function fetchFacilities() {
export function fetchFacilities(pushNewRoute = noop) {
return (dispatch, getState) => {
dispatch(startFetchFacilities());

Expand All @@ -31,7 +34,26 @@ export function fetchFacilities() {

return apiRequest
.get(makeGetFacilitiesURLWithQueryString(qs))
.then(({ data }) => dispatch(completeFetchFacilities(data)))
.then(({ data }) => {
const responseHasOnlyOneFacility = get(
data,
'features',
[],
).length === 1;

if (responseHasOnlyOneFacility) {
const facilityID = get(data, 'features[0].id', null);

if (!facilityID) {
throw new Error('No facility ID was found');
}

pushNewRoute(makeFacilityDetailLink(facilityID));
}

return data;
})
.then(data => dispatch(completeFetchFacilities(data)))
.catch(err => dispatch(logErrorAndDispatchFailure(
err,
'An error prevented fetching facilities',
Expand Down
3 changes: 2 additions & 1 deletion src/app/src/actions/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import {
updateListWithLabels,
} from '../util/util';

export const updateFacilityNameFilter = createAction('UPDATE_FACILITY_NAME_FILTER');
export const updateFacilityFreeTextQueryFilter =
createAction('UPDATE_FACILITY_FREE_TEXT_QUERY_FILTER');
export const updateContributorFilter = createAction('UPDATE_CONTRIBUTOR_FILTER');
export const updateContributorTypeFilter = createAction('UPDATE_CONTRIBUTOR_TYPE_FILTER');
export const updateCountryFilter = createAction('UPDATE_COUNTRY_FILTER');
Expand Down
5 changes: 4 additions & 1 deletion src/app/src/components/FilterSidebar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { connect } from 'react-redux';
import AppBar from '@material-ui/core/AppBar';
import Tabs from '@material-ui/core/Tabs';
import Tab from '@material-ui/core/Tab';
import { Route } from 'react-router-dom';

import FilterSidebarGuideTab from './FilterSidebarGuideTab';
import FilterSidebarSearchTab from './FilterSidebarSearchTab';
Expand Down Expand Up @@ -131,7 +132,9 @@ class FilterSidebar extends Component {
case filterSidebarTabsEnum.guide:
return <FilterSidebarGuideTab />;
case filterSidebarTabsEnum.search:
return <FilterSidebarSearchTab />;
// We wrap this component in a `Route` to give it access to `history.push`
// in its `mapDispatchToProps` function.
return <Route component={FilterSidebarSearchTab} />;
case filterSidebarTabsEnum.facilities:
return <FilterSidebarFacilitiesTab />;
default:
Expand Down
35 changes: 20 additions & 15 deletions src/app/src/components/FilterSidebarSearchTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import ReactSelect from 'react-select';
import FacilitySidebarSearchTabFacilitiesCount from './FacilitySidebarSearchTabFacilitiesCount';

import {
updateFacilityNameFilter,
updateFacilityFreeTextQueryFilter,
updateContributorFilter,
updateContributorTypeFilter,
updateCountryFilter,
Expand Down Expand Up @@ -59,8 +59,8 @@ function FilterSidebarSearchTab({
contributorTypeOptions,
countryOptions,
resetFilters,
facilityName,
updateFacilityName,
facilityFreeTextQuery,
updateFacilityFreeTextQuery,
contributors,
updateContributor,
contributorTypes,
Expand Down Expand Up @@ -114,14 +114,14 @@ function FilterSidebarSearchTab({
htmlFor={FACILITIES}
className="form__label"
>
Search a Facility Name
Search a Facility Name or OAR ID
</InputLabel>
<TextField
id={FACILITIES}
placeholder="Facility Name"
placeholder="Facility Name or OAR ID"
className="full-width margin-bottom-16 form__text-input"
value={facilityName}
onChange={updateFacilityName}
value={facilityFreeTextQuery}
onChange={updateFacilityFreeTextQuery}
onKeyPress={submitFormOnEnterKeyPress}
/>
</div>
Expand Down Expand Up @@ -243,11 +243,11 @@ FilterSidebarSearchTab.propTypes = {
contributorTypeOptions: contributorTypeOptionsPropType.isRequired,
countryOptions: countryOptionsPropType.isRequired,
resetFilters: func.isRequired,
updateFacilityName: func.isRequired,
updateFacilityFreeTextQuery: func.isRequired,
updateContributor: func.isRequired,
updateContributorType: func.isRequired,
updateCountry: func.isRequired,
facilityName: string.isRequired,
facilityFreeTextQuery: string.isRequired,
contributors: contributorOptionsPropType.isRequired,
contributorTypes: contributorTypeOptionsPropType.isRequired,
countries: countryOptionsPropType.isRequired,
Expand All @@ -273,7 +273,7 @@ function mapStateToProps({
},
},
filters: {
facilityName,
facilityFreeTextQuery,
contributors,
contributorTypes,
countries,
Expand All @@ -289,7 +289,7 @@ function mapStateToProps({
contributorOptions,
contributorTypeOptions,
countryOptions,
facilityName,
facilityFreeTextQuery,
contributors,
contributorTypes,
countries,
Expand All @@ -301,19 +301,24 @@ function mapStateToProps({
};
}

function mapDispatchToProps(dispatch) {
function mapDispatchToProps(dispatch, {
history: {
push,
},
}) {
return {
updateFacilityName: e => dispatch(updateFacilityNameFilter(getValueFromEvent(e))),
updateFacilityFreeTextQuery: e =>
dispatch(updateFacilityFreeTextQueryFilter(getValueFromEvent(e))),
updateContributor: v => dispatch(updateContributorFilter(v)),
updateContributorType: v => dispatch(updateContributorTypeFilter(v)),
updateCountry: v => dispatch(updateCountryFilter(v)),
resetFilters: () => {
dispatch(recordSearchTabResetButtonClick());
return dispatch(resetAllFilters());
},
searchForFacilities: () => dispatch(fetchFacilities()),
searchForFacilities: () => dispatch(fetchFacilities(push)),
submitFormOnEnterKeyPress: makeSubmitFormOnEnterKeyPressFunction(
() => dispatch(fetchFacilities()),
() => dispatch(fetchFacilities(push)),
),
};
}
Expand Down
4 changes: 2 additions & 2 deletions src/app/src/reducers/FacilitiesReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
} from '../actions/facilities';

import {
updateFacilityNameFilter,
updateFacilityFreeTextQueryFilter,
updateContributorFilter,
updateContributorTypeFilter,
updateCountryFilter,
Expand Down Expand Up @@ -122,7 +122,7 @@ export default createReducer({
[resetSingleFacility]: state => update(state, {
singleFacility: { $set: initialState.singleFacility },
}),
[updateFacilityNameFilter]: clearFacilitiesDataOnFilterChange,
[updateFacilityFreeTextQueryFilter]: clearFacilitiesDataOnFilterChange,
[updateContributorFilter]: clearFacilitiesDataOnFilterChange,
[updateContributorTypeFilter]: clearFacilitiesDataOnFilterChange,
[updateCountryFilter]: clearFacilitiesDataOnFilterChange,
Expand Down
8 changes: 4 additions & 4 deletions src/app/src/reducers/FiltersReducer.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createReducer } from 'redux-act';
import update from 'immutability-helper';

import {
updateFacilityNameFilter,
updateFacilityFreeTextQueryFilter,
updateContributorFilter,
updateContributorTypeFilter,
updateCountryFilter,
Expand All @@ -23,7 +23,7 @@ import {
} from '../util/util';

const initialState = Object.freeze({
facilityName: '',
facilityFreeTextQuery: '',
contributors: Object.freeze([]),
contributorTypes: Object.freeze([]),
countries: Object.freeze([]),
Expand All @@ -44,8 +44,8 @@ export const maybeSetFromQueryString = field => (state, payload) => {
};

export default createReducer({
[updateFacilityNameFilter]: (state, payload) => update(state, {
facilityName: { $set: payload },
[updateFacilityFreeTextQueryFilter]: (state, payload) => update(state, {
facilityFreeTextQuery: { $set: payload },
}),
[updateContributorFilter]: (state, payload) => update(state, {
contributors: { $set: payload },
Expand Down
2 changes: 1 addition & 1 deletion src/app/src/util/propTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export const reactSelectOptionPropType = shape({
});

export const filtersPropType = shape({
facilityName: string.isRequired,
facilityFreeTextQuery: string.isRequired,
contributors: arrayOf(reactSelectOptionPropType).isRequired,
contributorTypes: arrayOf(reactSelectOptionPropType).isRequired,
countries: arrayOf(reactSelectOptionPropType).isRequired,
Expand Down
8 changes: 4 additions & 4 deletions src/app/src/util/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,13 +129,13 @@ export const makeGetClientInfoURL = () => {
export const getValueFromObject = ({ value }) => value;

export const createQueryStringFromSearchFilters = ({
facilityName = '',
facilityFreeTextQuery = '',
contributors = [],
contributorTypes = [],
countries = [],
}) => {
const inputForQueryString = Object.freeze({
name: facilityName,
q: facilityFreeTextQuery,
contributors: compact(contributors.map(getValueFromObject)),
contributor_types: compact(contributorTypes.map(getValueFromObject)),
countries: compact(countries.map(getValueFromObject)),
Expand Down Expand Up @@ -177,14 +177,14 @@ export const createFiltersFromQueryString = (qs) => {
: qs;

const {
name = '',
q: facilityFreeTextQuery = '',
contributors = [],
contributor_types: contributorTypes = [],
countries = [],
} = querystring.parse(qsToParse);

return Object.freeze({
facilityName: name,
facilityFreeTextQuery,
contributors: createSelectOptionsFromParams(contributors),
contributorTypes: createSelectOptionsFromParams(contributorTypes),
countries: createSelectOptionsFromParams(countries),
Expand Down
8 changes: 6 additions & 2 deletions src/app/src/util/withQueryStringSync.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,13 +99,17 @@ export default function withQueryStringSync(WrappedComponent) {
};
}

function mapDispatchToProps(dispatch) {
function mapDispatchToProps(dispatch, {
history: {
push,
},
}) {
return {
hydrateFiltersFromQueryString: (qs, fetch = true) => {
dispatch(setFiltersFromQueryString(qs));

return fetch
? dispatch(fetchFacilities())
? dispatch(fetchFacilities(push))
: null;
},
clearFacilities: () => dispatch(resetFacilities()),
Expand Down
1 change: 1 addition & 0 deletions src/django/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class ProcessingAction:


class FacilitiesQueryParams:
Q = 'q'
NAME = 'name'
CONTRIBUTORS = 'contributors'
CONTRIBUTOR_TYPES = 'contributor_types'
Expand Down

0 comments on commit 41820e7

Please sign in to comment.