-
Notifications
You must be signed in to change notification settings - Fork 334
feat: Course outline restructure with new plugin slots #1920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,33 +2,43 @@ | |
| import { useToggle } from '@openedx/paragon'; | ||
| import { LOADING } from '@src/constants'; | ||
|
|
||
| import { | ||
| useCourseOutlineData, | ||
| } from '@src/courseware/course/sidebar/sidebars/course-outline/hooks'; | ||
| import PageLoading from '@src/generic/PageLoading'; | ||
| import { CourseOutlineSidebarHeadingSlot } from '@src/plugin-slots/CourseOutlineSidebarHeadingSlot'; | ||
| import classNames from 'classnames'; | ||
| import { useState } from 'react'; | ||
| import SidebarSection from './components/SidebarSection'; | ||
| import { useParams } from 'react-router-dom'; | ||
| import SidebarSequence from './components/SidebarSequence'; | ||
| import { ID } from './constants'; | ||
| import { useCourseOutlineSidebar } from './hooks'; | ||
| import SidebarSection from './components/SidebarSection'; | ||
| import messages from './messages'; | ||
|
|
||
| export const CourseOutline = () => { | ||
| interface CourseOutlineProps { | ||
| shouldDisplayFullScreen?: boolean; | ||
| onToggleCollapse?: () => void; | ||
| } | ||
|
|
||
| interface CoursePageParams extends Record<string, string> { | ||
| courseId: string; | ||
| unitId: string; | ||
| } | ||
|
Comment on lines
+22
to
+25
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude called this out
|
||
|
|
||
| export const CourseOutline = ({ | ||
| shouldDisplayFullScreen = false, | ||
| onToggleCollapse, | ||
| }: CourseOutlineProps) => { | ||
| const intl = useIntl(); | ||
| const [selectedSection, setSelectedSection] = useState<string | null>(null); | ||
| const [isDisplaySequenceLevel, setDisplaySequenceLevel, setDisplaySectionLevel] = useToggle(true); | ||
|
|
||
| const { unitId, courseId } = useParams<CoursePageParams>(); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see any test changes in this PR. Were there tests assuming we were getting a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that is a good point. I think the fact that not tests fail after moving the source from Sidebar context to useParams means that the tests were probably not testing how unitId is used. |
||
| const { | ||
| courseId, | ||
| unitId, | ||
| currentSidebar, | ||
|
brian-smith-tcril marked this conversation as resolved.
|
||
| isActiveEntranceExam, | ||
| courseOutlineStatus, | ||
| activeSequenceId, | ||
| sections, | ||
| sequences, | ||
| shouldDisplayFullScreen, | ||
| handleToggleCollapse, | ||
| } = useCourseOutlineSidebar(); | ||
| isActiveEntranceExam, | ||
| } = useCourseOutlineData(); | ||
|
|
||
| const resolvedSectionId = selectedSection | ||
| || Object.keys(sections).find( | ||
|
|
@@ -47,19 +57,16 @@ | |
| setDisplaySequenceLevel(); | ||
| setSelectedSection(id); | ||
| }; | ||
|
|
||
| const sidebarHeading = ( | ||
| <CourseOutlineSidebarHeadingSlot | ||
| onToggleCollapse={handleToggleCollapse} | ||
| onToggleCollapse={onToggleCollapse} | ||
| isDisplaySequenceLevel={isDisplaySequenceLevel} | ||
| backButton={backButtonTitle ? { title: backButtonTitle, onClick: handleBackToSectionLevel } : undefined} | ||
| /> | ||
| ); | ||
|
|
||
| if (isActiveEntranceExam || currentSidebar !== ID) { | ||
| if (isActiveEntranceExam) { | ||
| return null; | ||
| } | ||
|
|
||
| if (courseOutlineStatus === LOADING) { | ||
| return ( | ||
| <div className={classNames('outline-sidebar-wrapper', { | ||
|
|
@@ -90,10 +97,10 @@ | |
| ? sequenceIds.map((sequenceId: string) => ( | ||
| <SidebarSequence | ||
| key={sequenceId} | ||
| courseId={courseId!} | ||
| courseId={courseId} | ||
| sequence={sequences[sequenceId]} | ||
| defaultOpen={sequenceId === activeSequenceId} | ||
| activeUnitId={unitId!} | ||
| activeUnitId={unitId} | ||
| /> | ||
| )) | ||
| : sectionsIds.map((sectionId) => ( | ||
|
|
@@ -108,5 +115,3 @@ | |
| </div> | ||
| ); | ||
| }; | ||
|
|
||
| export default CourseOutline; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -5,12 +5,14 @@ import { useCourseOutlineSidebar } from './hooks'; | |
| const CourseOutlineTray = () => { | ||
| const { | ||
| currentSidebar, | ||
| shouldDisplayFullScreen, | ||
| handleToggleCollapse, | ||
| } = useCourseOutlineSidebar(); | ||
|
|
||
| if (currentSidebar !== ID) { | ||
| return null; | ||
| } | ||
| return <CourseOutline />; | ||
| return <CourseOutline shouldDisplayFullScreen={shouldDisplayFullScreen} onToggleCollapse={handleToggleCollapse} />; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude question about this:
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Having CourseOuline call
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Could you elaborate on this a bit? My feeling is that regardless of where I'm open to these being passed as props, I just want to understand the motivation a bit better.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I see your point, that is how those values are currently used. However for a client we extracted this component and injected it in the header as a dropdown. It can still use the toggle collapse, but its context is different from that of a sidebar. This work was triggered by the need for hosting this component outside the sidebar. Having the values passed explicitly seemed to be a cleaner separation. That said it's still in the sidebars folder so without further refactoring it's still somewhat tied to the sidebar and keeping the values by default won't break anything. We could do further refactoring to move this out and make the fullscreen code part of the sidebar wrapper rather than the outline component, but I think for now I can make these params default to the sidebar context values. |
||
| }; | ||
|
|
||
| CourseOutlineTray.ID = ID; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import React from 'react'; | ||
| import { Link, useLocation } from 'react-router-dom'; | ||
|
|
||
| import { useCourseOutlineSidebar } from '../hooks'; | ||
| import { useCourseOutlineData, useCourseOutlineSidebar } from '../hooks'; | ||
|
|
||
| interface Props { | ||
| courseId: string; | ||
|
|
@@ -26,17 +26,25 @@ const UnitLinkWrapper: React.FC<Props> = ({ | |
| courseId, | ||
| children, | ||
| }) => { | ||
| const { handleUnitClick } = useCourseOutlineSidebar(); | ||
| const { handleUnitClick } = useCourseOutlineData(); | ||
| const { shouldDisplayFullScreen, handleToggleCollapse } = useCourseOutlineSidebar(); | ||
| const { pathname } = useLocation(); | ||
| const isPreview = pathname.startsWith('/preview'); | ||
| const baseUrl = `/course/${courseId}/${sequenceId}/${id}`; | ||
| const link = isPreview ? `/preview${baseUrl}` : baseUrl; | ||
| const handleClick = React.useCallback(() => { | ||
| // Hide the sidebar after selecting a unit on a mobile device. | ||
| if (shouldDisplayFullScreen) { | ||
| handleToggleCollapse(); | ||
| } | ||
| handleUnitClick({ sequenceId, activeUnitId, id }); | ||
| }, [handleUnitClick, sequenceId, activeUnitId, id, shouldDisplayFullScreen, handleToggleCollapse]); | ||
|
brian-smith-tcril marked this conversation as resolved.
Comment on lines
+35
to
+41
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looking at this block a few things stand out to me:
Claude dive into why
|
||
|
|
||
| return ( | ||
| <Link | ||
| to={link} | ||
| className="row w-100 m-0 d-flex align-items-center text-gray-700" | ||
| onClick={() => handleUnitClick({ sequenceId, activeUnitId, id })} | ||
| onClick={handleClick} | ||
| > | ||
| {children} | ||
| </Link> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I haven't read through this file fully but it looks like it might need to be updated, so this is just a note to make sure this file accurately reflects the current state of the repo with the changes in this PR.