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.
This commit is contained in:
@@ -1,8 +1,17 @@
|
||||
import { ELECTIVE_SETS } from '../data/electiveSets';
|
||||
import { SPECIALIZATIONS } from '../data/specializations';
|
||||
import { coursesBySet } from '../data/lookups';
|
||||
import type { Term } from '../data/types';
|
||||
import type { SetAnalysis } from '../solver/decisionTree';
|
||||
|
||||
// Reverse map: courseId → specialization names that require it
|
||||
const requiredForSpec: Record<string, string[]> = {};
|
||||
for (const spec of SPECIALIZATIONS) {
|
||||
if (spec.requiredCourseId) {
|
||||
(requiredForSpec[spec.requiredCourseId] ??= []).push(spec.name);
|
||||
}
|
||||
}
|
||||
|
||||
interface CourseSelectionProps {
|
||||
pinnedCourses: Record<string, string | null>;
|
||||
treeResults: SetAnalysis[];
|
||||
@@ -79,30 +88,37 @@ function ElectiveSet({
|
||||
<div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
|
||||
{courses.map((course) => {
|
||||
const ceiling = ceilingMap.get(course.id);
|
||||
const reqFor = requiredForSpec[course.id];
|
||||
return (
|
||||
<button
|
||||
key={course.id}
|
||||
onClick={() => onPin(course.id)}
|
||||
style={{
|
||||
display: 'flex', justifyContent: 'space-between', alignItems: 'center',
|
||||
display: 'flex', flexDirection: 'column', alignItems: 'stretch',
|
||||
textAlign: 'left', padding: '6px 10px',
|
||||
border: '1px solid #e5e7eb', borderRadius: '4px',
|
||||
background: '#fff', cursor: 'pointer', fontSize: '13px', color: '#333',
|
||||
gap: '8px',
|
||||
}}
|
||||
>
|
||||
<span style={{ flex: 1 }}>{course.name}</span>
|
||||
{ceiling && (
|
||||
<span style={{
|
||||
fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 600,
|
||||
color: ceiling.ceilingCount >= 3 ? '#16a34a' : ceiling.ceilingCount >= 2 ? '#2563eb' : '#666',
|
||||
}}>
|
||||
{ceiling.ceilingCount} spec{ceiling.ceilingCount !== 1 ? 's' : ''}
|
||||
{ceiling.ceilingSpecs.length > 0 && (
|
||||
<span style={{ fontWeight: 400, color: '#888', marginLeft: '3px' }}>
|
||||
({ceiling.ceilingSpecs.join(', ')})
|
||||
</span>
|
||||
)}
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '8px' }}>
|
||||
<span style={{ flex: 1 }}>{course.name}</span>
|
||||
{ceiling && (
|
||||
<span style={{
|
||||
fontSize: '11px', whiteSpace: 'nowrap', fontWeight: 600,
|
||||
color: ceiling.ceilingCount >= 3 ? '#16a34a' : ceiling.ceilingCount >= 2 ? '#2563eb' : '#666',
|
||||
}}>
|
||||
{ceiling.ceilingCount} spec{ceiling.ceilingCount !== 1 ? 's' : ''}
|
||||
{ceiling.ceilingSpecs.length > 0 && (
|
||||
<span style={{ fontWeight: 400, color: '#888', marginLeft: '3px' }}>
|
||||
({ceiling.ceilingSpecs.join(', ')})
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{reqFor && (
|
||||
<span style={{ fontSize: '11px', color: '#92400e', marginTop: '2px' }}>
|
||||
Required for {reqFor.join(', ')}
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user