working search bar
parent
5bff592068
commit
d1a33be5e1
|
@ -6878,6 +6878,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz",
|
||||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
|
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
|
||||||
},
|
},
|
||||||
|
"fuse.js": {
|
||||||
|
"version": "6.4.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-6.4.6.tgz",
|
||||||
|
"integrity": "sha512-/gYxR/0VpXmWSfZOIPS3rWwU8SHgsRTwWuXhyb2O6s7aRuVtHtxCkR33bNYu3wyLyNx/Wpv0vU7FZy8Vj53VNw=="
|
||||||
|
},
|
||||||
"gensync": {
|
"gensync": {
|
||||||
"version": "1.0.0-beta.2",
|
"version": "1.0.0-beta.2",
|
||||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
"@testing-library/user-event": "^12.8.3",
|
"@testing-library/user-event": "^12.8.3",
|
||||||
"axios": "^0.24.0",
|
"axios": "^0.24.0",
|
||||||
"express": "^4.17.1",
|
"express": "^4.17.1",
|
||||||
|
"fuse.js": "^6.4.6",
|
||||||
"jQuery": "^1.7.4",
|
"jQuery": "^1.7.4",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
|
|
91
src/App.js
91
src/App.js
|
@ -1,6 +1,8 @@
|
||||||
import React, { useState, useEffect, Component } from 'react';
|
import React, { useState, useEffect, Component } from 'react';
|
||||||
import LangDropdown from './components/LangDropdown';
|
import LangDropdown from './components/LangDropdown';
|
||||||
|
import SearchBar from './components/SearchBar';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import Fuse from 'fuse.js';
|
||||||
|
|
||||||
function makeBook(author, hLang, cLang, title, url)
|
function makeBook(author, hLang, cLang, title, url)
|
||||||
{
|
{
|
||||||
|
@ -87,11 +89,27 @@ class SubmitButton extends Component{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sorts search results by their score
|
||||||
|
function sortByScore(results){
|
||||||
|
results.sort(function(a,b){
|
||||||
|
return a.score - b.score;
|
||||||
|
});
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [ data, setData ] = useState(undefined);
|
const [ data, setData ] = useState(undefined);
|
||||||
const [ loading, setLoading ] = useState(true); //Determines whether to show spinner
|
const [ loading, setLoading ] = useState(true); //Determines whether to show spinner
|
||||||
|
const [ searchTerm, setSearchTerm ] = useState('');
|
||||||
|
const [ searchResults, setSearchResults ] = useState([]);
|
||||||
|
let resultsList = null; // the html string containing the search results
|
||||||
|
|
||||||
useEffect( // runs the first time the page renders
|
const setSearch = (term) => { // Lets a child set the value of the search term
|
||||||
|
setSearchTerm(term);
|
||||||
|
};
|
||||||
|
|
||||||
|
// fetches data the first time the page renders
|
||||||
|
useEffect(
|
||||||
() => {
|
() => {
|
||||||
async function fetchData() {
|
async function fetchData() {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
|
@ -104,24 +122,69 @@ function App() {
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
if(loading){ //still fetching resource
|
// fires when searchTerm changes
|
||||||
|
// THIS IS THE MAIN SEARCH FUNCTION CURRENTLY
|
||||||
|
useEffect(
|
||||||
|
() => {
|
||||||
|
if(data){
|
||||||
|
let result = [];
|
||||||
|
data.children[0].children.forEach( (document) => {
|
||||||
|
document.sections.forEach( (section) => {
|
||||||
|
const fuseOptions = {
|
||||||
|
findAllMatches: true,
|
||||||
|
shouldSort: false,
|
||||||
|
includeScore: true,
|
||||||
|
threshold: 0.3,
|
||||||
|
keys: ['title']
|
||||||
|
};
|
||||||
|
let fuse = new Fuse(section.entries, fuseOptions);
|
||||||
|
let fuseResult = fuse.search(searchTerm);
|
||||||
|
result = result.concat(fuseResult);
|
||||||
|
section.subsections.forEach( (subsection) => {
|
||||||
|
let fuse = new Fuse(subsection.entries, fuseOptions);
|
||||||
|
let fuseResult = fuse.search(searchTerm);
|
||||||
|
result = result.concat(fuseResult);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
result = sortByScore(result);
|
||||||
|
setSearchResults(result);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[ searchTerm ]
|
||||||
|
)
|
||||||
|
|
||||||
|
const buildList = () => {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
if(loading){ // if still fetching resource
|
||||||
return(
|
return(
|
||||||
<h1>Loading...</h1>
|
<h1>Loading...</h1>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else{ // resource fetched
|
if(searchTerm && searchResults.length !== 0){
|
||||||
console.log(data);
|
resultsList =
|
||||||
return(
|
searchResults &&
|
||||||
<div>
|
searchResults.map((entry) => {
|
||||||
<div id="frontPage">
|
return (<li><a href={entry.item.url}>{entry.item.title}</a></li>)
|
||||||
<h1>Free Programming Books</h1>
|
});
|
||||||
<input type="text"></input>
|
|
||||||
<LangDropdown data={data}/>
|
|
||||||
<SubmitButton/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
console.log(data);
|
||||||
|
return(
|
||||||
|
<div>
|
||||||
|
<div id="frontPage">
|
||||||
|
<h1>Free Programming Books</h1>
|
||||||
|
{/* <input type="text"></input> */}
|
||||||
|
<SearchBar setSearch={setSearch}/>
|
||||||
|
<LangDropdown data={data}/>
|
||||||
|
<SubmitButton/>
|
||||||
|
<ol>
|
||||||
|
{resultsList}
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@ function LangDropdown({ data }){
|
||||||
return(
|
return(
|
||||||
|
|
||||||
<select name="languages" id="languages">
|
<select name="languages" id="languages">
|
||||||
|
<option key="allLangs" value="allLangs">All Languages</option>
|
||||||
{options}
|
{options}
|
||||||
</select>
|
</select>
|
||||||
)
|
)
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
function SearchBar(props){
|
||||||
|
const handleChange = (e) => {
|
||||||
|
props.setSearch(e.target.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return(
|
||||||
|
<form
|
||||||
|
onSubmit={(e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
}}
|
||||||
|
name="searchBar"
|
||||||
|
>
|
||||||
|
<input autoComplete="off" type="text" name="searchTerm" onChange={handleChange} />
|
||||||
|
</form>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SearchBar;
|
Loading…
Reference in New Issue