From dbc5c9ed7e57588a55f5a9f6c2990881c641d83e Mon Sep 17 00:00:00 2001 From: condyl Date: Sun, 15 Mar 2026 18:50:32 -0400 Subject: [PATCH] feat: improve course search ranking and filtering logic in CourseSearchComponent --- .../CourseSearch/CourseSearchComponent.jsx | 46 ++++++++++++++----- 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/src/components/generator/Forms/CourseSearch/CourseSearchComponent.jsx b/src/components/generator/Forms/CourseSearch/CourseSearchComponent.jsx index 858f80c..d3a120a 100644 --- a/src/components/generator/Forms/CourseSearch/CourseSearchComponent.jsx +++ b/src/components/generator/Forms/CourseSearch/CourseSearchComponent.jsx @@ -88,25 +88,47 @@ export default function CourseSearchComponent({ const filteredOptions = React.useMemo(() => { const query = (value || "").trim().toUpperCase(); + const compactQuery = query.replace(/\s+/g, ""); const results = []; for (let i = 0; i < normalizedOptions.length; i += 1) { const option = normalizedOptions[i]; const label = option.label.toUpperCase(); + const compactLabel = label.replace(/\s+/g, ""); const courseName = option.courseName.toUpperCase(); - const matchesQuery = - !query || - label.startsWith(query) || - label.includes(query) || - courseName.includes(query); - - if (matchesQuery) { - results.push(option); - if (results.length >= displayLimit) { - break; - } + const courseNameWords = courseName.split(/\s+/).filter(Boolean); + + let rank = -1; + if (!query) { + rank = 0; + } else if (compactLabel.startsWith(compactQuery)) { + rank = 1; + } else if (label.startsWith(query)) { + rank = 2; + } else if (compactLabel.includes(compactQuery)) { + rank = 3; + } else if (label.includes(query)) { + rank = 4; + } else if (courseName.startsWith(query)) { + rank = 5; + } else if (courseNameWords.some((word) => word.startsWith(query))) { + rank = 6; + } else if (courseName.includes(query)) { + rank = 7; } + + if (rank === -1) continue; + + results.push({ option, rank }); } - return results; + + results.sort((a, b) => { + if (a.rank !== b.rank) { + return a.rank - b.rank; + } + return a.option.label.localeCompare(b.option.label); + }); + + return results.slice(0, displayLimit).map((result) => result.option); }, [normalizedOptions, value, displayLimit]); const handleSelectOption = (option) => {