Skip to content

Commit f934a74

Browse files
authored
Merge pull request #198 from CodeChefVIT/staging
PDF full screen and filter fix
2 parents f59b712 + c940efa commit f934a74

File tree

2 files changed

+97
-34
lines changed

2 files changed

+97
-34
lines changed

src/components/CatalogueContent.tsx

+51-31
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,17 @@ export async function downloadFile(url: string, filename: string) {
2929
const CatalogueContent = () => {
3030
const router = useRouter();
3131
const searchParams = useSearchParams();
32-
const subject = searchParams.get("subject");
33-
const exams = searchParams.get("exams")?.split(",");
34-
const slots = searchParams.get("slots")?.split(",");
35-
const years = searchParams.get("years")?.split(",");
36-
const campuses = searchParams.get("campus")?.split(",");
37-
const semesters = searchParams.get("semester")?.split(",");
38-
const answerKeyIncluded =
39-
searchParams.get("answerkey") === "true" ? true : false;
40-
// Initialize state with searchParams
41-
const [selectedExams, setSelectedExams] = useState<string[]>(exams ?? []);
42-
const [selectedSlots, setSelectedSlots] = useState<string[]>(slots ?? []);
43-
const [selectedYears, setSelectedYears] = useState<string[]>(years ?? []);
44-
const [selectedSemesters, setSelectedSemesters] = useState<string[]>(
45-
semesters ?? [],
46-
);
47-
const [selectedCampuses, setSelectedCampuses] = useState<string[]>(
48-
campuses ?? [],
49-
);
32+
const [isMounted, setIsMounted] = useState(false);
33+
34+
// Initialize state with defaults, set later in useEffect
35+
const [subject, setSubject] = useState<string | null>(null);
36+
const [selectedExams, setSelectedExams] = useState<string[]>([]);
37+
const [selectedSlots, setSelectedSlots] = useState<string[]>([]);
38+
const [selectedYears, setSelectedYears] = useState<string[]>([]);
39+
const [selectedSemesters, setSelectedSemesters] = useState<string[]>([]);
40+
const [selectedCampuses, setSelectedCampuses] = useState<string[]>([]);
5041
const [selectedAnswerKeyIncluded, setSelectedAnswerKeyIncluded] =
51-
useState<boolean>(answerKeyIncluded);
42+
useState<boolean>(false);
5243
const [papers, setPapers] = useState<IPaper[]>([]);
5344
const [filteredPapers, setFilteredPapers] = useState<IPaper[]>([]);
5445
const [selectedPapers, setSelectedPapers] = useState<IPaper[]>([]);
@@ -58,12 +49,27 @@ const CatalogueContent = () => {
5849
const [filtersPulled, setFiltersPulled] = useState<boolean>(false);
5950
const [appliedFilters, setAppliedFilters] = useState<boolean>(false);
6051

52+
// Set initial state from searchParams on client-side mount
53+
useEffect(() => {
54+
setIsMounted(true);
55+
if (searchParams) {
56+
setSubject(searchParams.get("subject"));
57+
setSelectedExams(searchParams.get("exams")?.split(",") ?? []);
58+
setSelectedSlots(searchParams.get("slots")?.split(",") ?? []);
59+
setSelectedYears(searchParams.get("years")?.split(",") ?? []);
60+
setSelectedCampuses(searchParams.get("campus")?.split(",") ?? []);
61+
setSelectedSemesters(searchParams.get("semester")?.split(",") ?? []);
62+
setSelectedAnswerKeyIncluded(searchParams.get("answerkey") === "true");
63+
}
64+
}, [searchParams]);
65+
6166
const filtersNotPulled = () => {
6267
setFiltersPulled(false);
6368
};
64-
// Memoized effect to fetch papers
69+
70+
// Fetch papers and apply filters
6571
useEffect(() => {
66-
if (!subject) return;
72+
if (!subject || !isMounted) return;
6773

6874
const fetchPapers = async () => {
6975
setLoading(true);
@@ -75,6 +81,7 @@ const CatalogueContent = () => {
7581
const papersData = data.papers;
7682
setFilterOptions(data);
7783
setPapers(papersData);
84+
// Apply filters from URL params
7885
const filtered = papersData.filter((paper) => {
7986
const examCondition = selectedExams.length
8087
? selectedExams.includes(paper.exam)
@@ -104,23 +111,32 @@ const CatalogueContent = () => {
104111
);
105112
});
106113
setFilteredPapers(filtered.length > 0 ? filtered : papersData);
114+
setAppliedFilters(true);
107115
} catch (error) {
108116
setPapers([]);
109-
if (axios.isAxiosError(error)) {
110-
const axiosError = error as AxiosError<{ message?: string }>;
111-
setError(
112-
axiosError.response?.data?.message ?? "Error fetching papers",
113-
);
114-
} else {
115-
setError("Error fetching papers");
116-
}
117+
const axiosError = error as AxiosError;
118+
setError(
119+
axios.isAxiosError(axiosError)
120+
? ((axiosError.response?.data as { message?: string })?.message ??
121+
"Error fetching papers")
122+
: "Error fetching papers",
123+
);
117124
} finally {
118125
setLoading(false);
119126
}
120127
};
121128

122129
void fetchPapers();
123-
}, [subject]); // Just run on initial page render
130+
}, [
131+
subject,
132+
isMounted,
133+
selectedExams,
134+
selectedSlots,
135+
selectedYears,
136+
selectedSemesters,
137+
selectedCampuses,
138+
selectedAnswerKeyIncluded,
139+
]);
124140

125141
// Memoized handlers
126142
const handleSelectPaper = useCallback(
@@ -213,6 +229,11 @@ const CatalogueContent = () => {
213229
setSelectedPapers([]);
214230
}, []);
215231

232+
// Render loading state until mounted to avoid hydration mismatch
233+
if (!isMounted) {
234+
return <Loader />;
235+
}
236+
216237
return (
217238
<div className="relative flex min-h-screen justify-center p-0 md:justify-normal">
218239
<div className="hidden w-[30%] min-w-fit md:block">
@@ -237,7 +258,6 @@ const CatalogueContent = () => {
237258
/>
238259
</div>
239260

240-
{/* {error && <p className="text-red-500">{error}</p>} */}
241261
<div className="w-full">
242262
<Sheet>
243263
<SheetTrigger className="mx-8 mt-8 block md:hidden">

src/components/pdfViewer.tsx

+46-3
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import "react-pdf/dist/Page/AnnotationLayer.css";
44
import "react-pdf/dist/Page/TextLayer.css";
55
import { useState, useRef, useCallback, useEffect } from "react";
66
import { Document, Page, pdfjs } from "react-pdf";
7-
import { Download, ZoomIn, ZoomOut } from "lucide-react";
7+
import { Download, ZoomIn, ZoomOut, Maximize2, Minimize2 } from "lucide-react";
88
import { Button } from "./ui/button";
99
import { downloadFile } from "./CatalogueContent";
1010
import ShareButton from "./ShareButton";
@@ -25,6 +25,7 @@ export default function PdfViewer({ url, name }: PdfViewerProps) {
2525
const [numPages, setNumPages] = useState<number>();
2626
const [pageNumber, setPageNumber] = useState<number>(1);
2727
const [scale, setScale] = useState<number>(1);
28+
const [isFullscreen, setIsFullscreen] = useState<boolean>(false);
2829
const pageRefs = useRef<(HTMLDivElement | null)[]>([]);
2930
const containerRef = useRef<HTMLDivElement>(null);
3031

@@ -109,14 +110,50 @@ export default function PdfViewer({ url, name }: PdfViewerProps) {
109110
await downloadFile(url, fileName);
110111
};
111112

113+
const toggleFullscreen = () => {
114+
if (!containerRef.current) return;
115+
116+
if (!document.fullscreenElement) {
117+
containerRef.current
118+
.requestFullscreen()
119+
.then(() => {
120+
setIsFullscreen(true);
121+
})
122+
.catch((err) => {
123+
console.error("Error entering fullscreen:", err);
124+
});
125+
} else {
126+
document
127+
.exitFullscreen()
128+
.then(() => {
129+
setIsFullscreen(false);
130+
})
131+
.catch((err) => {
132+
console.error("Error exiting fullscreen:", err);
133+
});
134+
}
135+
};
136+
137+
useEffect(() => {
138+
const handleFullscreenChange = () => {
139+
setIsFullscreen(!!document.fullscreenElement);
140+
};
141+
142+
document.addEventListener("fullscreenchange", handleFullscreenChange);
143+
return () => {
144+
document.removeEventListener("fullscreenchange", handleFullscreenChange);
145+
};
146+
}, []);
147+
112148
return (
113149
<div className="flex flex-col items-center">
114150
<div
115151
ref={containerRef}
116-
className="max-h-[70vh] overflow-auto border border-gray-300 shadow-lg"
152+
className="max-h-[70vh] w-fit overflow-auto bg-[#F3F5FF] shadow-lg dark:bg-[#070114]"
117153
>
118154
<Document
119155
file={url}
156+
className={"w-fit"}
120157
onLoadSuccess={onDocumentLoadSuccess}
121158
error={
122159
<div className="p-4 text-red-500">Failed to load PDF file.</div>
@@ -150,7 +187,7 @@ export default function PdfViewer({ url, name }: PdfViewerProps) {
150187
</Document>
151188
</div>
152189

153-
<div className="mt-4 flex flex-col items-center gap-4 rounded-lg bg-[#262635] p-4 shadow sm:flex-row">
190+
<div className="mt-4 flex flex-col items-center gap-4 rounded-lg bg-[#F3F5FF] p-4 shadow dark:bg-[#262635] sm:flex-row">
154191
<div className="flex items-center gap-2">
155192
<Button
156193
onClick={goToPreviousPage}
@@ -197,6 +234,12 @@ export default function PdfViewer({ url, name }: PdfViewerProps) {
197234
<Button onClick={downloadPDF} className="aspect-square h-10 w-10 p-0">
198235
<Download />
199236
</Button>
237+
<Button
238+
onClick={toggleFullscreen}
239+
className="h-10 w-10 rounded p-0 text-white transition hover:bg-[#6536c1]"
240+
>
241+
{isFullscreen ? <Minimize2 /> : <Maximize2 />}
242+
</Button>
200243
</div>
201244
</div>
202245
</div>

0 commit comments

Comments
 (0)