@@ -23,9 +23,10 @@ function PinnedPapersCarousel() {
2323 const [ displayPapers , setDisplayPapers ] = useState < IUpcomingPaper [ ] > ( [ ] ) ;
2424 useEffect ( ( ) => {
2525 const handleResize = ( ) => {
26- if ( window . innerWidth <= 540 ) {
26+ if ( window . innerWidth <= 540 ) {
2727 setChunkSize ( 2 ) ;
28- } else if ( window . innerWidth <= 920 ) {
28+ }
29+ else if ( window . innerWidth <= 920 ) {
2930 setChunkSize ( 4 ) ;
3031 } else {
3132 setChunkSize ( 8 ) ;
@@ -47,9 +48,7 @@ function PinnedPapersCarousel() {
4748 { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ,
4849 ] ;
4950 } else {
50- chunkedPapers . push ( [
51- { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ,
52- ] ) ;
51+ chunkedPapers . push ( [ { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ] ) ;
5352 }
5453 }
5554
@@ -97,41 +96,42 @@ function PinnedPapersCarousel() {
9796 } , [ ] ) ;
9897
9998 useEffect ( ( ) => {
100- const handleSubjectsChange = ( ) => {
101- void ( async ( ) => {
102- try {
103- const storedSubjects = JSON . parse (
104- localStorage . getItem ( "userSubjects" ) ?? "[]" ,
105- ) as StoredSubjects ;
106-
107- const response = await axios . post <
108- { subject : string ; slots : string [ ] } [ ]
109- > ( "/api/user-papers" , storedSubjects ) ;
110-
111- const fetchedPapers = response . data ;
112-
113- const fetchedSubjectsSet = new Set (
114- fetchedPapers . map ( ( paper ) => paper . subject ) ,
115- ) ;
116-
117- const storedSubjectsArray = Array . isArray ( storedSubjects )
118- ? storedSubjects
119- : [ ] ;
120- const missingSubjects = storedSubjectsArray
121- . filter ( ( subject : string ) => ! fetchedSubjectsSet . has ( subject ) )
122- . map ( ( subject : string ) => ( {
123- subject,
124- slots : [ ] ,
125- } ) ) as { subject : string ; slots : string [ ] } [ ] ;
126-
127- const allDisplayPapers = [ ...fetchedPapers , ...missingSubjects ] ;
128-
129- setDisplayPapers ( allDisplayPapers ) ;
130- } catch ( error ) {
131- console . error ( "Failed to fetch papers:" , error ) ;
132- }
133- } ) ( ) ;
134- } ;
99+ const handleSubjectsChange = ( ) => {
100+ void ( async ( ) => {
101+ try {
102+ const storedSubjects = JSON . parse (
103+ localStorage . getItem ( "userSubjects" ) ?? "[]" ,
104+ ) as StoredSubjects ;
105+
106+ const response = await axios . post < { subject : string ; slots : string [ ] } [ ] > (
107+ "/api/user-papers" ,
108+ storedSubjects ,
109+ ) ;
110+
111+ const fetchedPapers = response . data ;
112+
113+ const fetchedSubjectsSet = new Set (
114+ fetchedPapers . map ( ( paper ) => paper . subject ) ,
115+ ) ;
116+
117+ const storedSubjectsArray = Array . isArray ( storedSubjects )
118+ ? storedSubjects
119+ : [ ] ;
120+ const missingSubjects = storedSubjectsArray
121+ . filter ( ( subject : string ) => ! fetchedSubjectsSet . has ( subject ) )
122+ . map ( ( subject : string ) => ( {
123+ subject,
124+ slots : [ ] ,
125+ } ) ) as { subject : string ; slots : string [ ] } [ ] ;
126+
127+ const allDisplayPapers = [ ...fetchedPapers , ...missingSubjects ] ;
128+
129+ setDisplayPapers ( allDisplayPapers ) ;
130+ } catch ( error ) {
131+ console . error ( "Failed to fetch papers:" , error ) ;
132+ }
133+ } ) ( ) ;
134+ } ;
135135
136136 window . addEventListener ( "userSubjectsChanged" , handleSubjectsChange ) ;
137137
@@ -143,102 +143,83 @@ function PinnedPapersCarousel() {
143143 const plugins = [ Autoplay ( { delay : 8000 , stopOnInteraction : true } ) ] ;
144144
145145 return (
146- < div className = "mt-8 px-4 md:mt-4" >
146+ < div className = "px-4 mt-8 md:mt-4" >
147147 < div className = "" >
148- { displayPapers . length > 0 ? (
149- < Carousel
150- opts = { {
151- align : "start" ,
152- loop : true ,
153- } }
154- plugins = { plugins }
155- className = "w-full"
156- >
157- { ( ( ) => {
158- const totalItems = displayPapers . length + 1 ;
159- const needsNav = totalItems > chunkSize ;
160- return needsNav ? (
161- < div className = "relative mt-4 flex justify-end gap-4" >
162- < CarouselPrevious className = "relative" />
163- < CarouselNext className = "relative" />
164- </ div >
165- ) : null ;
166- } ) ( ) }
167- < CarouselContent >
168- { isLoading ? (
169- < CarouselItem
170- className = { `grid ${
171- chunkSize === 2
172- ? "grid-cols-1 grid-rows-2"
173- : chunkSize === 4
174- ? "grid-cols-2 grid-rows-2"
175- : "grid-cols-4"
176- } gap-4 lg:auto-rows-fr`}
177- >
178- < SkeletonPaperCard length = { chunkSize } />
179- </ CarouselItem >
180- ) : (
181- chunkedPapers . map ( ( paperGroup , index ) => {
182- const placeholdersNeeded =
183- ( chunkSize - paperGroup . length ) % chunkSize ;
184- return (
185- < CarouselItem
186- key = { `carousel-item-${ index } ` }
187- className = { `grid ${
188- chunkSize === 2
189- ? "grid-cols-1 grid-rows-2"
190- : chunkSize === 4
191- ? "grid-cols-2 grid-rows-2"
192- : "grid-cols-4"
193- } gap-4 lg:auto-rows-fr`}
194- >
195- { paperGroup . map ( ( paper , subIndex ) =>
196- paper . subject === "add_subject_button" ? (
197- < div
198- key = { subIndex }
199- className = "h-full rounded-sm border border-dashed border-[#734DFF] bg-[#FFFFFF] font-bold hover:bg-[#EFEAFF] dark:border-[#36266D] dark:bg-transparent dark:hover:bg-[#1A1823]"
200- >
201- < PinnedModal
202- triggerName = { "Add Subjects" }
203- page = { "Carousel" }
204- />
205- </ div >
206- ) : (
207- < div key = { subIndex } className = "h-full" >
208- < UpcomingPaper
209- subject = { paper . subject }
210- slots = { paper . slots }
211- />
212- </ div >
213- ) ,
214- ) }
215-
216- { Array . from ( { length : placeholdersNeeded } ) . map (
217- ( _ , placeholderIndex ) => (
218- < div
219- key = { `placeholder-${ placeholderIndex } ` }
220- className = "invisible h-full"
221- > </ div >
222- ) ,
223- ) }
224- </ CarouselItem >
225- ) ;
226- } )
227- ) }
228- </ CarouselContent >
229- </ Carousel >
230- ) : (
231- < div
232- className = { `relative flex flex-col items-center justify-center gap-4 text-center font-bold` }
233- >
234- Start pinning subjects for quick and easy access.
235- < div className = "flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base" >
236- < span className = "truncate" >
237- < PinnedModal />
238- </ span >
239- </ div >
148+ { displayPapers . length > 0 ?
149+ < Carousel
150+ opts = { {
151+ align : "start" ,
152+ loop : true ,
153+ } }
154+ plugins = { plugins }
155+ className = "w-full"
156+ >
157+ { ( ( ) => {
158+ const totalItems = displayPapers . length + 1 ;
159+ const needsNav = totalItems > chunkSize ;
160+ return needsNav ? (
161+ < div className = "relative mt-4 flex justify-end gap-4" >
162+ < CarouselPrevious className = "relative" />
163+ < CarouselNext className = "relative" />
164+ </ div >
165+ ) : null ;
166+ } ) ( ) }
167+ < CarouselContent >
168+ { isLoading ? (
169+ < CarouselItem
170+ className = { `grid ${
171+ chunkSize === 2 ? "grid-cols-1 grid-rows-2" : chunkSize === 4 ? "grid-cols-2 grid-rows-2" : "grid-cols-4"
172+ } gap-4 lg:auto-rows-fr`}
173+ >
174+ < SkeletonPaperCard length = { chunkSize } />
175+ </ CarouselItem >
176+ ) : (
177+ chunkedPapers . map ( ( paperGroup , index ) => {
178+ const placeholdersNeeded = ( chunkSize - paperGroup . length ) % chunkSize ;
179+ return (
180+ < CarouselItem
181+ key = { `carousel-item-${ index } ` }
182+ className = { `grid ${
183+ chunkSize === 2 ? "grid-cols-1 grid-rows-2" : chunkSize === 4 ? "grid-cols-2 grid-rows-2" : "grid-cols-4"
184+ } gap-4 lg:auto-rows-fr`}
185+ >
186+ { paperGroup . map ( ( paper , subIndex ) => (
187+ paper . subject === "add_subject_button" ?
188+ < div key = { subIndex } className = "h-full border-dashed border border-[#734DFF] dark:border-[#36266D] rounded-sm font-bold hover:bg-[#EFEAFF] dark:bg-transparent dark:hover:bg-[#1A1823] bg-[#FFFFFF]" >
189+ < PinnedModal triggerName = { "Add Subjects" } page = { "Carousel" } />
190+ </ div >
191+ :
192+ < div key = { subIndex } className = "h-full" >
193+ < UpcomingPaper
194+ subject = { paper . subject }
195+ slots = { paper . slots }
196+ />
197+ </ div >
198+ ) ) }
199+
200+ { Array . from ( { length : placeholdersNeeded } ) . map (
201+ ( _ , placeholderIndex ) => (
202+ < div
203+ key = { `placeholder-${ placeholderIndex } ` }
204+ className = "invisible h-full"
205+ > </ div >
206+ ) ,
207+ ) }
208+ </ CarouselItem >
209+ ) ;
210+ } )
211+ ) }
212+ </ CarouselContent >
213+ </ Carousel > :
214+ < div className = { `relative flex flex-col justify-center gap-4 items-center text-center font-bold` }
215+ >
216+ Start pinning subjects for quick and easy access.
217+ < div className = "flex h-8 items-center gap-1 rounded-full border border-[#3A3745] bg-[#e8e9ff] px-2.5 py-1 text-xs font-semibold text-gray-700 transition hover:bg-slate-50 dark:bg-black dark:text-white dark:hover:bg-[#1A1823] sm:h-9 sm:gap-2 sm:px-3.5 sm:py-1.5 sm:text-sm md:h-10 md:px-4 md:py-2 md:text-base" >
218+ < span className = "truncate" >
219+ < PinnedModal />
220+ </ span >
240221 </ div >
241- ) }
222+ </ div > }
242223 </ div >
243224 </ div >
244225 ) ;
0 commit comments