Skip to content

Commit da98eaf

Browse files
committed
2927: Refactored poster subscription
1 parent 40e3d1f commit da98eaf

File tree

2 files changed

+282
-260
lines changed

2 files changed

+282
-260
lines changed
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import AsyncSelect from "react-select/async";
2+
import { React, useRef } from "react";
3+
import { useTranslation } from "react-i18next";
4+
import PropTypes from "prop-types";
5+
import { getHeaders, loadDropdownOptionsPromise } from "./poster-helper";
6+
7+
/**
8+
* @param {object} props The props.
9+
* @param {string} props.optionsEndpoint The options endpoint.
10+
* @param {object} props.configuration The configuration object.
11+
* @param {Array} props.configuration.subscriptionPlaceValue Array of selections.
12+
* @param {Array} props.configuration.subscriptionOrganizerValue Array of selections.
13+
* @param {Array} props.configuration.subscriptionTagValue Array of selections.
14+
* @param {number} props.configuration.subscriptionNumberValue Number of results to pick.
15+
* @param {Function} props.handleSelect Select callback.
16+
* @returns {React.JSX.Element} The criteria component.
17+
*/
18+
function PosterSubscriptionCriteria({
19+
optionsEndpoint,
20+
configuration: {
21+
subscriptionPlaceValue,
22+
subscriptionOrganizerValue,
23+
subscriptionTagValue,
24+
subscriptionNumberValue,
25+
},
26+
handleSelect,
27+
}) {
28+
const { t } = useTranslation("common", { keyPrefix: "poster-selector-v2" });
29+
30+
const locationTimeoutRef = useRef(null);
31+
const organizationTimeoutRef = useRef(null);
32+
const tagTimeoutRef = useRef(null);
33+
34+
// The user can choose between 1-10 entries to display.
35+
const numberOptions = Array.from(Array(10).keys());
36+
37+
const debounceOptions = (inputValue, type) => {
38+
// Debounce promise.
39+
return new Promise((resolve, reject) => {
40+
let timeoutRef = null;
41+
42+
switch (type) {
43+
case "locations":
44+
timeoutRef = locationTimeoutRef;
45+
break;
46+
case "organizations":
47+
timeoutRef = organizationTimeoutRef;
48+
break;
49+
case "tags":
50+
timeoutRef = tagTimeoutRef;
51+
break;
52+
default:
53+
return;
54+
}
55+
56+
if (timeoutRef.current) {
57+
clearTimeout(timeoutRef.current);
58+
}
59+
60+
timeoutRef.current = setTimeout(() => {
61+
loadDropdownOptionsPromise(
62+
optionsEndpoint,
63+
getHeaders(),
64+
inputValue,
65+
type
66+
)
67+
.then((data) => resolve(data))
68+
.catch((reason) => reject(reason));
69+
}, 500);
70+
});
71+
};
72+
73+
return (
74+
<>
75+
<h5 className="mt-3">{t("filters")}</h5>
76+
<div className="mb-2">
77+
<div className="form-group">
78+
<label
79+
htmlFor="os2display-poster--select-subscription-places"
80+
className="form-label"
81+
>
82+
{t("filters-place")}
83+
</label>
84+
<AsyncSelect
85+
id="subscription-search-place"
86+
isClearable
87+
isSearchable
88+
defaultOptions
89+
isMulti
90+
loadOptions={(inputValue) =>
91+
debounceOptions(inputValue, "locations")
92+
}
93+
value={subscriptionPlaceValue}
94+
onChange={(newValue) => {
95+
handleSelect("subscriptionPlaceValue", newValue);
96+
}}
97+
/>
98+
</div>
99+
</div>
100+
101+
<div className="mb-2">
102+
<div className="form-group">
103+
<label
104+
htmlFor="os2display-poster--select-subscription-organizers"
105+
className="form-label"
106+
>
107+
{t("filters-organizer")}
108+
</label>
109+
<AsyncSelect
110+
id="subscription-search-place"
111+
isClearable
112+
isSearchable
113+
defaultOptions
114+
isMulti
115+
loadOptions={(inputValue) =>
116+
debounceOptions(inputValue, "organizations")
117+
}
118+
value={subscriptionOrganizerValue}
119+
onChange={(newValue) => {
120+
handleSelect("subscriptionOrganizerValue", newValue);
121+
}}
122+
/>
123+
</div>
124+
</div>
125+
126+
<div className="mb-2">
127+
<div className="form-group">
128+
<label
129+
htmlFor="os2display-poster--select-subscription-tags"
130+
className="form-label"
131+
>
132+
{t("filters-tag")}
133+
</label>
134+
<AsyncSelect
135+
id="subscription-search-tag"
136+
isClearable
137+
isSearchable
138+
defaultOptions
139+
isMulti
140+
loadOptions={(inputValue) => debounceOptions(inputValue, "tags")}
141+
value={subscriptionTagValue}
142+
onChange={(newValue) => {
143+
handleSelect("subscriptionTagValue", newValue);
144+
}}
145+
/>
146+
</div>
147+
</div>
148+
149+
<div>
150+
<div className="form-group">
151+
<div>
152+
<label
153+
htmlFor="os2display-poster--select-number"
154+
className="form-label"
155+
>
156+
{t("number-of-slides")}
157+
<select
158+
className="form-control"
159+
id="os2display-poster--select-number"
160+
value={subscriptionNumberValue}
161+
onChange={({ target }) =>
162+
handleSelect("subscriptionNumberValue", target.value)
163+
}
164+
>
165+
{numberOptions?.map((i) => (
166+
<option value={i + 1} key={`number-of-slides-option-${i}`}>
167+
{i + 1}
168+
</option>
169+
))}
170+
</select>
171+
</label>
172+
</div>
173+
</div>
174+
</div>
175+
</>
176+
);
177+
}
178+
179+
PosterSubscriptionCriteria.propTypes = {
180+
optionsEndpoint: PropTypes.string.isRequired,
181+
configuration: PropTypes.shape({
182+
subscriptionPlaceValue: PropTypes.arrayOf(
183+
PropTypes.shape({ label: PropTypes.string, value: PropTypes.number })
184+
),
185+
subscriptionOrganizerValue: PropTypes.arrayOf(
186+
PropTypes.shape({ label: PropTypes.string, value: PropTypes.number })
187+
),
188+
subscriptionTagValue: PropTypes.arrayOf(
189+
PropTypes.shape({ label: PropTypes.string, value: PropTypes.number })
190+
),
191+
subscriptionNumberValue: PropTypes.number,
192+
}).isRequired,
193+
handleSelect: PropTypes.func.isRequired,
194+
};
195+
196+
export default PosterSubscriptionCriteria;

0 commit comments

Comments
 (0)