Skip to content

Commit bf3214f

Browse files
committed
2927: Refactored poster single component
1 parent 05f9ce3 commit bf3214f

File tree

3 files changed

+341
-319
lines changed

3 files changed

+341
-319
lines changed

src/components/slide/content/poster/poster-helper.js

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -80,41 +80,10 @@ const getHeaders = () => {
8080
return headers;
8181
};
8282

83-
const getSingleSearchOptions = (t) => {
84-
return [
85-
{
86-
key: "singleSearchTypeOptions1",
87-
value: "title",
88-
title: t("single-search-type-title"),
89-
},
90-
{
91-
key: "singleSearchTypeOptions2",
92-
value: "url",
93-
title: t("single-search-type-url"),
94-
},
95-
{
96-
key: "singleSearchTypeOptions3",
97-
value: "organizations",
98-
title: t("single-search-type-organization"),
99-
},
100-
{
101-
key: "singleSearchTypeOptions4",
102-
value: "locations",
103-
title: t("single-search-type-location"),
104-
},
105-
{
106-
key: "singleSearchTypeOptions5",
107-
value: "tags",
108-
title: t("single-search-type-tag"),
109-
},
110-
];
111-
};
112-
11383
export {
11484
formatDate,
11585
capitalize,
11686
loadDropdownOptions,
11787
getHeaders,
11888
loadDropdownOptionsPromise,
119-
getSingleSearchOptions,
12089
};
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
1+
import { React, useEffect, useRef, useState } from "react";
2+
import { Button, Row } from "react-bootstrap";
3+
import Col from "react-bootstrap/Col";
4+
import AsyncSelect from "react-select/async";
5+
import { useTranslation } from "react-i18next";
6+
import PropTypes from "prop-types";
7+
import FormInput from "../../../util/forms/form-input";
8+
import Select from "../../../util/forms/select";
9+
import { getHeaders, loadDropdownOptionsPromise } from "./poster-helper";
10+
11+
/**
12+
* @param {object} props The props.
13+
* @param {string} props.searchEndpoint The search endpoint.
14+
* @param {string} props.optionsEndpoint The options endpoint
15+
* @param {Function} props.setLoading Set loading status.
16+
* @param {Function} props.setResult Set results of search.
17+
* @returns {React.JSX.Element} The search component.
18+
*/
19+
function PosterSingleSearch({
20+
searchEndpoint,
21+
optionsEndpoint,
22+
setLoading,
23+
setResult,
24+
}) {
25+
const { t } = useTranslation("common", { keyPrefix: "poster-selector-v2" });
26+
27+
const [singleSearch, setSingleSearch] = useState("");
28+
const [singleSearchType, setSingleSearchType] = useState("title");
29+
const [singleSearchTypeValue, setSingleSearchTypeValue] = useState("");
30+
31+
const timeoutRef = useRef(null);
32+
33+
const debounceOptions = (inputValue) => {
34+
// Debounce result to avoid searching while typing.
35+
return new Promise((resolve, reject) => {
36+
if (timeoutRef.current) {
37+
clearTimeout(timeoutRef.current);
38+
}
39+
40+
timeoutRef.current = setTimeout(() => {
41+
loadDropdownOptionsPromise(
42+
optionsEndpoint,
43+
getHeaders(),
44+
inputValue,
45+
singleSearchType
46+
)
47+
.then((data) => resolve(data))
48+
.catch((reason) => reject(reason));
49+
}, 500);
50+
});
51+
};
52+
53+
const singleSearchFetch = () => {
54+
const params = {
55+
type: "events",
56+
};
57+
58+
const singleSearchTypeValueId = singleSearchTypeValue?.value;
59+
60+
switch (singleSearchType) {
61+
case "title":
62+
params.title = singleSearch;
63+
break;
64+
case "url":
65+
params.url = singleSearch;
66+
break;
67+
case "tags":
68+
params.tag = singleSearchTypeValueId;
69+
break;
70+
case "organizations":
71+
params.organization = singleSearchTypeValueId;
72+
break;
73+
case "locations":
74+
params.location = singleSearchTypeValueId;
75+
break;
76+
default:
77+
}
78+
79+
setLoading(true);
80+
81+
const query = new URLSearchParams(params);
82+
83+
fetch(`${searchEndpoint}?${query}`, {
84+
headers: getHeaders(),
85+
})
86+
.then((response) => response.json())
87+
.then((data) => {
88+
setResult(data);
89+
})
90+
.finally(() => {
91+
setLoading(false);
92+
});
93+
};
94+
95+
const singleSearchTypeOptions = [
96+
{
97+
key: "singleSearchTypeOptions1",
98+
value: "title",
99+
title: t("single-search-type-title"),
100+
},
101+
{
102+
key: "singleSearchTypeOptions2",
103+
value: "url",
104+
title: t("single-search-type-url"),
105+
},
106+
{
107+
key: "singleSearchTypeOptions3",
108+
value: "organizations",
109+
title: t("single-search-type-organization"),
110+
},
111+
{
112+
key: "singleSearchTypeOptions4",
113+
value: "locations",
114+
title: t("single-search-type-location"),
115+
},
116+
{
117+
key: "singleSearchTypeOptions5",
118+
value: "tags",
119+
title: t("single-search-type-tag"),
120+
},
121+
];
122+
123+
useEffect(() => {
124+
setSingleSearchTypeValue("");
125+
}, [singleSearchType]);
126+
127+
return (
128+
<Row className="mb-2">
129+
<Col>
130+
<Select
131+
value={singleSearchType}
132+
onChange={({ target }) => setSingleSearchType(target.value)}
133+
label={t("single-search-type")}
134+
options={singleSearchTypeOptions}
135+
name="poster-search-type"
136+
allowNull={false}
137+
/>
138+
</Col>
139+
{(singleSearchType === "title" || singleSearchType === "url") && (
140+
<Col>
141+
<FormInput
142+
label={t("single-search-text")}
143+
name="poster-search"
144+
value={singleSearch}
145+
onChange={({ target }) => setSingleSearch(target.value)}
146+
/>
147+
</Col>
148+
)}
149+
{singleSearchType === "locations" && (
150+
<Col>
151+
<label
152+
className="form-label"
153+
htmlFor="single-search-select-locations"
154+
>
155+
{t("single-search-select")}
156+
</label>
157+
<AsyncSelect
158+
id="single-search-select-locations"
159+
isClearable
160+
isSearchable
161+
defaultOptions
162+
loadOptions={debounceOptions}
163+
value={singleSearchTypeValue}
164+
onChange={(newValue) => {
165+
setSingleSearchTypeValue(newValue);
166+
}}
167+
/>
168+
</Col>
169+
)}
170+
{singleSearchType === "organizations" && (
171+
<Col>
172+
<label
173+
className="form-label"
174+
htmlFor="single-search-select-organizations"
175+
>
176+
{t("single-search-select")}
177+
</label>
178+
<AsyncSelect
179+
id="single-search-select-organizations"
180+
isClearable
181+
isSearchable
182+
defaultOptions
183+
loadOptions={debounceOptions}
184+
value={singleSearchTypeValue}
185+
onChange={(newValue) => {
186+
setSingleSearchTypeValue(newValue);
187+
}}
188+
/>
189+
</Col>
190+
)}
191+
{singleSearchType === "tags" && (
192+
<Col>
193+
<label className="form-label" htmlFor="single-search-select-tags">
194+
{t("single-search-select")}
195+
</label>
196+
<AsyncSelect
197+
id="single-search-select-tags"
198+
isClearable
199+
isSearchable
200+
defaultOptions
201+
loadOptions={debounceOptions}
202+
value={singleSearchTypeValue}
203+
onChange={(newValue) => {
204+
setSingleSearchTypeValue(newValue);
205+
}}
206+
/>
207+
</Col>
208+
)}
209+
<Col className="d-flex align-items-end">
210+
<Button onClick={singleSearchFetch} className="mt-3" variant="success">
211+
{t("single-search-button")}
212+
</Button>
213+
</Col>
214+
</Row>
215+
);
216+
}
217+
218+
PosterSingleSearch.propTypes = {
219+
searchEndpoint: PropTypes.string.isRequired,
220+
optionsEndpoint: PropTypes.string.isRequired,
221+
setLoading: PropTypes.func.isRequired,
222+
setResult: PropTypes.func.isRequired,
223+
};
224+
225+
export default PosterSingleSearch;

0 commit comments

Comments
 (0)