The following is a quick reference to the StudentDegreePlannerPage.
Sticky State# We are using three StickyState variables to share state across the Degree Experience Planner components. The three state names are defined in the DegreePlannerStateNames enum.
Copy export enum DegreePlannerStateNames {
selectedCiID = 'Planner.selectedCiID' ,
selectedOiID = 'Planner.selectedOiID' ,
selectedProfileTab = 'Planner.selectedProfileTab' ,
}
StudentDegreePlannerPage# The StudentDegreePlannerPage.tsx just uses the set methods. It doesn't actually care what the state values are.
Copy const [ , setSelectedCiID ] = useStickyState ( DegreePlannerStateNames . selectedCiID , '' ) ;
const [ , setSelectedOiID ] = useStickyState ( DegreePlannerStateNames . selectedOiID , '' ) ;
const [ , setSelectedProfileTab ] = useStickyState ( DegreePlannerStateNames . selectedProfileTab , '' ) ;
We pass these set methods are passed into the onDragEnd method by using a higher order method.
Copy const onDragEnd = ( onDragEndProps ) => ( result ) => {
const { match , setSelectedCiID , setSelectedOiID , setSelectedProfileTab } = onDragEndProps ;
...
}
We use the setSelectedCiID, setSelectedOiID, and setSelectedProfileTab in the onDragEnd method to tell the TabbedProfileEntries.tsx what to display.
DegreeExperiencePlanner# The DegreeExperiencePlanner also uses the StickyState set methods to tell the TabbedProfileEntries what is selected.
Copy const [ , setSelectedCiID ] = useStickyState ( DegreePlannerStateNames . selectedCiID , '' ) ;
const [ , setSelectedOiID ] = useStickyState ( DegreePlannerStateNames . selectedOiID , '' ) ;
const [ , setSelectedProfileTab ] = useStickyState ( DegreePlannerStateNames . selectedProfileTab , '' ) ;
TabbedProfileEntries# The TabbedProfileEntries defines the names of the individual tabs in an exported enum TabbedProfileEntryNames.
Copy export enum TabbedProfileEntryNames {
profileCourses = 'PROFILE_COURSES' ,
profileOpportunities = 'PROFILE_OPPORTUNITIES' ,
profileDetails = 'PROFILE_DETAILS' ,
}
It only cares about the selected tab state.
Copy const [ selectedTab , setSelectedTab ] = useStickyState ( DegreePlannerStateNames . selectedProfileTab , TabbedProfileEntryNames . profileOpportunities ) ;
When the student clicks on a tab we use the setSelectedTab method to update the selectedTab.
DepDetailsCard# Uses the selectedCourse and selectedOpportunity state to decide what to show.
Copy const [ selectedCourse ] = useStickyState ( DegreePlannerStateNames . selectedCiID , '' ) ;
const [ selectedOpportunity ] = useStickyState ( DegreePlannerStateNames . selectedOiID , '' ) ;
const courseP = selectedCourse !== '' ;
...
return courseP ? < DetailCourseCard instance = { instance as CourseInstance } / > : < DetailOpportunityCard instance = { instance as OpportunityInstance } verificationRequests = { verificationRequests } / > ;
Drag and Drop# We are using react-beautiful-dnd for our drag and drop needs.
StudentDegreePlannerPage# The StudentDegreePlannerPage wraps the entire page in a DragDropContext.
Copy return (
< DragDropContext onDragEnd = { onDragEnd ( onDragEndProps ) } >
...
< / DragDropContext >
) ;
The onDragEnd is our higher order function that passes in the sticky state set methods. By wrapping the entire page in the DragDropContext, we can drag items between the different components on the page. The onDragEnd method handles all the drop events. It stops the students from doing incorrect things to their degree plan. It creates the CourseInstances and OpportunityInstances on a valid drop. See onDragEnd for the current code.
AcademicTermView# The AcademicTermView defines the Droppable that allow students to drop course or opportunities into an academic term.
Copy < Droppable droppableId = { ` ${ termSlug } ` } >
{ ( provided , snapshot ) => (
< div ref = { provided . innerRef } style = { getDroppableListStyle ( snapshot . isDraggingOver ) } >
{ courseInstancesToShow . map ( ( ci , index ) => (
< DraggableCourseInstancePill key = { ci . _id } instance = { ci } index = { index } inPast = { inPast }
handleClickCourseInstance = { handleClickCourseInstance } / >
) ) }
{ opportunityInstancesToShow . map ( ( oi , index ) => (
< DraggableOpportunityInstancePill key = { oi . _id } instance = { oi }
index = { courseInstancesToShow . length + index }
handleClickOpportunityInstance = { handleClickOpportunityInstance } / >
) ) }
{ provided . placeholder }
< Icon name = "plus circle" color = "grey" / > Drag Here
< / div >
) }
< / Droppable >
DraggableCourseInstancePill and DraggableOpportunityInstancePill# The DraggableCourseInstancePill and DraggableOpportunityInstancePill define the Draggable elements.
Copy < Draggable key = { instance . _id } draggableId = { instance . _id } index = { index } >
{ ( prov , snap ) => (
< div ref = { prov . innerRef } { ... prov . draggableProps } { ... prov . dragHandleProps } style = { getDraggablePillStyle ( snap . isDragging , prov . draggableProps . style ) } >
< Grid >
< Grid . Row style = { { paddingTop : 7 , paddingBottom : 7 } } >
< Grid . Column width = { 13 } onClick = { handleClick ( instance , handleClickCourseInstance ) } >
< NamePill name = { instance . note } / >
< / Grid . Column >
< Grid . Column width = { 2 } > { inPast ? '' : < RemoveItWidget collectionName = "CourseInstanceCollection" id = { instance . _id } name = { getName ( instance ) } courseNumber = { instance . note } / > } < / Grid . Column >
< / Grid . Row >
< / Grid >
< / div >
) }
< / Draggable >