@@ -23,10 +23,9 @@ 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- }
29- else if ( window . innerWidth <= 920 ) {
28+ } else if ( window . innerWidth <= 920 ) {
3029 setChunkSize ( 4 ) ;
3130 } else {
3231 setChunkSize ( 8 ) ;
@@ -48,7 +47,9 @@ function PinnedPapersCarousel() {
4847 { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ,
4948 ] ;
5049 } else {
51- chunkedPapers . push ( [ { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ] ) ;
50+ chunkedPapers . push ( [
51+ { subject : "add_subject_button" , slots : [ ] } as IUpcomingPaper ,
52+ ] ) ;
5253 }
5354 }
5455
@@ -96,42 +97,41 @@ function PinnedPapersCarousel() {
9697 } , [ ] ) ;
9798
9899 useEffect ( ( ) => {
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- } ;
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+ } ;
135135
136136 window . addEventListener ( "userSubjectsChanged" , handleSubjectsChange ) ;
137137
@@ -143,83 +143,102 @@ function PinnedPapersCarousel() {
143143 const plugins = [ Autoplay ( { delay : 8000 , stopOnInteraction : true } ) ] ;
144144
145145 return (
146- < div className = "px-4 mt-8 md:mt-4" >
146+ < div className = "mt-8 px-4 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 ? "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 >
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 >
221240 </ div >
222- </ div > }
241+ ) }
223242 </ div >
224243 </ div >
225244 ) ;
0 commit comments