Merge pull request #99 from ClaytonWWilson/improve-search

Improved speed of search and made it fuzzy search
This commit is contained in:
Clayton Wilson 2019-12-03 13:19:53 -05:00 committed by GitHub
commit f7058a520d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 50 deletions

View File

@ -331,6 +331,24 @@ exports.getUserDetails = (req, res) => {
}); });
}; };
exports.getAllHandles = (req, res) => {
var user_query = admin.firestore().collection("users");
user_query.get()
.then((allUsers) => {
let users = [];
allUsers.forEach((user) => {
users.push(user.data().handle);
});
return res.status(200).json(users);
})
.catch((err) => {
return res.status(500).json({
message:"Failed to retrieve posts from database.",
error: err
});
});
};
exports.getAuthenticatedUser = (req, res) => { exports.getAuthenticatedUser = (req, res) => {
let credentials = {}; let credentials = {};
db.doc(`/users/${req.user.handle}`) db.doc(`/users/${req.user.handle}`)

View File

@ -11,6 +11,7 @@ app.use(cors());
*------------------------------------------------------------------*/ *------------------------------------------------------------------*/
const { const {
getAuthenticatedUser, getAuthenticatedUser,
getAllHandles,
getUserDetails, getUserDetails,
getProfileInfo, getProfileInfo,
login, login,
@ -39,6 +40,10 @@ app.delete("/delete", fbAuth, deleteUser);
app.post("/getUserDetails", fbAuth, getUserDetails); app.post("/getUserDetails", fbAuth, getUserDetails);
// Returns a list of all usernames
// Used for searching
app.get("/getAllHandles", fbAuth, getAllHandles);
// Returns all profile data of the currently logged in user // Returns all profile data of the currently logged in user
app.get("/getProfileInfo", fbAuth, getProfileInfo); app.get("/getProfileInfo", fbAuth, getProfileInfo);

View File

@ -10,11 +10,13 @@
"axios": "^0.19.0", "axios": "^0.19.0",
"clsx": "^1.0.4", "clsx": "^1.0.4",
"create-react-app": "^3.1.2", "create-react-app": "^3.1.2",
"fuse.js": "^3.4.6",
"install": "^0.13.0", "install": "^0.13.0",
"jwt-decode": "^2.2.0", "jwt-decode": "^2.2.0",
"node-pre-gyp": "^0.13.0", "node-pre-gyp": "^0.13.0",
"react": "^16.9.0", "react": "^16.9.0",
"react-dom": "^16.9.0", "react-dom": "^16.9.0",
"react-modal": "^3.11.1",
"react-redux": "^7.1.1", "react-redux": "^7.1.1",
"react-router-dom": "^5.1.0", "react-router-dom": "^5.1.0",
"react-scripts": "0.9.5", "react-scripts": "0.9.5",

View File

@ -2,38 +2,75 @@ import React, { Component } from "react";
// import props // import props
import { TextField, Button } from "@material-ui/core"; import { TextField, Button } from "@material-ui/core";
import Grid from "@material-ui/core/Grid"; import Grid from "@material-ui/core/Grid";
import Axios from "axios"; import axios from "axios";
import Fuse from "fuse.js";
import { BrowserRouter as Router } from "react-router-dom"; import { BrowserRouter as Router } from "react-router-dom";
import CircularProgress from "@material-ui/core/CircularProgress";
const fuseOptions = {
shouldSort: true,
threshold: 0.6,
location: 0,
distance: 100,
maxPatternLength: 32,
minMatchCharLength: 1,
keys: []
};
let fuse;
export class Search extends Component { export class Search extends Component {
state = { state = {
searchPhase: null, handles: [],
searchResult: null // searchPhrase: null,
searchResult: null,
loading: false
}; };
handleSearch = () => { componentDidMount() {
console.log(this.state.searchPhase); this.setState({loading: true});
Axios.post("/getUserHandles", { axios.get("/getAllHandles")
userHandle: this.state.searchPhase .then((res) => {
})
.then(res => {
console.log(res);
this.setState({ this.setState({
searchResult: res.data handles: res.data,
}); loading: false
}, () => {
console.log(res.data);
fuse = new Fuse(this.state.handles, fuseOptions); // "list" is the item array
}) })
.catch(err => { })
console.log(err); }
});
};
handleInput(event) { // handleSearch = () => {
// console.log(this.state.searchPhase);
// axios.post("/getUserHandles", {
// userHandle: this.state.searchPhase
// })
// .then(res => {
// console.log(res);
// this.setState({
// searchResult: res.data
// });
// })
// .catch(err => {
// console.log(err);
// });
// };
handleChange = (event) => {
let result = fuse.search(event.target.value);
let parsed = [];
result.forEach((res) => {
console.log(res)
parsed.push(this.state.handles[res])
})
this.setState({ this.setState({
searchPhase: event.target.value searchResult: parsed.length !== 0 ? parsed : "No Results"
}); })
console.log(this.state.searchPhase);
} }
handleRedirect() { handleRedirect() {
@ -41,35 +78,46 @@ export class Search extends Component {
} }
render() { render() {
let resultMarkup = this.state.searchResult ? ( let resultMarkup = this.state.searchResult && this.state.searchResult !== "No Results" ? (
this.state.searchResult.map(res =>
<Router> <Router>
<div> <div>
<a href={`/user/${this.state.searchResult}`}> <a href={`/user/${res}`}>
{this.state.searchResult} {res}
</a> </a>
</div> </div>
</Router> </Router>
) : ( )
// console.log(this.state.searchResult) )
<p> No result </p> :
); this.state.searchResult === "No Results" ?
(
<p> No results </p>
)
:
(
null
)
return ( return (
this.state.loading
?
<CircularProgress size={60} style={{marginTop: "300px"}}></CircularProgress>
:
<Grid> <Grid>
<Grid> <Grid>
<TextField <TextField
id="standard-required" id="standard-required"
label="Search" label="Username"
defaultValue="username"
margin="normal" margin="normal"
value={this.state.searchPhase} // value={this.state.searchPhrase}
onChange={event => this.handleInput(event)} onChange={this.handleChange}
/> />
</Grid> </Grid>
<Grid> <Grid>
<Button color="primary" onClick={this.handleSearch}> {/* <Button color="primary" onClick={this.handleSearch}>
Search Search
</Button> </Button> */}
</Grid> </Grid>
<Grid>{resultMarkup}</Grid> <Grid>{resultMarkup}</Grid>
</Grid> </Grid>