Skip to content

Instantly share code, notes, and snippets.

@colonelrascals
Created April 17, 2018 20:09
Show Gist options
  • Select an option

  • Save colonelrascals/f562fb98781b37b4c2ef45a074b7d0b2 to your computer and use it in GitHub Desktop.

Select an option

Save colonelrascals/f562fb98781b37b4c2ef45a074b7d0b2 to your computer and use it in GitHub Desktop.
class Search extends React.Component {
constructor(props) {
super(props);
this.state = {
locationValue: [],
resourceValue: [],
keywords: null,
results: {
loading: false,
data: { resources: [], num_hits: 0 },
error: null
},
firstSearch: true,
currentPage: 1,
totalPages: 1
};
}
componentWillMount() {
// if a query in the url bar, go ahead and populate state.
const query = queryString.parse(window.location.hash.replace('#', ''));
if (Object.keys(query).length) {
const keyMap = {
location: 'locationValue',
resource: 'resourceValue'
};
const newState = {};
Object.keys(keyMap).forEach(key => {
if (query[key] && typeof query[key] === 'string') {
newState[keyMap[key]] = [{ value: query[key], label: query[key] }];
} else if (query[key] && typeof query[key] === 'object') {
newState[keyMap[key]] = query[key].map(v => ({ value: v, label: v }));
}
});
this.fireSearch(newState);
}
}
fireSearch(newState) {
this.setState(
{
...newState,
results: { ...this.state.results, loading: true }
},
this.search
);
}
handleClick(keyword) {
this.setState(
{
resourceValue: [{ className: "Select-create-option-placeholder", label: keyword, value: keyword }],
results: { ...this.state.results, loading: true }
},
this.search
);
}
onChange(value, stateKey) {
this.setState(
{
[stateKey]: value,
results: { ...this.state.results, loading: true }
},
this.search
);
}
handlePageChange(value) {
this.setState({ currentPage: value }, () => this.fireSearch());
}
search() {
const resource_qlst = this.state.resourceValue.map(o => o.label);
const location_qlst = this.state.locationValue.map(o => o.label);
const qs = queryString.stringify({
location: location_qlst,
resource: resource_qlst,
page: this.state.currentPage
});
window.history.replaceState(null, null, `${window.location.pathname}#${qs}`);
request
.get('/api/resources/search')
.query({
resource_meta: resource_qlst,
location: location_qlst,
page: this.state.currentPage
})
.then((success, err) => {
this.setState(
{
results: {
loading: false,
error: err,
data: {
resources: success.body.resources,
num_hits: success.body.num_results
}
},
keywords: success.body.keywords,
firstSearch: false,
totalPages: success.body.num_pages
},
() => {
// init new tooltips
$('[data-toggle="tooltip"]').tooltip();
}
)
});
// record search event
ReactGA.event({
category: 'Search',
action: 'Search Executed',
label: `Resources: ${resource_qlst.join(', ')}; Locations: ${location_qlst.join(', ')}`
});
}
getOptions(input, kw, callback) {
request
.get(`/api/resources/suggest/${kw}`)
.query({ [kw]: input })
.then((success, err) => {
const options = success.body.suggestions.map(o => ({
value: o,
label: o
}));
callback(err, { options });
});
}
render() {
return (
<div>
<div style={{ minHeight: 80 }}>
<AutoAffix viewportOffsetTop={80} container={this}>
<div className="search-tools">
<div className="row">
<div className="col-xs-12 col-sm-5">
<div className="form-group search-form-input">
<AsyncCreatable
name="resource-search"
value={this.state.resourceValue}
multi
cache={false}
filterOption={() => true}
autoload={false}
loadOptions={(input, cb) => this.getOptions(input, 'resource', cb)}
onChange={vals => this.onChange(vals, 'resourceValue')}
placeholder="Resource or Services (e.g. METROLift, transportation)"
arrowRenderer={() => null}
/>
</div>
</div>
<div className="col-xs-12 col-sm-5">
<div className="form-group search-form-input">
<AsyncCreatable
name="location-search"
value={this.state.locationValue}
multi
cache={false}
filterOption={() => true}
autoload={false}
loadOptions={(input, cb) => this.getOptions(input, 'location', cb)}
onChange={vals => this.onChange(vals, 'locationValue')}
placeholder="Zip Code (e.g. 77036)"
arrowRenderer={() => null}
/>
</div>
</div>
<div className="col-xs-12 col-sm-2">
<button
className="btn btn-fill"
onClick={() => this.fireSearch(this.state)}
disabled={this.state.results.loading}>
{this.state.results.loading ? (
<i className="fa fa-lg fa-spinner fa-spin" />
) : (
<i className="fa fa-search" aria-hidden="true" />
)}
</button>
</div>
</div>
</div>
</AutoAffix>
</div>
{this.state.keywords ? (
<div className="row">
<div className="col-xs-12 col-sm-5">
<p>suggested keywords: </p>
{this.state.keywords.map((keyword) => <a onClick={() => { this.handleClick(keyword) }} style={styles}>{keyword} </a>
)}
</div>
</div>) :
null}
<div className="row">
<div className="col-xs-12 col-sm-6">
<SearchResults
{...this.state.results}
keywords={this.state.keywords}
count={this.props.count}
csrf={this.props.csrfToken}
firstSearch={this.state.firstSearch}
currentUser={this.props.currentUser}
/>
{this.state.totalPages > 1 && (
<Pagination
prev
next
first
last
ellipsis
boundaryLinks
bsSize="medium"
maxButtons={10}
items={this.state.totalPages}
activePage={this.state.currentPage}
onSelect={value => this.handlePageChange(value)}
/>
)}
</div>
<div className="col-xs-12 col-sm-6">
{!this.state.results.data.resources.length ? null : (
<Map
data={this.state.results.data.resources.map(d => ({
id: d.id,
name: d.name,
description: d.description,
latitude: d.latitude || null,
longitude: d.longitude || null
}))}
/>
)}
{!this.state.results.data.resources.length ? null : (
<p style={{ top: 667, position: 'fixed' }}>
Not finding a resource? Please <a href="/resource-submission/">submit it</a> to be
added to the Welnity database.
</p>
)}
</div>
</div>
</div>
);
}
}
ReactDOM.render(
React.createElement(
Search,
Object.assign(window.props, {
csrfToken: window.csrfToken,
httpReferrer: window.httpReferrer,
currentUser: window.currentUser
})
),
window.react_mount
);
class UserClickButton extends Component {
constructor(props) {
super(props);
this.onClick = this.handleOnClick.bind(this);
}
handleOnClick() {
const { resource, csrf } = this.props;
console.log(this.props.keywords[0])
request
.post('/api/resources/click/')
.set('X-CSRFToken', csrf)
.send({ id: resource.id })
.then((data) => {
console.log('about to search');
request
.get('/api/resources/search')
.query({
resource_meta: this.props.keywords[2],
page: 1
})
.then(()=>{
this.forceUpdate()
})
});
}
render() {
return (
<div className="pull-right">
<a className="private-blue" style={{ marginTop: 10, fontSize: 20, fontWeight: 'bold' }} onClick={() => this.handleOnClick()}>View Similar Resources</a>
</div>
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment