@@ -17,7 +17,7 @@ import { useCopyToClipboard } from "react-use";
1717
1818import { getOkpyCommand , areArraysEqual } from "../../utils" ;
1919
20- function TimelineButton ( { backup, selected, index, handleBackupSelect } ) {
20+ function TimelineButton ( { backup, selected, index, handleBackupSelect, ref } ) {
2121 function getQuestionsWorkedOn ( ) {
2222 return backup . question_display_names . join ( " " ) ;
2323 }
@@ -106,6 +106,7 @@ function TimelineButton({ backup, selected, index, handleBackupSelect }) {
106106 return (
107107 < Tooltip title = { getTooltipTitle ( ) } placement = "right" >
108108 < Button
109+ ref = { ref }
109110 key = { backup . id }
110111 variant = { selected ? "contained" : "outlined" }
111112 onClick = { ( ) => handleBackupSelect ( index ) }
@@ -123,6 +124,7 @@ function TimelineButtonGroup({
123124 handleBackupSelect,
124125 absoluteStartIndex,
125126 setIsSnackbarOpen,
127+ selectedRef,
126128} ) {
127129 const [ _ , copyOkpyCommand ] = useCopyToClipboard ( ) ;
128130 const okpyCommand = getOkpyCommand (
@@ -169,14 +171,17 @@ function TimelineButtonGroup({
169171 aria-label = "Vertical button group"
170172 style = { { width : "100%" } }
171173 >
172- { backups . map ( ( backup , relativeIndex ) => (
173- < TimelineButton
174+ { backups . map ( ( backup , relativeIndex ) => {
175+ const isSelected = relativeIndex + absoluteStartIndex === selectedBackup ;
176+
177+ return ( < TimelineButton
174178 backup = { backup }
175- selected = { relativeIndex + absoluteStartIndex === selectedBackup }
179+ selected = { isSelected }
176180 index = { relativeIndex + absoluteStartIndex }
177181 handleBackupSelect = { handleBackupSelect }
178- />
179- ) ) }
182+ ref = { isSelected ? selectedRef : null }
183+ /> ) ;
184+ } ) }
180185 </ ButtonGroup >
181186 </ div >
182187 ) ;
@@ -187,6 +192,18 @@ function Timeline({ backups, selectedBackup, handleBackupSelect }) {
187192 "A timeline of this student's OkPy backups, most recent backup first. A backup is formed every time they run unlocking or coding tests for a particular question." ;
188193
189194 const [ isSnackbarOpen , setIsSnackbarOpen ] = React . useState ( false ) ;
195+ const selectedRef = React . useRef ( null ) ;
196+
197+ // Add an effect that scrolls when selectedBackup changes or on initial load
198+ // TODO only scroll left sidebar, not entire page
199+ useEffect ( ( ) => {
200+ if ( selectedRef . current ) {
201+ selectedRef . current . scrollIntoView ( {
202+ behavior : "smooth" , // Use "auto" for instant jump on page load
203+ block : "center" , // Centers the button in the viewport
204+ } ) ;
205+ }
206+ } , [ selectedBackup ] ) ; // Re-run if the selection changes
190207
191208 const handleSnackbarClose = ( event , reason ) => {
192209 if ( reason === "clickaway" ) {
@@ -269,6 +286,7 @@ function Timeline({ backups, selectedBackup, handleBackupSelect }) {
269286 handleBackupSelect = { handleBackupSelect }
270287 absoluteStartIndex = { absoluteStartIndex }
271288 setIsSnackbarOpen = { setIsSnackbarOpen }
289+ selectedRef = { selectedRef }
272290 /> ,
273291 ) ;
274292 absoluteStartIndex += backupGroup . length ;
0 commit comments