Implement search results for users
Diff
chartered-frontend/src/index.sass | 8 ++++++++
chartered-frontend/src/index.tsx | 6 ++++++
chartered-frontend/src/util.tsx | 3 ++-
chartered-frontend/src/pages/Search.tsx | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
chartered-frontend/src/sections/Nav.tsx | 40 ++++++++++++++++++++++++++++++++++++++--
5 files changed, 123 insertions(+), 9 deletions(-)
@@ -42,3 +42,11 @@
&::after
content: ""
border-top: 1px solid
.navbar .form-control
transition: width 0.5s ease-in-out
width: 250px
&:focus, &:not(:placeholder-shown)
width: 350px
@@ -23,6 +23,7 @@
import OrganisationView from "./pages/crate/OrganisationView";
import CreateOrganisation from "./pages/organisations/CreateOrganisation";
import User from "./pages/User";
import Search from "./pages/Search";
function App() {
return (
@@ -92,6 +93,11 @@
exact
path="/organisations/create"
component={() => <CreateOrganisation />}
/>
<PrivateRoute
exact
path="/search"
component={() => <Search />}
/>
</Switch>
</Router>
@@ -24,6 +24,7 @@
React.useEffect(async () => {
try {
setResponse(null);
let res = await fetch(authenticatedEndpoint(auth, endpoint));
if (res.status == 401) {
@@ -94,7 +95,7 @@
} else {
return (
<div
className={`rounded-circle ${className}`}
className={`rounded-circle d-inline-block ${className}`}
style={{ width, height, background: "rgb(235, 235, 235)" }}
/>
);
@@ -1,0 +1,75 @@
import React = require("react");
import { useState, useEffect } from "react";
import { Link, useHistory, useLocation } from "react-router-dom";
import Nav from "../sections/Nav";
import { useAuth } from "../useAuth";
import { authenticatedEndpoint, ProfilePicture, useAuthenticatedRequest } from "../util";
import { Plus } from "react-bootstrap-icons";
import { LoadingSpinner } from "./Loading";
interface UsersSearchResponse {
users: UserSearchResponseUser[];
}
interface UserSearchResponseUser {
user_uuid: string;
display_name: string;
picture_url: string;
}
export default function Search() {
const auth = useAuth();
const location = useLocation();
const query = location.pathname === '/search'
? new URLSearchParams(location.search).get("q") || ""
: "";
return (
<div className="text-white">
<Nav />
<div className="container mt-4 pb-4">
<h1>Search Results {query ? <>for '{query}'</> : <></>}</h1>
<UsersResults query={query} />
</div>
</div>
);
}
function UsersResults({ query }: { query: string }) {
const auth = useAuth();
const { response: results, error } =
useAuthenticatedRequest<UsersSearchResponse>({
auth,
endpoint: "users/search?q=" + encodeURIComponent(query),
}, [query]);
if (!results) {
return <div className="card border-0 shadow-sm text-black p-2">
<div className="card-body">
{[0, 1, 2].map((i) => (
<ProfilePicture key={i} height="5rem" width="5rem" className="me-2" src={undefined} />
))}
</div>
</div>
}
if (results?.users.length === 0) {
return <></>;
}
return <div className="card border-0 shadow-sm text-black p-2">
<div className="card-body">
{results.users.map((user, i) => (
<Link to={`users/${user.user_uuid}`}>
<ProfilePicture key={i} height="5rem" width="5rem" className="me-2" src={user.picture_url} />
</Link>
))}
</div>
</div>;
}
@@ -1,17 +1,33 @@
import React = require("react");
import { useHistory, useLocation } from "react-router-dom";
import { NavLink, Link } from "react-router-dom";
import { BoxArrowRight } from "react-bootstrap-icons";
import { BoxArrowRight, Search } from "react-bootstrap-icons";
import { useAuth } from "../useAuth";
export default function Nav() {
const auth = useAuth();
const history = useHistory();
const location = useLocation();
const logout = async (e) => {
e.preventDefault();
await auth.logout();
};
const [search, setSearch] = React.useState(
location.pathname === '/search'
? new URLSearchParams(location.search).get("q") || ""
: ""
);
const submitSearchForm = (e) => {
e.preventDefault();
if (search != "") {
history.push(`/search?q=${encodeURIComponent(search)}`)
}
};
return (
<nav className="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div className="container-fluid">
@@ -48,14 +64,22 @@
</NavLink>
</li>
</ul>
<form className="d-flex" onSubmit={submitSearchForm}>
<div className="input-group">
<span className="input-group-text bg-transparent border-none">
<Search />
</span>
<form className="d-flex">
<input
className="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
/>
<input
className="form-control me-2"
type="search"
placeholder="Search"
aria-label="Search"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
</div>
</form>
<div>