11"use client" ;
22import React , { useRef , useState } from "react" ;
3- import JSZip from "jszip" ;
43import axios from "axios" ;
54import { slots , courses } from "./select_options" ;
65import toast , { Toaster } from "react-hot-toast" ;
@@ -31,7 +30,6 @@ import Footer from "@/components/Footer";
3130
3231const Page = ( ) => {
3332 const router = useRouter ( ) ;
34- // const [openCamera, setOpenCamera] = useState(false);
3533 const fileInputRef = useRef < HTMLInputElement > ( null ) ;
3634
3735 const [ slot , setSlot ] = useState ( "" ) ;
@@ -40,45 +38,61 @@ const Page = () => {
4038 const [ year , setYear ] = useState ( "" ) ;
4139 const [ files , setFiles ] = useState < File [ ] > ( [ ] ) ;
4240 const [ inputValue , setInputValue ] = useState ( '' )
43-
4441 const [ isSubjectCommandOpen , setIsSubjectCommandOpen ] = useState ( false ) ;
45- // const toggleOpenCamera = () => {
46- // setOpenCamera((prev) => !prev);
47- // };
42+ const [ isUploading , setIsUploading ] = useState ( false ) ;
4843
4944 const handlePrint = async ( ) => {
50- // file validation
5145 const maxFileSize = 5 * 1024 * 1024 ;
46+ const allowedFileTypes = [ "application/pdf" , "image/jpeg" , "image/png" , "image/gif" ] ;
5247 const files = fileInputRef . current ?. files as FileList | null ;
53- if ( ! files || files . length == 0 ) {
48+
49+ if ( ! slot ) {
50+ toast . error ( "Slot is required" ) ;
51+ return ;
52+ }
53+ if ( ! subject ) {
54+ toast . error ( "Subject is required" ) ;
55+ return ;
56+ }
57+ if ( ! exam ) {
58+ toast . error ( "Exam is required" ) ;
59+ return ;
60+ }
61+ if ( ! year ) {
62+ toast . error ( "Year is required" ) ;
63+ return ;
64+ }
65+ if ( ! files || files . length === 0 ) {
5466 toast . error ( "No files selected" ) ;
5567 return ;
5668 } else if ( files . length > 5 ) {
5769 toast . error ( "More than 5 files selected" ) ;
5870 return ;
5971 }
72+
6073 for ( const file of files ) {
6174 if ( file . size > maxFileSize ) {
6275 toast . error ( `File ${ file . name } is more than 5MB` ) ;
6376 return ;
6477 }
78+
79+ if ( ! allowedFileTypes . includes ( file . type ) ) {
80+ toast . error ( `File type of ${ file . name } is not allowed. Only PDFs and images are accepted.` ) ;
81+ return ;
82+ }
6583 }
66- const zip = new JSZip ( ) ;
84+
6785 const formData = new FormData ( ) ;
68-
6986 for ( const file of files ) {
70- zip . file ( file . name , file ) ;
71- const content = await zip . generateAsync ( { type : "blob" } ) ;
72-
73- const arrayBuffer = await new Response ( content ) . arrayBuffer ( ) ;
74- const uint8Array = new Uint8Array ( arrayBuffer ) ;
75-
76- formData . append ( "zipFile" , new Blob ( [ uint8Array ] ) , "files.zip" ) ;
77- formData . append ( "slot" , slot ) ;
78- formData . append ( "subject" , subject ) ;
79- formData . append ( "exam" , exam ) ;
80- formData . append ( "year" , year ) ;
87+ formData . append ( "files" , file ) ;
8188 }
89+ formData . append ( "slot" , slot ) ;
90+ formData . append ( "subject" , subject ) ;
91+ formData . append ( "exam" , exam ) ;
92+ formData . append ( "year" , year ) ;
93+
94+ setIsUploading ( true ) ; // Set uploading to true
95+
8296 try {
8397 const result = await toast . promise (
8498 ( async ( ) => {
@@ -90,28 +104,28 @@ const Page = () => {
90104 headers : {
91105 "Content-Type" : "multipart/form-data" ,
92106 } ,
93- } ,
107+ }
94108 ) ;
95109 return response . data ;
96110 } catch ( error ) {
97- handleAPIError ( error ) ;
111+ throw handleAPIError ( error ) ;
98112 }
99113 } ) ( ) ,
100114 {
101115 loading : "Sending papers" ,
102116 success : "Papers successfully sent" ,
103117 error : ( err : ApiError ) => err . message ,
104- } ,
118+ }
105119 ) ;
120+
106121 if ( result ?. message === "Email sent successfully!" ) {
107- setTimeout ( ( ) => {
108- router . push ( "/" ) ;
109- } , 1500 ) ;
110122 }
111123 } catch ( e ) {
124+ } finally {
125+ setIsUploading ( false ) ;
112126 }
113127 } ;
114-
128+
115129 const handleSubjectSelect = ( value : string ) => {
116130 setSubject ( value ) ;
117131 setInputValue ( value )
@@ -169,30 +183,6 @@ const Page = () => {
169183 { /* Subject Selection */ }
170184 < div >
171185 < label > Subject:</ label >
172- { /* <div className="relative">
173- <Button
174- type="button"
175- onClick={() => setIsSubjectCommandOpen((prev) => !prev)}
176- className="m-2 rounded-md border p-2"
177- >
178- {subject || "Select subject"}
179- </Button>
180- {isSubjectCommandOpen && (
181- <Command className="absolute z-10 mt-2 w-full rounded-lg border shadow-md">
182- <CommandInput placeholder="Search subject..." />
183- <CommandList>
184- <CommandEmpty>No subjects found.</CommandEmpty>
185- <CommandGroup heading="Subjects">
186- {courses.map((course) => (
187- <CommandItem key={course} onSelect={() => handleSubjectSelect(course)}>
188- <span>{course}</span>
189- </CommandItem>
190- ))}
191- </CommandGroup>
192- </CommandList>
193- </Command>
194- )}
195- </div> */ }
196186 < Command className = "rounded-lg border shadow-md md:min-w-[450px]" >
197187 < CommandInput
198188 value = { inputValue }
@@ -249,7 +239,7 @@ const Page = () => {
249239 < Input
250240 required
251241 type = "file"
252- accept = "image/*,.pdf"
242+ // accept="image/*,.pdf"
253243 multiple
254244 ref = { fileInputRef }
255245 className = "hidden"
@@ -261,7 +251,7 @@ const Page = () => {
261251 < div >
262252 < Button
263253 type = "button"
264- onClick = { ( ) => fileInputRef . current ?. click ( ) } // Trigger file input on button click
254+ onClick = { ( ) => fileInputRef . current ?. click ( ) }
265255 className = "rounded-md px-4 py-2 transition"
266256 >
267257 Choose files
@@ -277,9 +267,10 @@ const Page = () => {
277267 </ fieldset >
278268 < Button
279269 onClick = { handlePrint }
280- className = "w-fit rounded-md px-4 py-3"
270+ disabled = { isUploading }
271+ className = { `w-fit rounded-md px-4 py-3 ${ isUploading ? "bg-gray-300" : "" } ` }
281272 >
282- Upload Papers
273+ { isUploading ? "Uploading..." : " Upload Papers" }
283274 </ Button >
284275 </ div >
285276 < div className = "" >
0 commit comments