Skip to content

Commit c2b4e51

Browse files
spotta85claude
andauthored
Fix catalog search matching and remove duplicate query/dedupe logic (#189)
- Catalog DB search (searchCatalogCourses) only matched fullName/courseName, so searching by course code or instructor silently returned nothing. Extract matchesCatalogQuery (code + title + short name + instructors) and use it in both filterCatalogCourses and searchCatalogCourses so the two paths agree. - Replace the inline Set dedupe in searchCores with dedupeCatalogCoursesByCode. - Delete the duplicate "Requirement" dropdown that bound the same formData.department as the Department dropdown (and its now-unused icon). - Decode leaked HTML entity: Women&#x27;s -> Women's. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent cda7a6f commit c2b4e51

4 files changed

Lines changed: 26 additions & 41 deletions

File tree

features/catalog/catalog-course-mappers.ts

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,23 @@ export function catalogCourseToPlannedCourse(
3737
};
3838
}
3939

40+
// Matches a catalog course against an already-normalized (trimmed, lowercased)
41+
// query across code, title, short name, and instructor names. Shared by the
42+
// in-memory filter and the Dexie-backed search so both stay in sync.
43+
export function matchesCatalogQuery(
44+
course: CatalogCourse,
45+
normalizedQuery: string,
46+
): boolean {
47+
if (!normalizedQuery) return true;
48+
49+
return [
50+
`${course.department} ${course.number}`,
51+
course.fullName,
52+
course.courseName,
53+
course.instructors.map(({ fullName }) => fullName).join(" "),
54+
].some((value) => value.toLowerCase().includes(normalizedQuery));
55+
}
56+
4057
export function filterCatalogCourses(
4158
courses: CatalogCourse[],
4259
query: string,
@@ -45,11 +62,6 @@ export function filterCatalogCourses(
4562
if (!normalizedQuery) return courses;
4663

4764
return courses.filter((course) =>
48-
[
49-
`${course.department} ${course.number}`,
50-
course.fullName,
51-
course.courseName,
52-
course.instructors.map(({ fullName }) => fullName).join(" "),
53-
].some((value) => value.toLowerCase().includes(normalizedQuery)),
65+
matchesCatalogQuery(course, normalizedQuery),
5466
);
5567
}

features/catalog/catalog-db.ts

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import Dexie from "dexie";
22
import type { CatalogCourse } from "@/domain/catalog";
33
import type { CoreArea } from "@/domain/course";
4+
import {
5+
dedupeCatalogCoursesByCode,
6+
matchesCatalogQuery,
7+
} from "./catalog-course-mappers";
48
import { DEPARTMENT_MAP } from "./department-map";
59

610
export class UTDatabase extends Dexie {
@@ -34,19 +38,8 @@ export async function searchCores(
3438
}
3539

3640
const courses = await findCoursesByCore(core);
37-
const seenCourseCodes = new Set<string>();
3841

39-
return courses
40-
.filter((course) => {
41-
const courseCode = `${course.department} ${course.number}`;
42-
if (seenCourseCodes.has(courseCode)) {
43-
return false;
44-
}
45-
46-
seenCourseCodes.add(courseCode);
47-
return true;
48-
})
49-
.slice(0, limit);
42+
return dedupeCatalogCoursesByCode(courses).slice(0, limit);
5043
}
5144

5245
function getDepartmentCodesByName(departmentName: string): string[] {
@@ -71,11 +64,8 @@ export function searchCatalogCourses(filters: {
7164
return db.courses
7265
.toCollection()
7366
.filter((course) => {
74-
// Match the search text against the catalog title fields.
75-
const matchesQuery =
76-
normalizedQuery.length === 0 ||
77-
course.fullName.toLowerCase().includes(normalizedQuery) ||
78-
course.courseName.toLowerCase().includes(normalizedQuery);
67+
// Match the search text against code, title, short name, and instructors.
68+
const matchesQuery = matchesCatalogQuery(course, normalizedQuery);
7969

8070
// Match the selected department name against the stored department codes.
8171
const matchesDepartment =

features/catalog/department-map.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export const DEPARTMENT_MAP: Record<string, string> = {
227227
VIA: "Viola",
228228
VIO: "Violin",
229229
VOI: "Voice",
230-
WGS: "Women&#x27;s and Gender Studies",
230+
WGS: "Women's and Gender Studies",
231231
WRT: "Writing",
232232
YID: "Yiddish",
233233
YOR: "Yoruba",

features/course-search/course-search-panel.tsx

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
CaretLeftIcon,
1313
ChalkboardTeacherIcon,
1414
CircleNotchIcon,
15-
GraduationCapIcon,
1615
} from "@phosphor-icons/react";
1716
import { useState } from "react";
1817
import CourseCard from "./course-card";
@@ -157,22 +156,6 @@ function CourseSearchContent({
157156

158157
<div className="flex items-center gap-3 my-4" />
159158

160-
<div className="mb-4">
161-
<SelectDropdown
162-
icon={<GraduationCapIcon size={28} />}
163-
placeholder="Requirement"
164-
options={DEPARTMENTS}
165-
value={formData.department}
166-
onChange={(value) =>
167-
setFormData((previous) => ({
168-
...previous,
169-
department: value,
170-
}))
171-
}
172-
disabled={isSearching}
173-
/>
174-
</div>
175-
176159
<div className="mb-4">
177160
<SelectDropdown
178161
icon={<ChalkboardTeacherIcon size={28} />}

0 commit comments

Comments
 (0)