33import { useState , useEffect , useMemo , useCallback , memo } from "react" ;
44import { useSession } from "next-auth/react" ;
55import { trpc } from "@/lib/trpc" ;
6- import { sheetModules } from "@/data/sheet" ;
76import type { SheetModule } from "@/data/sheet" ;
87import {
98 Table ,
@@ -22,6 +21,7 @@ import { OpensoxProBadge } from "@/components/sheet/OpensoxProBadge";
2221import { ProgressBar } from "@/components/sheet/ProgressBar" ;
2322import { ActiveTag } from "@/components/ui/ActiveTag" ;
2423import { useSubscription } from "@/hooks/useSubscription" ;
24+ import { SheetSkeleton } from "@/components/sheet/SheetSkeleton" ;
2525
2626const tableColumns = [
2727 "S.No" ,
@@ -39,7 +39,7 @@ const SheetTableRow = memo(function SheetTableRow({
3939 onCheckboxChange,
4040 isPaidUser,
4141} : {
42- module : SheetModule ;
42+ module : Omit < SheetModule , "docContent" > ;
4343 index : number ;
4444 isCompleted : boolean ;
4545 onCheckboxChange : ( moduleId : string , checked : boolean ) => void ;
@@ -129,14 +129,35 @@ const SheetTableRow = memo(function SheetTableRow({
129129 </ TableRow >
130130 ) ;
131131} ) ;
132-
133132export default function SheetPage ( ) {
134133 const { data : session , status } = useSession ( ) ;
135134 const { isPaidUser } = useSubscription ( ) ;
136135 const [ completedSteps , setCompletedSteps ] = useState < string [ ] > ( [ ] ) ;
137136 const [ copied , setCopied ] = useState ( false ) ;
137+ const [ sheetModules , setSheetModules ] = useState <
138+ Omit < SheetModule , "docContent" > [ ]
139+ > ( [ ] ) ;
140+ const [ isLoadingModules , setIsLoadingModules ] = useState ( true ) ;
138141 const utils = trpc . useUtils ( ) ;
139142
143+ // fetch modules metadata from api
144+ useEffect ( ( ) => {
145+ async function fetchModules ( ) {
146+ try {
147+ const response = await fetch ( "/api/sheet/modules" ) ;
148+ if ( response . ok ) {
149+ const modules = await response . json ( ) ;
150+ setSheetModules ( modules ) ;
151+ }
152+ } catch ( error ) {
153+ console . error ( "failed to fetch modules:" , error ) ;
154+ } finally {
155+ setIsLoadingModules ( false ) ;
156+ }
157+ }
158+ fetchModules ( ) ;
159+ } , [ ] ) ;
160+
140161 // TypeScript has difficulty narrowing TRPC procedure union types.
141162 // These procedures are correctly typed at runtime (query vs mutation).
142163 const getCompletedStepsProcedure = trpc . user
@@ -215,7 +236,7 @@ export default function SheetPage() {
215236 ) ;
216237
217238 // Memoize computed values
218- const totalModules = useMemo ( ( ) => sheetModules . length , [ ] ) ;
239+ const totalModules = useMemo ( ( ) => sheetModules . length , [ sheetModules ] ) ;
219240 const completedCount = useMemo ( ( ) => completedSteps . length , [ completedSteps ] ) ;
220241
221242 // Memoize download handler
@@ -299,7 +320,7 @@ export default function SheetPage() {
299320 setTimeout ( ( ) => {
300321 printWindow . print ( ) ;
301322 } , 250 ) ;
302- } , [ completedCount , totalModules , completedSteps ] ) ;
323+ } , [ completedCount , totalModules , completedSteps , sheetModules ] ) ;
303324
304325 // Memoize share handler
305326 const handleShare = useCallback ( async ( ) => {
@@ -313,16 +334,11 @@ export default function SheetPage() {
313334 }
314335 } , [ ] ) ;
315336
316- // Show loading only if we're actually loading session OR steps
317- const isLoading =
318- ( status === "loading" || isLoadingSteps ) && ! completedSteps . length ;
337+ // Show loading only if we're actually loading session OR steps OR modules
338+ const isLoading = status === "loading" || isLoadingSteps || isLoadingModules ;
319339
320340 if ( isLoading ) {
321- return (
322- < div className = "w-full p-6 flex items-center justify-center h-[80vh]" >
323- < p className = "text-text-muted" > Loading...</ p >
324- </ div >
325- ) ;
341+ return < SheetSkeleton /> ;
326342 }
327343
328344 return (
0 commit comments