Updating search functionality setup
This commit is contained in:
parent
1beebf9b9b
commit
b9dc338c6d
|
@ -1,4 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import _ from 'lodash';
|
||||||
import RelatedInterviewsList from '../interviews/relatedInterviewsList';
|
import RelatedInterviewsList from '../interviews/relatedInterviewsList';
|
||||||
import InterviewsList from '../interviews/interviewsList';
|
import InterviewsList from '../interviews/interviewsList';
|
||||||
import SingleInterview from '../interviews/singleInterview';
|
import SingleInterview from '../interviews/singleInterview';
|
||||||
|
@ -6,7 +7,7 @@ import TopicsList from '../topicsList';
|
||||||
import ProjectsList from '../projectsList';
|
import ProjectsList from '../projectsList';
|
||||||
import SearchBar from '../searchBar';
|
import SearchBar from '../searchBar';
|
||||||
import SearchResults from '../searchResults';
|
import SearchResults from '../searchResults';
|
||||||
import Data from '../../data/archives/interviews';
|
import InterviewsData from '../../data/archives/interviews';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
class BrowseArchives extends React.Component {
|
class BrowseArchives extends React.Component {
|
||||||
|
@ -15,18 +16,24 @@ class BrowseArchives extends React.Component {
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
term: '',
|
term: '',
|
||||||
|
searchResults: [],
|
||||||
isSingleInterviewModalOpen: false,
|
isSingleInterviewModalOpen: false,
|
||||||
isInterviewsListModalOpen: false,
|
isInterviewsListModalOpen: false,
|
||||||
activeSingleInterviewId: 1,
|
activeSingleInterviewId: 1,
|
||||||
isSearchActive: false,
|
isSearchActive: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.onInputChange = this.onInputChange.bind(this);
|
this.onSearchInputChange = this.onSearchInputChange.bind(this);
|
||||||
this.toggleSingleInterview = this.toggleSingleInterview.bind(this);
|
this.toggleSingleInterview = this.toggleSingleInterview.bind(this);
|
||||||
this.toggleInterviewsListModal = this.toggleInterviewsListModal.bind(this);
|
this.toggleInterviewsListModal = this.toggleInterviewsListModal.bind(this);
|
||||||
|
this.setSearchTerm = this.setSearchTerm.bind(this);
|
||||||
|
this.clearSearchInput = this.clearSearchInput.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
onInputChange(event) {
|
onSearchInputChange = (event) => {
|
||||||
|
const { term } = this.state;
|
||||||
|
const getSearchResults = _.debounce(() => { this.getSearchResults(term); }, 500);
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
term: event.target.value,
|
term: event.target.value,
|
||||||
isSearchActive: true,
|
isSearchActive: true,
|
||||||
|
@ -35,15 +42,42 @@ class BrowseArchives extends React.Component {
|
||||||
if (event.target.value.length === 0) {
|
if (event.target.value.length === 0) {
|
||||||
this.setState({ isSearchActive: false });
|
this.setState({ isSearchActive: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throttle search result frequency with debounce
|
||||||
|
getSearchResults(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
getSelectedInterview() {
|
getSearchResults = (term) => {
|
||||||
|
// Edit function to do actual search based on term and update searchResults with dynamic data
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.log(`Get search results array based on searching for: ${term}`);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
searchResults: InterviewsData,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSelectedInterview = () => {
|
||||||
const { activeSingleInterviewId } = this.state;
|
const { activeSingleInterviewId } = this.state;
|
||||||
const selectedInterview = Data.find(item => item.id === activeSingleInterviewId);
|
const selectedInterview = InterviewsData.find(item => item.id === activeSingleInterviewId);
|
||||||
return selectedInterview;
|
return selectedInterview;
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleInterviewsListModal() {
|
setSearchTerm = (event) => {
|
||||||
|
this.setState({
|
||||||
|
term: event.target.innerText,
|
||||||
|
isSearchActive: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
clearSearchInput = () => {
|
||||||
|
this.setState({
|
||||||
|
isSearchActive: false,
|
||||||
|
term: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
toggleInterviewsListModal = () => {
|
||||||
const { isInterviewsListModalOpen } = this.state;
|
const { isInterviewsListModalOpen } = this.state;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
|
@ -52,13 +86,19 @@ class BrowseArchives extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
toggleSingleInterview(event) {
|
toggleSingleInterview = (event) => {
|
||||||
const { isSingleInterviewModalOpen, isInterviewsListModalOpen } = this.state;
|
const { isSingleInterviewModalOpen, isInterviewsListModalOpen } = this.state;
|
||||||
|
|
||||||
|
let clickedInterview = event.target;
|
||||||
|
while (clickedInterview.id === '') {
|
||||||
|
clickedInterview = clickedInterview.parentNode;
|
||||||
|
}
|
||||||
|
const clickedSingleInterviewId = clickedInterview.id;
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isInterviewsListModalOpen: !isInterviewsListModalOpen,
|
isInterviewsListModalOpen: !isInterviewsListModalOpen,
|
||||||
isSingleInterviewModalOpen: !isSingleInterviewModalOpen,
|
isSingleInterviewModalOpen: !isSingleInterviewModalOpen,
|
||||||
activeSingleInterviewId: Number(event.target.id),
|
activeSingleInterviewId: Number(clickedSingleInterviewId),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,32 +109,42 @@ class BrowseArchives extends React.Component {
|
||||||
isSearchActive,
|
isSearchActive,
|
||||||
activeSingleInterviewId,
|
activeSingleInterviewId,
|
||||||
term,
|
term,
|
||||||
|
searchResults,
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="browse-wrap">
|
<div className="browse-wrap">
|
||||||
<SearchBar onInputChange={this.onInputChange} term={term} />
|
<SearchBar
|
||||||
|
onSearchInputChange={this.onSearchInputChange}
|
||||||
|
clearSearchInput={this.clearSearchInput}
|
||||||
|
isSearchActive={isSearchActive}
|
||||||
|
term={term}
|
||||||
|
/>
|
||||||
<div className="browse-content-wrap container">
|
<div className="browse-content-wrap container">
|
||||||
<div className="browse-content-left">
|
<div className="browse-content-left">
|
||||||
{isSearchActive &&
|
{isSearchActive &&
|
||||||
(<RelatedInterviewsList
|
(<RelatedInterviewsList
|
||||||
data={Data}
|
data={InterviewsData}
|
||||||
toggleSingleInterview={this.toggleSingleInterview}
|
toggleSingleInterview={this.toggleSingleInterview}
|
||||||
/>)
|
/>)
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div className="browse-content-right">
|
<div className="browse-content-right">
|
||||||
{isSearchActive ? <SearchResults /> :
|
{isSearchActive ? (
|
||||||
|
<SearchResults
|
||||||
|
data={searchResults}
|
||||||
|
toggleSingleInterview={this.toggleSingleInterview}
|
||||||
|
/>) :
|
||||||
(
|
(
|
||||||
<React.Fragment>
|
<React.Fragment>
|
||||||
<InterviewsList
|
<InterviewsList
|
||||||
data={Data}
|
data={InterviewsData}
|
||||||
isInterviewsListModalOpen={isInterviewsListModalOpen}
|
isInterviewsListModalOpen={isInterviewsListModalOpen}
|
||||||
toggleSingleInterview={this.toggleSingleInterview}
|
toggleSingleInterview={this.toggleSingleInterview}
|
||||||
toggleInterviewsListModal={this.toggleInterviewsListModal}
|
toggleInterviewsListModal={this.toggleInterviewsListModal}
|
||||||
/>
|
/>
|
||||||
<TopicsList />
|
<TopicsList setSearchTerm={this.setSearchTerm} />
|
||||||
<ProjectsList />
|
<ProjectsList setSearchTerm={this.setSearchTerm} />
|
||||||
</React.Fragment>
|
</React.Fragment>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
import Data from '../../data/archives/projects';
|
import Data from '../../data/archives/projects';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
export default () => (
|
const ProjectsList = props => (
|
||||||
<div className="projects-list">
|
<div className="projects-list">
|
||||||
<h4>Projects</h4>
|
<h4>Projects</h4>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
Data.map(project => <li key={project}><span>{ project }</span></li>)
|
Data.map(project => (
|
||||||
|
// eslint-disable-next-line
|
||||||
|
<li key={project} onClick={props.setSearchTerm}>
|
||||||
|
<span>{ project }</span>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ProjectsList.propTypes = {
|
||||||
|
setSearchTerm: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ProjectsList;
|
||||||
|
|
|
@ -6,20 +6,34 @@ const SearchBar = props => (
|
||||||
<div className="search-bar">
|
<div className="search-bar">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<h3>Browse Archives</h3>
|
<h3>Browse Archives</h3>
|
||||||
<input
|
<form className="search-form">
|
||||||
className="search-input"
|
<input
|
||||||
type="search"
|
className="search-input"
|
||||||
placeholder="Search archives"
|
type="search"
|
||||||
value={props.term}
|
placeholder="Search archives"
|
||||||
onChange={props.onInputChange}
|
value={props.term}
|
||||||
/>
|
onChange={props.onSearchInputChange}
|
||||||
|
/>
|
||||||
|
{ props.isSearchActive && (
|
||||||
|
// eslint-disable-next-line
|
||||||
|
<span
|
||||||
|
className="search-clear-button"
|
||||||
|
onClick={props.clearSearchInput}
|
||||||
|
>
|
||||||
|
Clear search
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
SearchBar.propTypes = {
|
SearchBar.propTypes = {
|
||||||
term: PropTypes.string.isRequired,
|
term: PropTypes.string.isRequired,
|
||||||
onInputChange: PropTypes.func.isRequired,
|
isSearchActive: PropTypes.bool.isRequired,
|
||||||
}
|
onSearchInputChange: PropTypes.func.isRequired,
|
||||||
|
clearSearchInput: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default SearchBar;
|
export default SearchBar;
|
||||||
|
|
|
@ -13,17 +13,40 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-form {
|
||||||
|
position: relative;
|
||||||
|
bottom: calculateRem(-24);
|
||||||
|
}
|
||||||
|
|
||||||
.search-input {
|
.search-input {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calculateRem(48);
|
height: calculateRem(48);
|
||||||
border: 5px solid #efefef;
|
border: 5px solid #efefef;
|
||||||
padding: calculateRem(12);
|
padding: calculateRem(12) calculateRem(100) calculateRem(12) calculateRem(12);
|
||||||
font-size: calculateRem(16);
|
font-size: calculateRem(16);
|
||||||
position: relative;
|
|
||||||
bottom: calculateRem(-24);
|
|
||||||
|
|
||||||
&:focus,
|
&:focus,
|
||||||
&:active {
|
&:active {
|
||||||
outline: none;
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.search-clear-button {
|
||||||
|
position: absolute;
|
||||||
|
top: 10%;
|
||||||
|
right: calculateRem(4);
|
||||||
|
height: 80%;
|
||||||
|
border: 0;
|
||||||
|
padding: 0 calculateRem(16);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: calculateRem(14);
|
||||||
|
background-color: #fff;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:focus,
|
||||||
|
&:active {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,40 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
const SearchResults = () => (
|
const SearchResults = (props) => {
|
||||||
<div className="search-results">
|
if (!props.data) {
|
||||||
<p>Search results go here</p>
|
return <div>Loading...</div>;
|
||||||
</div>
|
}
|
||||||
);
|
|
||||||
|
return (
|
||||||
|
<div className="search-results">
|
||||||
|
<ul>
|
||||||
|
{ props.data.map(interview => (
|
||||||
|
// eslint-disable-next-line
|
||||||
|
<li
|
||||||
|
id={interview.id}
|
||||||
|
key={interview.id}
|
||||||
|
onClick={props.toggleSingleInterview}
|
||||||
|
>
|
||||||
|
<h3>{ interview.name }</h3>
|
||||||
|
<h5>1) Question goes here</h5>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce hendrerit dolor quis
|
||||||
|
ante mollis fringilla. <span>Lorem</span> ipsum dolor sit amet, consectetur adipiscing
|
||||||
|
elit.
|
||||||
|
</p>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
SearchResults.propTypes = {
|
||||||
|
data: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
|
||||||
|
toggleSingleInterview: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
export default SearchResults;
|
export default SearchResults;
|
||||||
|
|
|
@ -2,4 +2,37 @@
|
||||||
|
|
||||||
.search-results {
|
.search-results {
|
||||||
|
|
||||||
|
li {
|
||||||
|
margin-bottom: calculateRem(32);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
font-size: calculateRem(18);
|
||||||
|
margin-bottom: calculateRem(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
font-size: calculateRem(16);
|
||||||
|
margin-bottom: calculateRem(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
font-size: calculateRem(14);
|
||||||
|
|
||||||
|
span {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: -10%;
|
||||||
|
left: -15%;
|
||||||
|
height: 120%;
|
||||||
|
width: 130%;
|
||||||
|
background-color: #efefef;
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,26 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { PropTypes } from 'prop-types';
|
||||||
import Data from '../../data/archives/topics';
|
import Data from '../../data/archives/topics';
|
||||||
import './style.scss';
|
import './style.scss';
|
||||||
|
|
||||||
export default () => (
|
const TopicsList = props => (
|
||||||
<div className="topics-list">
|
<div className="topics-list">
|
||||||
<h4>Topics</h4>
|
<h4>Topics</h4>
|
||||||
<ul>
|
<ul>
|
||||||
{
|
{
|
||||||
Data.map(topic => <li key={topic}><span>{ topic }</span></li>)
|
Data.map(topic => (
|
||||||
|
// eslint-disable-next-line
|
||||||
|
<li key={topic} onClick={props.setSearchTerm}>
|
||||||
|
<span>{ topic }</span>
|
||||||
|
</li>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TopicsList.propTypes = {
|
||||||
|
setSearchTerm: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default TopicsList;
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@zeit/next-sass": "^0.2.0",
|
"@zeit/next-sass": "^0.2.0",
|
||||||
"html-react-parser": "^0.4.5",
|
"html-react-parser": "^0.4.5",
|
||||||
|
"lodash": "^4.17.10",
|
||||||
"next": "^6.0.3",
|
"next": "^6.0.3",
|
||||||
"node-sass": "^4.9.0",
|
"node-sass": "^4.9.0",
|
||||||
"prop-types": "^15.6.1",
|
"prop-types": "^15.6.1",
|
||||||
|
|
Loading…
Reference in New Issue