1
1
"use client" ;
2
2
3
- import React , { useRef , useState } from "react" ;
3
+ import React , { useState } from "react" ;
4
4
import axios from "axios" ;
5
- import toast , { Toaster } from "react-hot-toast" ;
5
+ import toast from "react-hot-toast" ;
6
6
import { handleAPIError } from "../../util/error" ;
7
- import { useRouter } from "next/navigation" ;
8
- import { type ApiError } from "next/dist/server/api-utils" ;
9
7
import { Button } from "@/components/ui/button" ;
10
- import { CldUploadWidget } from "next-cloudinary" ;
11
- import { Input } from "@/components/ui/input" ;
8
+ import Navbar from "@/components/Navbar" ;
9
+ import Footer from "@/components/Footer" ;
10
+ import { type PostPDFToCloudinary } from "@/interface" ;
11
+ import { slots , years } from "@/components/select_options" ;
12
+ import SearchBar from "@/components/searchbarSubjectList" ;
13
+ import Dropzone from "react-dropzone" ;
12
14
import {
13
15
Select ,
14
- SelectTrigger ,
15
- SelectValue ,
16
16
SelectContent ,
17
17
SelectGroup ,
18
- SelectLabel ,
19
18
SelectItem ,
19
+ SelectLabel ,
20
+ SelectTrigger ,
21
+ SelectValue ,
20
22
} from "@/components/ui/select" ;
21
- import Navbar from "@/components/Navbar" ;
22
- import Footer from "@/components/Footer" ;
23
- import { PostPDFToCloudinary } from "@/interface" ;
24
- import { courses , slots , years } from "@/components/select_options" ;
25
- import SearchBar from "@/components/searchbarSubjectList" ;
26
- import Dropzone from "react-dropzone" ;
27
23
28
24
const Page = ( ) => {
29
- const fileInputRef = useRef < HTMLInputElement > ( null ) ;
30
-
31
25
const [ slot , setSlot ] = useState ( "" ) ;
32
26
const [ subject , setSubject ] = useState ( "" ) ;
33
27
const [ exam , setExam ] = useState ( "" ) ;
34
28
const [ year , setYear ] = useState ( "" ) ;
35
29
const [ files , setFiles ] = useState < File [ ] > ( [ ] ) ;
36
- const [ inputValue , setInputValue ] = useState ( "" ) ;
37
- const [ isSubjectCommandOpen , setIsSubjectCommandOpen ] = useState ( false ) ;
38
30
const [ isUploading , setIsUploading ] = useState ( false ) ;
39
31
const [ resetSearch , setResetSearch ] = useState ( false ) ;
40
32
@@ -47,8 +39,6 @@ const Page = () => {
47
39
"image/gif" ,
48
40
] ;
49
41
50
- const files = fileInputRef . current ?. files as FileList | null ;
51
-
52
42
if ( ! slot ) {
53
43
toast . error ( "Slot is required" ) ;
54
44
return ;
@@ -65,44 +55,39 @@ const Page = () => {
65
55
toast . error ( "Year is required" ) ;
66
56
return ;
67
57
}
58
+
68
59
if ( ! files || files . length === 0 ) {
69
60
toast . error ( "No files selected" ) ;
70
61
return ;
71
- } else if ( files . length > 5 ) {
72
- toast . error ( "More than 5 files selected" ) ;
73
- return ;
74
62
}
75
63
76
- if ( ! Array . from ( files ) . every ( ( file ) => file . type === files [ 0 ] ?. type ) ) {
77
- toast . error ( `All files MUST be of the same type` ) ;
64
+ if ( files . length > 5 ) {
65
+ toast . error ( "More than 5 files selected" ) ;
78
66
return ;
79
67
}
80
68
81
- for ( const file of files ) {
82
- if ( file . size > maxFileSize ) {
83
- toast . error ( `File ${ file . name } is more than 5MB` ) ;
84
- return ;
85
- }
86
- if ( ! allowedFileTypes . includes ( file . type ) ) {
87
- toast . error (
88
- `File type of ${ file . name } is not allowed. Only PDFs and images are accepted.` ,
89
- ) ;
90
- return ;
91
- }
69
+ // File validations
70
+ const invalidFiles = files . filter (
71
+ ( file ) =>
72
+ file . size > maxFileSize || ! allowedFileTypes . includes ( file . type ) ,
73
+ ) ;
74
+
75
+ if ( invalidFiles . length > 0 ) {
76
+ toast . error (
77
+ `Some files are invalid. Ensure each file is below 5MB and of an allowed type (PDF, JPEG, PNG, GIF).` ,
78
+ ) ;
79
+ return ;
92
80
}
93
81
94
- let isPdf = false ;
95
- if ( files [ 0 ] ?. type === "application/pdf" ) {
96
- isPdf = true ;
97
- if ( files . length > 1 ) {
98
- toast . error ( `PDFs should be uploaded separately` ) ;
99
- return ;
100
- }
82
+ const isPdf = files . length === 1 && files [ 0 ] ?. type === "application/pdf" ;
83
+ if ( isPdf && files . length > 1 ) {
84
+ toast . error ( "PDFs must be uploaded separately" ) ;
85
+ return ;
101
86
}
102
87
103
- const Arrfiles = Array . from ( files ) ;
88
+ // Prepare FormData
104
89
const formData = new FormData ( ) ;
105
- Arrfiles . forEach ( ( file ) => {
90
+ files . forEach ( ( file ) => {
106
91
formData . append ( "files" , file ) ;
107
92
} ) ;
108
93
formData . append ( "subject" , subject ) ;
@@ -113,37 +98,28 @@ const Page = () => {
113
98
114
99
setIsUploading ( true ) ;
115
100
116
- void toast . promise (
117
- ( async ( ) => {
118
- try {
119
- const response = await axios . post < PostPDFToCloudinary > (
120
- "/api/upload" ,
121
- formData ,
122
- ) ;
123
-
124
- setSlot ( "" ) ;
125
- setSubject ( "" ) ;
126
- setExam ( "" ) ;
127
- setYear ( "" ) ;
128
- setFiles ( [ ] ) ;
129
- if ( fileInputRef . current ) {
130
- fileInputRef . current . value = "" ;
131
- }
132
-
133
- setResetSearch ( true ) ;
134
- setTimeout ( ( ) => setResetSearch ( false ) , 100 ) ;
135
- } catch ( error ) {
136
- handleAPIError ( error ) ;
137
- } finally {
138
- setIsUploading ( false ) ;
139
- }
140
- } ) ( ) ,
141
- {
142
- loading : "Uploading papers..." ,
143
- success : "Papers uploaded" ,
144
- error : ( err : ApiError ) => err . message ,
145
- } ,
146
- ) ;
101
+ try {
102
+ await toast . promise (
103
+ axios . post < PostPDFToCloudinary > ( "/api/upload" , formData ) ,
104
+ {
105
+ loading : "Uploading papers..." ,
106
+ success : "Papers uploaded successfully!" ,
107
+ error : "Failed to upload papers. Please try again." ,
108
+ } ,
109
+ ) ;
110
+
111
+ setSlot ( "" ) ;
112
+ setSubject ( "" ) ;
113
+ setExam ( "" ) ;
114
+ setYear ( "" ) ;
115
+ setFiles ( [ ] ) ;
116
+ setResetSearch ( true ) ;
117
+ setTimeout ( ( ) => setResetSearch ( false ) , 100 ) ;
118
+ } catch ( error ) {
119
+ handleAPIError ( error ) ;
120
+ } finally {
121
+ setIsUploading ( false ) ;
122
+ }
147
123
} ;
148
124
149
125
return (
@@ -220,16 +196,14 @@ const Page = () => {
220
196
</ Select >
221
197
</ div >
222
198
199
+ { /* File Dropzone */ }
223
200
< div >
224
201
< Dropzone
225
- onDrop = { ( acceptedFiles ) => {
226
- console . log ( acceptedFiles ) ;
227
- setFiles ( acceptedFiles ) ;
228
- } }
202
+ onDrop = { ( acceptedFiles ) => setFiles ( acceptedFiles ) }
229
203
accept = { { "image/*" : [ ] , "application/pdf" : [ ] } }
230
204
>
231
205
{ ( { getRootProps, getInputProps } ) => (
232
- < section className = " my-2 -mr-2 rounded-2xl border-2 border-dashed p-8 text-center" >
206
+ < section className = "my-2 -mr-2 rounded-2xl border-2 border-dashed p-8 text-center" >
233
207
< div { ...getRootProps ( ) } >
234
208
< input { ...getInputProps ( ) } />
235
209
< p >
0 commit comments