From 6af24d92708f4c782903e7e303e419ec21cd0045 Mon Sep 17 00:00:00 2001 From: Bill Ballou Date: Sat, 28 Feb 2026 21:33:54 -0500 Subject: [PATCH] Show required specialization labels on course buttons Replace top-level mutual exclusion banner with dynamic per-course "Required for ..." labels derived from specialization data. Labels appear on any course that is a specialization prerequisite, across all elective sets. --- app/src/App.tsx | 3 +- app/src/components/CourseSelection.tsx | 44 ++++++++++++++++++-------- app/src/components/Notifications.tsx | 30 ------------------ 3 files changed, 31 insertions(+), 46 deletions(-) diff --git a/app/src/App.tsx b/app/src/App.tsx index 7be82f9..b8ae32a 100644 --- a/app/src/App.tsx +++ b/app/src/App.tsx @@ -5,7 +5,7 @@ import { SpecializationRanking } from './components/SpecializationRanking'; import { ModeToggle } from './components/ModeToggle'; import { CourseSelection } from './components/CourseSelection'; import { CreditLegend } from './components/CreditLegend'; -import { ModeComparison, MutualExclusionWarnings } from './components/Notifications'; +import { ModeComparison } from './components/Notifications'; import { optimize } from './solver/optimizer'; function App() { @@ -53,7 +53,6 @@ function App() { - = {}; +for (const spec of SPECIALIZATIONS) { + if (spec.requiredCourseId) { + (requiredForSpec[spec.requiredCourseId] ??= []).push(spec.name); + } +} + interface CourseSelectionProps { pinnedCourses: Record; treeResults: SetAnalysis[]; @@ -79,30 +88,37 @@ function ElectiveSet({
{courses.map((course) => { const ceiling = ceilingMap.get(course.id); + const reqFor = requiredForSpec[course.id]; return ( diff --git a/app/src/components/Notifications.tsx b/app/src/components/Notifications.tsx index b70683b..88f69ec 100644 --- a/app/src/components/Notifications.tsx +++ b/app/src/components/Notifications.tsx @@ -33,33 +33,3 @@ export function ModeComparison({ ); } -export function MutualExclusionWarnings({ pinnedCourses }: { pinnedCourses: Record }) { - const warnings: string[] = []; - const spr4Pin = pinnedCourses['spr4']; - - if (!spr4Pin) { - warnings.push('Spring Set 4: choosing Sustainability for Competitive Advantage eliminates Entrepreneurship & Innovation (and vice versa).'); - } else if (spr4Pin === 'spr4-sustainability') { - warnings.push('Entrepreneurship & Innovation is permanently unavailable (required course is in Spring Set 4, pinned to Sustainability).'); - } else if (spr4Pin === 'spr4-foundations-entrepreneurship') { - warnings.push('Sustainable Business & Innovation is permanently unavailable (required course is in Spring Set 4, pinned to Foundations of Entrepreneurship).'); - } - - if (warnings.length === 0) return null; - - return ( -
- {warnings.map((w, i) => ( -
- {w} -
- ))} -
- ); -}