Skip to content

Commit de024d5

Browse files
authored
Merge pull request #992 from WildMeOrg/all_filters_encounter_search
All filters encounter search
2 parents aae82a2 + 1bd2631 commit de024d5

25 files changed

+876
-182
lines changed

frontend/src/components/Chip.jsx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,13 @@ function Chip({ children }) {
115115
}
116116
}
117117

118+
if (query?.geo_distance) {
119+
const { occurrenceLocationGeoPoint, distance } = query.geo_distance;
120+
entries.push(
121+
`Location within ${distance} km of latitude: ${occurrenceLocationGeoPoint.lat}, longitude: ${occurrenceLocationGeoPoint.lon}`,
122+
);
123+
}
124+
118125
return entries.length > 0 ? `${entries.join(", ")}` : `No filters set`;
119126
}
120127

frontend/src/components/FilterPanel.jsx

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -146,40 +146,48 @@ export default function FilterPanel({
146146
}}
147147
>
148148
{safeSchemas.map((schema, index) => {
149-
return (
150-
<div
151-
key={index}
152-
className={`d-flex justify-content-between align-items-center rounded-3 p-2 mt-2 ${clicked === schema.id ? "bg-white" : "text-white"} cursor-pointer`}
153-
style={{
154-
color:
155-
clicked === schema.id
156-
? theme.primaryColors.primary700
157-
: "white",
158-
minHeight: "50px",
159-
cursor: "pointer",
160-
}}
161-
onClick={() => {
162-
setClicked(schema.id);
163-
handleClick(schema.id);
164-
}}
165-
>
166-
<Text
167-
id={schema.labelId}
168-
className="m-3"
149+
if (schema.FilterComponent) {
150+
return (
151+
<div
152+
key={index}
153+
className={`d-flex justify-content-between ms-4 align-items-center rounded-3 p-2 ${clicked === schema.id ? "bg-white" : "text-white"} cursor-pointer`}
169154
style={{
170-
fontWeight: "500",
171-
marginRight: "20px",
155+
color:
156+
clicked === schema.id
157+
? theme.primaryColors.primary700
158+
: "white",
159+
minHeight: "50px",
160+
cursor: "pointer",
172161
}}
173-
></Text>
174-
<span>
175-
{" "}
176-
<i
177-
className="bi bi-chevron-right"
178-
style={{ fontSize: "14px" }}
179-
></i>{" "}
180-
</span>
181-
</div>
182-
);
162+
onClick={() => {
163+
setClicked(schema.id);
164+
handleClick(schema.id);
165+
}}
166+
>
167+
<Text
168+
id={schema.labelId}
169+
className="m-3"
170+
style={{
171+
fontWeight: "500",
172+
marginRight: "20px",
173+
}}
174+
></Text>
175+
<span>
176+
{" "}
177+
<i
178+
className="bi bi-chevron-right"
179+
style={{ fontSize: "14px" }}
180+
></i>{" "}
181+
</span>
182+
</div>
183+
);
184+
} else {
185+
return (
186+
<div className="mt-2 mb-2" key={index}>
187+
{schema.id}
188+
</div>
189+
);
190+
}
183191
})}
184192
<div className="mt-2 d-flex flex-wrap justify-content-center align-items-center w-100 gap-3">
185193
<BrutalismButton
@@ -259,17 +267,25 @@ export default function FilterPanel({
259267
key={index}
260268
ref={schemaRefs.current[index]}
261269
>
262-
<schema.FilterComponent
263-
key={schema.id}
264-
labelId={schema.labelId}
265-
onChange={handleFilterChange}
266-
onClearFilter={clearFilter}
267-
{...schema.filterComponentProps}
268-
data={data}
269-
tempFormFilters={tempFormFilters}
270-
setFormFilters={setFormFilters}
271-
formFilters={formFilters}
272-
/>
270+
{schema.FilterComponent ? (
271+
<schema.FilterComponent
272+
key={schema.id}
273+
labelId={schema.labelId}
274+
onChange={handleFilterChange}
275+
onClearFilter={clearFilter}
276+
{...schema.filterComponentProps}
277+
data={data}
278+
tempFormFilters={tempFormFilters}
279+
setFormFilters={setFormFilters}
280+
formFilters={formFilters}
281+
/>
282+
) : (
283+
<div>
284+
<h2>
285+
<FormattedMessage id={schema.labelId} />
286+
</h2>
287+
</div>
288+
)}
273289
</div>
274290
);
275291
})}

frontend/src/components/filterFields/ApplyQueryFilter.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ export default function ApplyQueryFilter() {
1010
const [queryId, setQueryId] = React.useState("");
1111
return (
1212
<div>
13-
<h3>
13+
<h4>
1414
<FormattedMessage id="APPLY_SEARCH_ID" />
15-
</h3>
15+
</h4>
1616
{/* <Description>
1717
<FormattedMessage id="FILTER_METADATA_DESC" />
1818
</Description> */}

frontend/src/components/filterFields/BiologicalSamplesAndAnalysesFilter.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,9 +111,9 @@ export default function BiologicalSamplesAndAnalysesFilter({ onChange, data }) {
111111

112112
return (
113113
<div>
114-
<h3>
114+
<h4>
115115
<FormattedMessage id="FILTER_BIOLOGICAL_SAMPLE" />
116-
</h3>
116+
</h4>
117117
<Description>
118118
<FormattedMessage id="FILTER_BIOLOGICAL_SAMPLE_DESC" />
119119
</Description>

frontend/src/components/filterFields/DateFilter.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,15 +86,15 @@ export default function DateFilter({ onChange, data }) {
8686

8787
return (
8888
<div>
89-
<h3>
89+
<h4>
9090
<FormattedMessage id="FILTER_DATE" />
91-
</h3>
91+
</h4>
9292
<Description>
9393
<FormattedMessage id="FILTER_DATE_DESC" />
9494
</Description>
9595
<>
9696
<FormLabel>
97-
<FormattedMessage id="FILTER_SIGHTING_DATE" />
97+
<FormattedMessage id="FILTER_ENCOUNTER_DATE" />
9898
</FormLabel>
9999
<div className="d-flex flex-row w-100 mb-2">
100100
<FormGroup className="w-50" style={{ marginRight: "10px" }}>

frontend/src/components/filterFields/IdentityFilter.jsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,9 @@ export default function IdentityFilter({ onChange }) {
1515

1616
return (
1717
<div>
18-
<h3>
18+
<h4>
1919
<FormattedMessage id="FILTER_IDENTITY" />
20-
</h3>
20+
</h4>
2121
<Description>
2222
<FormattedMessage id="FILTER_IDENTITY_DESC" />
2323
</Description>
@@ -100,6 +100,15 @@ export default function IdentityFilter({ onChange }) {
100100
}}
101101
/>
102102
</Form>
103+
<FormGroupText
104+
label="FILTER_NUMBER_REPORTED_MARKED_INDIVIDUALS"
105+
noDesc={true}
106+
field={"occurrenceIndividualCount"}
107+
term={"match"}
108+
filterId={"occurrenceIndividualCount"}
109+
onChange={onChange}
110+
filterKey={"Number of Reported Marked Individuals"}
111+
/>
103112
<FormGroupText
104113
label="FILTER_ALTERNATIVE_ID"
105114
noDesc={true}

frontend/src/components/filterFields/ImageLabelFilter.jsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,9 @@ export default function ImageLabelFilter({ data, onChange }) {
5858

5959
return (
6060
<div>
61-
<h3>
61+
<h4>
6262
<FormattedMessage id="FILTER_IMAGE_LABEL" />
63-
</h3>
63+
</h4>
6464
<Description>
6565
<FormattedMessage id="FILTER_IMAGE_LABEL_DESC" />
6666
</Description>
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import React, { useState } from "react";
2+
import { FormattedMessage } from "react-intl";
3+
import Description from "../Form/Description";
4+
import { FormGroup, FormControl } from "react-bootstrap";
5+
6+
export default function IndividualDateFilter({ onChange }) {
7+
const [birthDate, setBirthDate] = useState("");
8+
const [deathDate, setDeathDate] = useState("");
9+
10+
return (
11+
<div>
12+
<h4>
13+
<FormattedMessage id="FILTER_DATE" />
14+
</h4>
15+
<Description>
16+
<FormattedMessage id="FILTER_DATE_DESC" />
17+
</Description>
18+
<>
19+
<FormGroup className="w-100" style={{ marginRight: "10px" }}>
20+
<p>
21+
<FormattedMessage id="FILTER_BIRTH" defaultMessage="Birth" />
22+
</p>
23+
<FormControl
24+
type="date"
25+
value={birthDate}
26+
onChange={(e) => {
27+
setBirthDate(e.target.value);
28+
onChange({
29+
filterId: "individualTimeOfBirth",
30+
filterKey: "Birth Date",
31+
clause: "filter",
32+
query: {
33+
range: {
34+
individualTimeOfBirth: {
35+
gte: `${e.target.value}T00:00:00.000Z`,
36+
lte: `${e.target.value}T23:59:59.000Z`,
37+
},
38+
},
39+
},
40+
});
41+
}}
42+
/>
43+
</FormGroup>
44+
<FormGroup className="w-100" style={{ marginRight: "10px" }}>
45+
<p>
46+
<FormattedMessage id="FILTER_DEATH" defaultMessage="Death" />
47+
</p>
48+
<FormControl
49+
type="date"
50+
value={deathDate}
51+
onChange={(e) => {
52+
setDeathDate(e.target.value);
53+
onChange({
54+
filterId: "individualTimeOfDeath",
55+
filterKey: "Death Date",
56+
clause: "filter",
57+
query: {
58+
range: {
59+
individualTimeOfDeath: {
60+
gte: `${e.target.value}T00:00:00.000Z`,
61+
lte: `${e.target.value}T23:59:59.000Z`,
62+
},
63+
},
64+
},
65+
});
66+
}}
67+
/>
68+
</FormGroup>
69+
</>
70+
</div>
71+
);
72+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import React from "react";
2+
import { FormattedMessage } from "react-intl";
3+
import Description from "../Form/Description";
4+
import FormGroupText from "../Form/FormGroupText";
5+
6+
export default function IndividualEstimateFilter({ onChange }) {
7+
return (
8+
<div>
9+
<h4>
10+
<FormattedMessage id="FILTER_INDIVIDUAL_ESTIMATE" />
11+
</h4>
12+
<Description>
13+
<FormattedMessage id="FILTER_INDIVIDUAL_ESTIMATE_DESC" />
14+
</Description>
15+
16+
<FormGroupText
17+
label="FILTER_BEST_ESTIMATE_INDIVIDUALS"
18+
noDesc={true}
19+
field={"occurrenceBestGroupSizeEstimate"}
20+
term={"match"}
21+
filterId={"occurrenceBestGroupSizeEstimate"}
22+
onChange={onChange}
23+
filterKey={"Best Estimate Individuals"}
24+
/>
25+
<FormGroupText
26+
label="FILTER_MINIMUM_ESTIMATE_INDIVIDUALS"
27+
noDesc={true}
28+
field={"occurrenceMinGroupSizeEstimate"}
29+
term={"match"}
30+
filterId={"occurrenceMinGroupSizeEstimate"}
31+
onChange={onChange}
32+
filterKey={"Minimum Estimate Individuals"}
33+
/>
34+
<FormGroupText
35+
label="FILTER_MAXIMUM_ESTIMATE_INDIVIDUALS"
36+
noDesc={true}
37+
field={"occurrenceMaxGroupSizeEstimate"}
38+
term={"match"}
39+
filterId={"occurrenceMaxGroupSizeEstimate"}
40+
onChange={onChange}
41+
filterKey={"Maximum Estimate Individuals"}
42+
/>
43+
</div>
44+
);
45+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import React from "react";
2+
import Description from "../Form/Description";
3+
import { FormattedMessage } from "react-intl";
4+
import FormGroupMultiSelect from "../Form/FormGroupMultiSelect";
5+
6+
export default function ObservationAttributeFilter({ onChange, data }) {
7+
const sexOptions =
8+
data?.sex?.map((item) => {
9+
return {
10+
value: item,
11+
label: item,
12+
};
13+
}) || [];
14+
15+
const genusAndSpeciesOptions =
16+
data?.siteTaxonomies?.map((item) => {
17+
return {
18+
value: item?.scientificName,
19+
label: item?.scientificName,
20+
};
21+
}) || [];
22+
23+
return (
24+
<div
25+
style={{
26+
overflow: "visible",
27+
}}
28+
>
29+
<h4>
30+
<FormattedMessage id="FILTER_OBSERVATION_ATTRIBUTE" />
31+
</h4>
32+
<Description>
33+
<FormattedMessage id="FILTER_OBSERVATION_ATTRIBUTE_DESC" />
34+
</Description>
35+
<FormGroupMultiSelect
36+
isMulti={true}
37+
noDesc={true}
38+
label="FILTER_INDIVIDUAL_SEX"
39+
options={sexOptions}
40+
onChange={onChange}
41+
field="individualSex"
42+
term="terms"
43+
filterKey="individualSex"
44+
/>
45+
<FormGroupMultiSelect
46+
isMulti={true}
47+
label="FILTER_INDIVIDUAL_TAXONOMY"
48+
noDesc={true}
49+
options={genusAndSpeciesOptions}
50+
onChange={onChange}
51+
field="individualTaxonomy"
52+
term="terms"
53+
filterId={"individualTaxonomy"}
54+
filterKey={"Individual Taxonomy"}
55+
/>
56+
</div>
57+
);
58+
}

0 commit comments

Comments
 (0)