working search bar

pull/6/head
nrfq 2021-11-19 15:21:57 -05:00
parent 5bff592068
commit d1a33be5e1
5 changed files with 104 additions and 14 deletions

5
package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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,25 +122,70 @@ 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){
resultsList =
searchResults &&
searchResults.map((entry) => {
return (<li><a href={entry.item.url}>{entry.item.title}</a></li>)
});
}
console.log(data); console.log(data);
return( return(
<div> <div>
<div id="frontPage"> <div id="frontPage">
<h1>Free Programming Books</h1> <h1>Free Programming Books</h1>
<input type="text"></input> {/* <input type="text"></input> */}
<SearchBar setSearch={setSearch}/>
<LangDropdown data={data}/> <LangDropdown data={data}/>
<SubmitButton/> <SubmitButton/>
<ol>
{resultsList}
</ol>
</div> </div>
</div> </div>
); );
} }
}
export default App; export default App;

View File

@ -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>
) )

View File

@ -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;