CourseCard.jsx UI component

The atomic unit of the UI. A draggable course tile rendered in three contexts: inside a semester row, inside the course bank, and inside the GradPanel requirement tree. Appearance adapts to context and viewport size.

Parent
SemRow, SummerRow, BankPanel, GradPanel
Lines
~500
Key props
id (courseId), inSem (bool), semId (when placed)

Three rendering modes

ContextLayoutShows
Semester (desktop)Tall card, full widthColor stripe, code, title, SH badge, NUPath tags, schedule badge, warning icons
Semester (phone)Compact rowCode + SH only. No title (saves space).
BankNarrow rowCode + star button. No SH/NUPath (shown in InfoPanel when selected).

Warning icons

Three types of inline warnings shown on cards in semester rows:

Additionally, a yellow border appears when prereqViolations.has(id) (the "misplaced" highlight in the legend).

Variable-credit editing

If course.shMin !== course.shMax, the SH badge becomes clickable. Clicking it enters edit mode: a small inline <input type="number"> replaces the badge. On blur/enter, the value is stored in shOverrides[id] in context (clamped to [shMin, shMax]).

Selection and dimming

Clicking a card sets selectedId = id in context. This opens InfoPanel and triggers RelationLines to draw SVG lines. All other cards receive reduced opacity (0.4) to dim them. The selected card gets a highlighted border.

Drag handling

sequenceDiagram participant Card as CourseCard participant Ctx as PlannerContext participant Target as SemRow (drop target) Card->>Ctx: onDragStart → set dragInfo = {courseId, sourceType} Card->>Card: set dragging CSS class Target->>Ctx: onDragEnter → set hoveredSem Target->>Ctx: onDragLeave → clear hoveredSem Target->>Ctx: onDrop(courseId, semId) Ctx->>Ctx: pushUndo() → update placements Card->>Ctx: onDragEnd → clear dragInfo

On touch devices, the same flow is driven by touchstart/touchmove/touchend events with a ghost element that follows the finger. The ghost is a clone of the card appended to document.body.