Skip to content

Commit bc71c9f

Browse files
authored
Merge pull request #998 from WildMeOrg/916_header_quick_search
916 header quick search
2 parents de024d5 + 96d4d1e commit bc71c9f

File tree

19 files changed

+546
-14
lines changed

19 files changed

+546
-14
lines changed

frontend/src/components/AuthenticatedAppHeader.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import AvatarAndUserProfile from "./header/AvatarAndUserProfile";
88
import Menu from "./header/Menu";
99
import FooterVisibilityContext from "../FooterVisibilityContext";
1010
import Logo from "./svg/Logo";
11+
import HeaderQuickSearch from "./header/HeaderQuickSearch";
1112

1213
export default function AuthenticatedAppHeader({
1314
username,
@@ -37,7 +38,7 @@ export default function AuthenticatedAppHeader({
3738
className="container"
3839
style={{
3940
height: "50px",
40-
paddingLeft: "5%",
41+
paddingLeft: 0,
4142
paddingRight: "5%",
4243
}}
4344
>
@@ -60,7 +61,7 @@ export default function AuthenticatedAppHeader({
6061
href="/"
6162
>
6263
<Logo />
63-
{process.env.SITE_NAME}
64+
<span className="site-name">{process.env.SITE_NAME}</span>
6465
</Navbar.Brand>
6566
<Navbar.Toggle aria-controls="basic-navbar-nav" />
6667
<Navbar.Collapse id="basic-navbar-nav">
@@ -78,6 +79,7 @@ export default function AuthenticatedAppHeader({
7879
showClassicEncounterSearch={showClassicEncounterSearch}
7980
/>
8081
</Nav>
82+
<HeaderQuickSearch />
8183
<NotificationButton
8284
collaborationTitle={collaborationTitle}
8385
collaborationData={collaborationData}

frontend/src/components/header/AvatarAndUserProfile.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ export default function AvatarAndUserProfile({ avatar }) {
3030
};
3131

3232
return (
33-
<Nav style={{ alignItems: "center", marginLeft: "20px", width: 50 }}>
33+
<Nav style={{ alignItems: "center", marginLeft: "5px", width: 50 }}>
3434
<NavDropdown
3535
title={<Avatar avatar={avatar} />}
3636
id="basic-nav-dropdown"
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import React, { useState, useContext } from "react";
2+
import { Dropdown, FormControl, Spinner } from "react-bootstrap";
3+
import MainButton from "../MainButton";
4+
import { FormattedMessage } from "react-intl";
5+
import ThemeColorContext from "../../ThemeColorProvider";
6+
import usePostHeaderQuickSearch from "../../models/usePostHeaderQuickSearch";
7+
8+
export default function HeaderQuickSearch() {
9+
const [search, setSearch] = useState("");
10+
const [showDropdown, setShowDropdown] = useState(false);
11+
const theme = useContext(ThemeColorContext);
12+
13+
const { searchResults, loading } = usePostHeaderQuickSearch(search);
14+
15+
const handleInputChange = (e) => {
16+
setSearch(e.target.value);
17+
};
18+
19+
const handleClearSearch = () => {
20+
setSearch(""); //
21+
setShowDropdown(false);
22+
};
23+
24+
return (
25+
<div className="header-quick-search">
26+
<Dropdown show={showDropdown} onBlur={() => setShowDropdown(false)}>
27+
<div className="d-flex">
28+
<FormControl
29+
type="text"
30+
placeholder="Search Individuals"
31+
value={search}
32+
onChange={handleInputChange}
33+
onFocus={() => setShowDropdown(true)}
34+
style={{
35+
height: "35px",
36+
width: "150px",
37+
paddingLeft: "10px",
38+
backgroundColor: "transparent",
39+
border: "1px solid white",
40+
borderRadius: "20px 0px 0px 20px",
41+
color: "white",
42+
borderRight: "none",
43+
}}
44+
className="header-quick-search-input"
45+
/>
46+
<button
47+
className="header-quick-search-button"
48+
style={{
49+
height: "35px",
50+
backgroundColor: "transparent",
51+
border: "1px solid white",
52+
borderRadius: "0px 20px 20px 0px",
53+
color: "white",
54+
borderLeft: "none",
55+
}}
56+
onClick={handleClearSearch}
57+
>
58+
<i className="bi bi-x"></i>
59+
</button>
60+
</div>
61+
62+
<Dropdown.Menu
63+
style={{
64+
width: "300px",
65+
marginTop: "10px",
66+
overflow: "auto",
67+
maxHeight: "400px",
68+
minHeight: "100px",
69+
}}
70+
>
71+
{loading && (
72+
<Dropdown.Item className="text-center">
73+
<Spinner animation="border" size="sm" />
74+
<span className="ms-2">
75+
<FormattedMessage id="LOADING" />
76+
</span>
77+
</Dropdown.Item>
78+
)}
79+
{!loading && searchResults.length === 0 && search.trim() === "" && (
80+
<Dropdown.Item>
81+
<FormattedMessage id="SEARCH_RESULT_DISPLAY" />
82+
</Dropdown.Item>
83+
)}
84+
{!loading && searchResults.length === 0 && search.trim() !== "" && (
85+
<Dropdown.Item>
86+
<FormattedMessage id="NO_MATCHING_RESULTS" />
87+
</Dropdown.Item>
88+
)}
89+
{!loading &&
90+
searchResults.map((result, index) => (
91+
<React.Fragment key={index}>
92+
<Dropdown.Item
93+
key={index}
94+
as="button"
95+
target="_blank"
96+
rel="noopener noreferrer"
97+
onMouseDown={(e) => {
98+
e.preventDefault();
99+
window.open(`/individuals.jsp?id=${result.id}`);
100+
}}
101+
>
102+
<div className="d-flex flex-row justify-content-between">
103+
<div
104+
className="individual-name"
105+
style={{
106+
width: "180px",
107+
fontSize: "0.8rem",
108+
overflow: "hidden",
109+
}}
110+
>
111+
<div>{search}</div>
112+
<div>{result.taxonomy}</div>
113+
</div>
114+
<MainButton
115+
noArrow={true}
116+
style={{
117+
width: "80px",
118+
height: "30px",
119+
color: "white",
120+
fontSize: "0.8rem",
121+
marginRight: 0,
122+
}}
123+
backgroundColor={theme.primaryColors.primary500}
124+
>
125+
<FormattedMessage
126+
id={
127+
result?.id
128+
?.toLowerCase()
129+
.includes(search.toLowerCase())
130+
? "SYSTEM_ID"
131+
: result?.names?.some((name) =>
132+
name
133+
.toLowerCase()
134+
.includes(search.toLowerCase()),
135+
)
136+
? "FILTER_NAME"
137+
: "UNKNOWN"
138+
}
139+
/>
140+
</MainButton>
141+
</div>
142+
{index < searchResults.length - 1 && <Dropdown.Divider />}
143+
</Dropdown.Item>
144+
</React.Fragment>
145+
))}
146+
</Dropdown.Menu>
147+
</Dropdown>
148+
</div>
149+
);
150+
}

frontend/src/components/header/Menu.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,8 @@ export default function Menu({
4343
style={{
4444
color: "white",
4545
boxSizing: "border-box",
46-
paddingLeft: 5,
47-
paddingRight: 5,
46+
paddingLeft: 2,
47+
paddingRight: 2,
4848
borderBottom:
4949
dropdownBorder[`dropdown${idx + 1}`] || "2px solid transparent",
5050
}}

frontend/src/components/navBar/NotificationButton.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ const NotificationButton = ({
2020
style={{
2121
width: "35px",
2222
height: "35px",
23-
marginLeft: "20px",
23+
marginLeft: "5px",
2424
position: "relative",
2525
}}
2626
tabIndex={0}

frontend/src/css/dropdown.css

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,16 @@
7171

7272
.nav-item>a {
7373
padding: 0.5rem 1rem;
74+
}
75+
76+
@media (max-width: 1100px) {
77+
.site-name {
78+
display: none !important;
79+
}
80+
}
81+
82+
.header-quick-search-input::placeholder {
83+
color: gray;
84+
opacity: 0.6;
85+
font-size: 0.9rem;
7486
}

frontend/src/locale/de.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -359,5 +359,10 @@
359359
"BEARING": "Peilung",
360360
"DISTANCE": "Entfernung",
361361
"FILTER_BIRTH" : "Geburt",
362-
"FILTER_DEATH" : "Tod"
363-
}
362+
"FILTER_DEATH" : "Tod",
363+
"NO_MATCHING_RESULTS": "Keine passenden Ergebnisse",
364+
"SYSTEM_ID": "System-ID",
365+
"SEARCH_INDIVIDUALS": "Individuen suchen",
366+
"SEARCH_RESULT_DISPLAY" : "Ihre Suchergebnisse werden hier angezeigt.",
367+
"UNKNOWN" : "Unbekannt"
368+
}

frontend/src/locale/en.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,5 +359,11 @@
359359
"BEARING" : "Bearing",
360360
"DISTANCE" : "Distance",
361361
"FILTER_BIRTH" : "Birth",
362-
"FILTER_DEATH" : "Death"
362+
"FILTER_DEATH" : "Death",
363+
"NO_MATCHING_RESULTS": "No matching results",
364+
"SYSTEM_ID": "System ID",
365+
"SEARCH_INDIVIDUALS": "Search Individuals",
366+
"SEARCH_RESULT_DISPLAY" : "Your search results will appear here",
367+
"UNKNOWN" : "Unknown"
368+
363369
}

frontend/src/locale/es.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,5 +358,10 @@
358358
"BEARING": "Rumbo",
359359
"DISTANCE": "Distancia",
360360
"FILTER_BIRTH" : "Nacimiento",
361-
"FILTER_DEATH" : "Muerte"
361+
"FILTER_DEATH" : "Muerte",
362+
"NO_MATCHING_RESULTS": "No hay resultados coincidentes",
363+
"SYSTEM_ID": "ID del Sistema",
364+
"SEARCH_INDIVIDUALS": "Buscar Individuos",
365+
"SEARCH_RESULT_DISPLAY": "Tus resultados de búsqueda aparecerán aquí.",
366+
"UNKNOWN" : "Desconocido"
362367
}

frontend/src/locale/fr.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -358,5 +358,10 @@
358358
"BEARING": "Cap",
359359
"DISTANCE": "Distance",
360360
"FILTER_BIRTH" : "Naissance",
361-
"FILTER_DEATH" : "Décès"
361+
"FILTER_DEATH" : "Décès",
362+
"NO_MATCHING_RESULTS": "Aucun résultat correspondant",
363+
"SYSTEM_ID": "ID du Système",
364+
"SEARCH_INDIVIDUALS": "Rechercher des Individus",
365+
"SEARCH_RESULT_DISPLAY": "Vos résultats de recherche apparaîtront ici",
366+
"UNKNOWN" : "Inconnu"
362367
}

0 commit comments

Comments
 (0)