Skip to content

Commit e4c0a63

Browse files
fix carousel grid
1 parent 2ea904f commit e4c0a63

1 file changed

Lines changed: 0 additions & 267 deletions

File tree

Lines changed: 0 additions & 267 deletions
Original file line numberDiff line numberDiff line change
@@ -1,267 +0,0 @@
1-
"use client";
2-
3-
import { useEffect, useState } from "react";
4-
import axios from "axios";
5-
import { type IUpcomingPaper } from "@/interface";
6-
import UpcomingPaper from "./UpcomingPaper";
7-
import {
8-
Carousel,
9-
CarouselContent,
10-
CarouselItem,
11-
CarouselNext,
12-
CarouselPrevious,
13-
} from "@/components/ui/carousel";
14-
import Autoplay from "embla-carousel-autoplay";
15-
import { chunkArray } from "@/lib/utils/array";
16-
import { type StoredSubjects } from "@/interface";
17-
import SkeletonPaperCard from "./SkeletonPaperCard";
18-
import PinnedModal from "./ui/PinnedModal";
19-
20-
function PinnedPapersCarousel() {
21-
const [isLoading, setIsLoading] = useState(true);
22-
const [chunkSize, setChunkSize] = useState<number>(4);
23-
const [displayPapers, setDisplayPapers] = useState<IUpcomingPaper[]>([]);
24-
useEffect(() => {
25-
const handleResize = () => {
26-
if (window.innerWidth <= 540) {
27-
setChunkSize(2);
28-
} else if (window.innerWidth <= 920) {
29-
setChunkSize(4);
30-
} else {
31-
setChunkSize(8);
32-
}
33-
};
34-
35-
handleResize(); // initialize
36-
window.addEventListener("resize", handleResize);
37-
return () => window.removeEventListener("resize", handleResize);
38-
}, []);
39-
40-
const chunkedPapers = chunkArray(displayPapers, chunkSize);
41-
42-
if (chunkedPapers.length > 0) {
43-
const lastChunkIndex = chunkedPapers.length - 1;
44-
if ((chunkedPapers[lastChunkIndex]?.length ?? 0) < chunkSize) {
45-
chunkedPapers[lastChunkIndex] = [
46-
...(chunkedPapers[lastChunkIndex] ?? []),
47-
{ subject: "add_subject_button", slots: [] } as IUpcomingPaper,
48-
];
49-
} else {
50-
chunkedPapers.push([
51-
{ subject: "add_subject_button", slots: [] } as IUpcomingPaper,
52-
]);
53-
}
54-
}
55-
56-
const fetchPapers = async () => {
57-
try {
58-
setIsLoading(true);
59-
60-
const storedSubjects = JSON.parse(
61-
localStorage.getItem("userSubjects") ?? "[]",
62-
) as StoredSubjects;
63-
64-
const response = await axios.post<{ subject: string; slots: string[] }[]>(
65-
"/api/user-papers",
66-
storedSubjects,
67-
);
68-
69-
const fetchedPapers = response.data;
70-
71-
const fetchedSubjectsSet = new Set(
72-
fetchedPapers.map((paper) => paper.subject),
73-
);
74-
75-
const storedSubjectsArray = Array.isArray(storedSubjects)
76-
? storedSubjects
77-
: [];
78-
const missingSubjects = storedSubjectsArray
79-
.filter((subject: string) => !fetchedSubjectsSet.has(subject))
80-
.map((subject: string) => ({
81-
subject,
82-
slots: [],
83-
})) as { subject: string; slots: string[] }[];
84-
85-
const allDisplayPapers = [...fetchedPapers, ...missingSubjects];
86-
87-
allDisplayPapers.sort((a, b) => {
88-
const aIndex = storedSubjects.indexOf(a.subject);
89-
const bIndex = storedSubjects.indexOf(b.subject);
90-
91-
return (
92-
(aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) -
93-
(bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex)
94-
);
95-
});
96-
97-
setDisplayPapers(allDisplayPapers);
98-
} catch (error) {
99-
console.error("Failed to fetch papers:", error);
100-
} finally {
101-
setIsLoading(false);
102-
}
103-
};
104-
105-
useEffect(() => {
106-
void fetchPapers();
107-
}, []);
108-
109-
useEffect(() => {
110-
const handleSubjectsChange = () => {
111-
void (async () => {
112-
try {
113-
const storedSubjects = JSON.parse(
114-
localStorage.getItem("userSubjects") ?? "[]",
115-
) as StoredSubjects;
116-
117-
const response = await axios.post<
118-
{ subject: string; slots: string[] }[]
119-
>("/api/user-papers", storedSubjects);
120-
121-
const fetchedPapers = response.data;
122-
123-
const fetchedSubjectsSet = new Set(
124-
fetchedPapers.map((paper) => paper.subject),
125-
);
126-
127-
const storedSubjectsArray = Array.isArray(storedSubjects)
128-
? storedSubjects
129-
: [];
130-
const missingSubjects = storedSubjectsArray
131-
.filter((subject: string) => !fetchedSubjectsSet.has(subject))
132-
.map((subject: string) => ({
133-
subject,
134-
slots: [],
135-
})) as { subject: string; slots: string[] }[];
136-
137-
const allDisplayPapers = [...fetchedPapers, ...missingSubjects];
138-
139-
allDisplayPapers.sort((a, b) => {
140-
const aIndex = storedSubjects.indexOf(a.subject);
141-
const bIndex = storedSubjects.indexOf(b.subject);
142-
143-
return (
144-
(aIndex === -1 ? Number.MAX_SAFE_INTEGER : aIndex) -
145-
(bIndex === -1 ? Number.MAX_SAFE_INTEGER : bIndex)
146-
);
147-
});
148-
149-
setDisplayPapers(allDisplayPapers);
150-
} catch (error) {
151-
console.error("Failed to fetch papers:", error);
152-
}
153-
})();
154-
};
155-
156-
window.addEventListener("userSubjectsChanged", handleSubjectsChange);
157-
158-
return () => {
159-
window.removeEventListener("userSubjectsChanged", handleSubjectsChange);
160-
};
161-
}, []);
162-
163-
const plugins = [Autoplay({ delay: 8000, stopOnInteraction: true })];
164-
165-
return (
166-
<div className="mt-8 px-4 md:mt-4">
167-
<div className="">
168-
{displayPapers.length > 0 ? (
169-
<Carousel
170-
opts={{
171-
align: "start",
172-
loop: true,
173-
}}
174-
plugins={plugins}
175-
className="w-full"
176-
>
177-
{(() => {
178-
const totalItems = displayPapers.length + 1;
179-
const needsNav = totalItems > chunkSize;
180-
return needsNav ? (
181-
<div className="relative mt-4 flex justify-end gap-4">
182-
<CarouselPrevious className="relative" />
183-
<CarouselNext className="relative" />
184-
</div>
185-
) : null;
186-
})()}
187-
<CarouselContent>
188-
{isLoading ? (
189-
<CarouselItem
190-
className={`grid ${
191-
chunkSize === 2
192-
? "grid-cols-1 grid-rows-2"
193-
: chunkSize === 4
194-
? "grid-cols-2 grid-rows-2"
195-
: "grid-cols-4"
196-
} gap-4 lg:auto-rows-fr`}
197-
>
198-
<SkeletonPaperCard length={chunkSize} />
199-
</CarouselItem>
200-
) : (
201-
chunkedPapers.map((paperGroup, index) => {
202-
const placeholdersNeeded =
203-
(chunkSize - paperGroup.length) % chunkSize;
204-
return (
205-
<CarouselItem
206-
key={`carousel-item-${index}`}
207-
className={`grid ${
208-
chunkSize === 2
209-
? "grid-cols-1 grid-rows-2"
210-
: chunkSize === 4
211-
? "grid-cols-2 grid-rows-2"
212-
: "grid-cols-4"
213-
} gap-4 lg:auto-rows-fr`}
214-
>
215-
{paperGroup.map((paper, subIndex) =>
216-
paper.subject === "add_subject_button" ? (
217-
<div
218-
key={subIndex}
219-
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]"
220-
>
221-
<PinnedModal
222-
triggerName={"Add Subjects"}
223-
page={"Carousel"}
224-
/>
225-
</div>
226-
) : (
227-
<div key={subIndex} className="h-full">
228-
<UpcomingPaper
229-
subject={paper.subject}
230-
slots={paper.slots}
231-
/>
232-
</div>
233-
),
234-
)}
235-
236-
{Array.from({ length: placeholdersNeeded }).map(
237-
(_, placeholderIndex) => (
238-
<div
239-
key={`placeholder-${placeholderIndex}`}
240-
className="invisible h-full"
241-
></div>
242-
),
243-
)}
244-
</CarouselItem>
245-
);
246-
})
247-
)}
248-
</CarouselContent>
249-
</Carousel>
250-
) : (
251-
<div
252-
className={`relative flex flex-col items-center justify-center gap-4 text-center font-bold`}
253-
>
254-
Start pinning subjects for quick and easy access.
255-
<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">
256-
<span className="truncate">
257-
<PinnedModal />
258-
</span>
259-
</div>
260-
</div>
261-
)}
262-
</div>
263-
</div>
264-
);
265-
}
266-
267-
export default PinnedPapersCarousel;

0 commit comments

Comments
 (0)