@@ -8,6 +8,7 @@ import { toaster } from "@/components/ui/toaster";
88import { useClassProfiles } from "@/hooks/useClassProfiles" ;
99import { useAssignmentDueDate , useCourse , useCourseController , useStudentRoster } from "@/hooks/useCourseController" ;
1010import { useListTableControllerValues , useTableControllerValueById } from "@/lib/TableController" ;
11+ import { useVirtualizedRowWindow } from "@/hooks/useVirtualizedRowWindow" ;
1112import { Assignment , AssignmentDueDateException , AssignmentGroup , UserProfile } from "@/utils/supabase/DatabaseTypes" ;
1213import { Database } from "@/utils/supabase/SupabaseTypes" ;
1314import {
@@ -608,16 +609,7 @@ export default function DueDateExceptions() {
608609 const course = useCourse ( ) ;
609610 const { assignment_id } = useParams ( ) ;
610611 const { assignments, assignmentGroupsWithMembers, assignmentDueDateExceptions } = useCourseController ( ) ;
611- //Ensure all data is fresh
612- useEffect ( ( ) => {
613- assignments . refetchAll ( ) ;
614- } , [ assignments ] ) ;
615- useEffect ( ( ) => {
616- assignmentDueDateExceptions . refetchAll ( ) ;
617- } , [ assignmentDueDateExceptions ] ) ;
618- useEffect ( ( ) => {
619- assignmentGroupsWithMembers . refetchAll ( ) ;
620- } , [ assignmentGroupsWithMembers ] ) ;
612+ // TableControllers already hydrate/fetch and stay realtime; avoid forced mount refetches on large classes.
621613 const controller = useCourseController ( ) ;
622614
623615 // Get assignment data
@@ -815,6 +807,11 @@ export default function DueDateExceptions() {
815807 }
816808 }
817809 } ) ;
810+ const tableRows = table . getRowModel ( ) . rows ;
811+ const rowWindow = useVirtualizedRowWindow ( tableRows , {
812+ estimatedRowHeight : 68 ,
813+ minRowsForVirtualization : 60
814+ } ) ;
818815
819816 if ( ! assignment ) {
820817 return < Skeleton height = "400px" width = "100%" /> ;
@@ -849,59 +846,71 @@ export default function DueDateExceptions() {
849846 </ Box >
850847
851848 { /* Table */ }
852- < Box w = "100%" overflowX = "auto" maxW = "100vw" maxH = "100vh" overflowY = "auto" >
853- < Table . Root minW = "0" w = "100%" >
854- < Table . Header >
855- { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
856- < Table . Row key = { headerGroup . id } >
857- { headerGroup . headers . map ( ( header ) => (
858- < Table . ColumnHeader
859- key = { header . id }
860- bg = "bg.muted"
861- style = { {
862- position : "sticky" ,
863- top : 0 ,
864- zIndex : 20
865- } }
866- >
867- { header . isPlaceholder ? null : (
868- < Text onClick = { header . column . getToggleSortingHandler ( ) } >
869- { flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
870- { {
871- asc : (
849+ < Box w = "100%" overflowX = "auto" maxW = "100vw" >
850+ < Box ref = { rowWindow . containerRef } onScroll = { rowWindow . onScroll } overflowY = "auto" maxH = "70vh" >
851+ < Table . Root minW = "0" w = "100%" >
852+ < Table . Header >
853+ { table . getHeaderGroups ( ) . map ( ( headerGroup ) => (
854+ < Table . Row key = { headerGroup . id } >
855+ { headerGroup . headers . map ( ( header ) => (
856+ < Table . ColumnHeader
857+ key = { header . id }
858+ bg = "bg.muted"
859+ style = { {
860+ position : "sticky" ,
861+ top : 0 ,
862+ zIndex : 20
863+ } }
864+ >
865+ { header . isPlaceholder ? null : (
866+ < Text onClick = { header . column . getToggleSortingHandler ( ) } >
867+ { flexRender ( header . column . columnDef . header , header . getContext ( ) ) }
868+ { {
869+ asc : (
870+ < Icon size = "md" >
871+ < FaSortUp />
872+ </ Icon >
873+ ) ,
874+ desc : (
875+ < Icon size = "md" >
876+ < FaSortDown />
877+ </ Icon >
878+ )
879+ } [ header . column . getIsSorted ( ) as string ] ?? (
872880 < Icon size = "md" >
873- < FaSortUp />
881+ < FaSort />
874882 </ Icon >
875- ) ,
876- desc : (
877- < Icon size = "md" >
878- < FaSortDown />
879- </ Icon >
880- )
881- } [ header . column . getIsSorted ( ) as string ] ?? (
882- < Icon size = "md" >
883- < FaSort />
884- </ Icon >
885- ) }
886- </ Text >
887- ) }
888- </ Table . ColumnHeader >
889- ) ) }
890- </ Table . Row >
891- ) ) }
892- </ Table . Header >
893- < Table . Body >
894- { table . getRowModel ( ) . rows . map ( ( row , idx ) => (
895- < Table . Row key = { row . id } bg = { idx % 2 === 0 ? "bg.subtle" : undefined } >
896- { row . getVisibleCells ( ) . map ( ( cell ) => (
897- < Table . Cell key = { cell . id } p = { 2 } >
898- { flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
899- </ Table . Cell >
900- ) ) }
901- </ Table . Row >
902- ) ) }
903- </ Table . Body >
904- </ Table . Root >
883+ ) }
884+ </ Text >
885+ ) }
886+ </ Table . ColumnHeader >
887+ ) ) }
888+ </ Table . Row >
889+ ) ) }
890+ </ Table . Header >
891+ < Table . Body >
892+ { rowWindow . shouldVirtualize && rowWindow . paddingTop > 0 ? (
893+ < Table . Row >
894+ < Table . Cell colSpan = { columns . length } p = { 0 } border = "none" h = { `${ rowWindow . paddingTop } px` } />
895+ </ Table . Row >
896+ ) : null }
897+ { rowWindow . visibleRows . map ( ( row ) => (
898+ < Table . Row key = { row . id } bg = { row . index % 2 === 0 ? "bg.subtle" : undefined } >
899+ { row . getVisibleCells ( ) . map ( ( cell ) => (
900+ < Table . Cell key = { cell . id } p = { 2 } >
901+ { flexRender ( cell . column . columnDef . cell , cell . getContext ( ) ) }
902+ </ Table . Cell >
903+ ) ) }
904+ </ Table . Row >
905+ ) ) }
906+ { rowWindow . shouldVirtualize && rowWindow . paddingBottom > 0 ? (
907+ < Table . Row >
908+ < Table . Cell colSpan = { columns . length } p = { 0 } border = "none" h = { `${ rowWindow . paddingBottom } px` } />
909+ </ Table . Row >
910+ ) : null }
911+ </ Table . Body >
912+ </ Table . Root >
913+ </ Box >
905914 </ Box >
906915
907916 < Text > { studentData . length } Students</ Text >
0 commit comments