Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit 55641f6

Browse files
committed
fix(roles): do not allow manual skill selection (if not in the list)
* Fix an issue which was allowing users to be able to add non-existing skills. * The `Typeahead` component was also firing the `onChange` event on Blur, Enter and Esc presses. * To overcome this, added a property (`enforceListOnlySelection`) to the component. If it's set, the `onChange` event will be fired only if the input is in the suggestion list. * Add `minLengthForSuggestions` property to the `Typeahead` component. * This is the minimum length to retrieve & display suggestions and was hardcoded (with 3) in the component. * The new property allows to specify it. The ability to set it to `1` is useful for displaying skills like `C`, `C#`, which have less than 3 characters. Adresses https://github.com/topcoder-platform/taas-app/issues/426
1 parent 870b4d5 commit 55641f6

File tree

2 files changed

+24
-10
lines changed

2 files changed

+24
-10
lines changed

src/components/Typeahead/index.jsx

+22-10
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ const selectComponents = {
7474
* @param {function} props.onChange function called when value changes
7575
* @param {function} [props.onInputChange] function called when input value changes
7676
* @param {function} [props.onBlur] function called on input blur
77+
* @param {number} [props.minLengthForSuggestions] the minimum string lenth for displaying suggestions (default 3)
78+
* @param {Boolean} [props.enforceListOnlySelection] enforces user to select from the list - manual inputs (if not in the list) won't affect the selection
7779
* @param {string} props.value input value
7880
* @param {function} props.getSuggestions the function to get suggestions
7981
* @param {string} props.targetProp the target property of the returned object from getSuggestions
@@ -87,6 +89,8 @@ const Typeahead = ({
8789
onChange,
8890
onInputChange,
8991
onBlur,
92+
minLengthForSuggestions = 3,
93+
enforceListOnlySelection = false,
9094
placeholder,
9195
value,
9296
getSuggestions,
@@ -139,7 +143,12 @@ const Typeahead = ({
139143
setIsMenuFocused(false);
140144
setIsMenuOpen(false);
141145
setIsLoading(false);
142-
onChange(inputValue);
146+
// fire onChange event
147+
// - if `enforceListOnlySelection` is not set,
148+
// - or if it's set and options list contains the value
149+
if (!enforceListOnlySelection || options.includes(inputValue)) {
150+
onChange(inputValue);
151+
}
143152
}
144153
} else if (key === "ArrowDown") {
145154
if (!isMenuFocused) {
@@ -158,7 +167,12 @@ const Typeahead = ({
158167
const onSelectBlur = () => {
159168
setIsMenuFocused(false);
160169
setIsMenuOpen(false);
161-
onChange(inputValue);
170+
// fire onChange event
171+
// - if `enforceListOnlySelection` is not set,
172+
// - or if it's set and options list contains the value
173+
if (!enforceListOnlySelection || options.includes(inputValue)) {
174+
onChange(inputValue);
175+
}
162176
onBlur && onBlur();
163177
};
164178

@@ -170,11 +184,10 @@ const Typeahead = ({
170184
}
171185
setIsLoading(true);
172186
setIsMenuOpen(true);
173-
const options = await loadSuggestions(
174-
getSuggestions,
175-
value,
176-
targetProp
177-
);
187+
const options =
188+
value.length < minLengthForSuggestions
189+
? [] // no suggestions yet if value length is less than `minLengthForSuggestions`
190+
: await loadSuggestions(getSuggestions, value, targetProp);
178191
if (!isChangeAppliedRef.current) {
179192
setOptions(options);
180193
setIsLoading(false);
@@ -233,9 +246,6 @@ const Typeahead = ({
233246

234247
const loadSuggestions = async (getSuggestions, inputValue, targetProp) => {
235248
let options = [];
236-
if (inputValue.length < 3) {
237-
return options;
238-
}
239249
try {
240250
const res = await getSuggestions(inputValue);
241251
const items = res.data.slice(0, 100);
@@ -266,6 +276,8 @@ Typeahead.propTypes = {
266276
onChange: PT.func.isRequired,
267277
onInputChange: PT.func,
268278
onBlur: PT.func,
279+
minLengthForSuggestions: PT.number,
280+
enforceListOnlySelection: PT.bool,
269281
placeholder: PT.string,
270282
value: PT.oneOfType([PT.number, PT.string]),
271283
getSuggestions: PT.func,

src/routes/Roles/components/RoleForm/index.jsx

+2
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,10 @@ function RoleForm() {
194194
id="skills"
195195
name="skills"
196196
placeholder="Search skills..."
197+
enforceListOnlySelection={true}
197198
onChange={(val) => addSkill(val)}
198199
onInputChange={(val) => setTypeaheadInputValue(val)}
200+
minLengthForSuggestions={1} // retrieve suggestions with min. 1 characters. Useful for skills like "C"
199201
value={typeaheadInputValue}
200202
getSuggestions={searchSkills}
201203
targetProp="name"

0 commit comments

Comments
 (0)