11import { useState } from 'react' ;
2+ import { isEmpty } from 'lodash' ;
3+
24import { useIntl } from '@edx/frontend-platform/i18n' ;
35import {
46 Button , Stack , Tab , Tabs ,
@@ -17,26 +19,28 @@ import { useCourseAuthoringContext } from '@src/CourseAuthoringContext';
1719import XBlockContainerIframe from '@src/course-unit/xblock-container-iframe' ;
1820import { IframeProvider } from '@src/generic/hooks/context/iFrameContext' ;
1921import { Link } from 'react-router-dom' ;
22+ import { possibleUnitMoves } from '@src/course-outline/drag-helper/utils' ;
2023import { useOutlineSidebarContext } from '../OutlineSidebarContext' ;
2124import { PublishButon } from './PublishButon' ;
2225import messages from '../messages' ;
2326import { InfoSection } from './InfoSection' ;
2427
25- interface Props {
26- unitId : string ;
27- index ?: number
28- }
29-
30- export const UnitSidebar = ( { unitId, index } : Props ) => {
28+ export const UnitSidebar = ( ) => {
3129 const intl = useIntl ( ) ;
3230 const [ tab , setTab ] = useState < 'preview' | 'info' | 'settings' > ( 'info' ) ;
31+ const { selectedContainerState, clearSelection, setSelectedContainerState } = useOutlineSidebarContext ( ) ;
32+ const {
33+ currentId : unitId = '' ,
34+ index,
35+ } = selectedContainerState ?? { } ;
3336 const { data : unitData , isLoading } = useCourseItemData ( unitId ) ;
34- const { selectedContainerState, clearSelection } = useOutlineSidebarContext ( ) ;
3537 const {
3638 openPublishModal,
3739 getUnitUrl,
3840 courseId,
3941 handleDuplicateUnitSubmit,
42+ sections,
43+ updateUnitOrderByIndex,
4044 } = useCourseAuthoringContext ( ) ;
4145
4246 const handlePublish = ( ) => {
@@ -53,6 +57,63 @@ export const UnitSidebar = ({ unitId, index }: Props) => {
5357 return < Loading /> ;
5458 }
5559
60+ // Resolve section and subsection from selectedContainerState indices
61+ const sectionIndex = selectedContainerState ?. sectionIndex ;
62+ const section = sectionIndex !== undefined ? sections [ sectionIndex ] : undefined ;
63+ const subsectionIndex = section && selectedContainerState ?. subsectionId
64+ ? section . childInfo . children . findIndex ( ( s ) => s . id === selectedContainerState . subsectionId )
65+ : - 1 ;
66+ const subsection = subsectionIndex !== - 1 ? section ?. childInfo . children [ subsectionIndex ] : undefined ;
67+
68+ // Build move calculator only when all ancestor context is available
69+ const getPossibleMoves = ( section && subsection && subsectionIndex !== - 1 )
70+ ? possibleUnitMoves (
71+ [ ...sections ] ,
72+ sectionIndex ?? - 1 ,
73+ subsectionIndex ,
74+ section ,
75+ subsection ,
76+ subsection . childInfo . children ,
77+ )
78+ : undefined ;
79+
80+ const canMoveUnit = ( oldIndex : number , step : number ) => {
81+ if ( getPossibleMoves ) {
82+ const moveDetails = getPossibleMoves ( oldIndex , step ) ;
83+ return ! isEmpty ( moveDetails ) ;
84+ }
85+ return false ;
86+ } ;
87+
88+ const handleMove = ( step : number ) => {
89+ if ( section && subsection && getPossibleMoves && index !== undefined && sectionIndex !== undefined ) {
90+ const moveDetails = getPossibleMoves ( index , step ) ;
91+ // section is the current parent section (used as prevSection in cross-section moves)
92+ updateUnitOrderByIndex ( section , moveDetails ) ;
93+ if ( ! isEmpty ( moveDetails ) ) {
94+ const newSectionId = moveDetails . sectionId ;
95+ const newSubsectionId = moveDetails . subsectionId ;
96+ // Cross-subsection move: unit goes to end of previous or start of next subsection
97+ const isCrossSubsection = newSubsectionId !== subsection . id ;
98+ const newSectionIndex = newSectionId !== section . id
99+ ? sections . findIndex ( ( s ) => s . id === newSectionId )
100+ : sectionIndex ;
101+ const newIndex = isCrossSubsection
102+ ? ( step === - 1
103+ ? sections [ newSectionIndex ] . childInfo . children . find ( ( s ) => s . id === newSubsectionId ) ?. childInfo . children . length ?? 0
104+ : 0 )
105+ : index + step ;
106+ setSelectedContainerState ( selectedContainerState ? {
107+ ...selectedContainerState ,
108+ sectionId : newSectionId ,
109+ sectionIndex : newSectionIndex ,
110+ subsectionId : newSubsectionId ,
111+ index : newIndex ,
112+ } : undefined ) ;
113+ }
114+ }
115+ } ;
116+
56117 return (
57118 < >
58119 < SidebarTitle
@@ -62,9 +123,10 @@ export const UnitSidebar = ({ unitId, index }: Props) => {
62123 menuProps = { {
63124 itemId : unitId ,
64125 index : index ?? - 1 ,
126+ canMoveItem : canMoveUnit ,
65127 onClickDuplicate : handleDuplicateUnitSubmit ,
66- onClickMoveUp : ( ) => { } ,
67- onClickMoveDown : ( ) => { } ,
128+ onClickMoveUp : ( ) => handleMove ( - 1 ) ,
129+ onClickMoveDown : ( ) => handleMove ( 1 ) ,
68130 onClickUnlink : ( ) => { } ,
69131 onClickDelete : ( ) => { } ,
70132 onClickViewLibrary : ( ) => { } ,
0 commit comments