1
1
"use client" ;
2
-
3
2
import React , { useState } from "react" ;
4
3
import axios from "axios" ;
5
4
import toast from "react-hot-toast" ;
@@ -8,26 +7,46 @@ import { Button } from "@/components/ui/button";
8
7
import Navbar from "@/components/Navbar" ;
9
8
import Footer from "@/components/Footer" ;
10
9
import { type PostPDFToCloudinary } from "@/interface" ;
11
- import { slots , years , campuses , semesters , exams } from "@/components/select_options" ;
12
- import SearchBar from "@/components/searchbarSubjectList" ;
13
10
import Dropzone from "react-dropzone" ;
14
- import {
15
- Select ,
16
- SelectContent ,
17
- SelectGroup ,
18
- SelectItem ,
19
- SelectLabel ,
20
- SelectTrigger ,
21
- SelectValue ,
22
- } from "@/components/ui/select" ;
11
+
12
+ import { createCanvas } from "canvas" ;
13
+ import { getDocument , GlobalWorkerOptions } from "pdfjs-dist" ;
14
+ import { PDFDocument } from "pdf-lib" ;
15
+ async function pdfToImage ( file : File ) {
16
+ GlobalWorkerOptions . workerSrc =
17
+ "https://unpkg.com/[email protected] /build/pdf.worker.min.js" ;
18
+
19
+ const pdfDoc = await PDFDocument . load ( await file . arrayBuffer ( ) ) ;
20
+
21
+ // Get the first page
22
+ const page = pdfDoc . getPages ( ) [ 0 ] ;
23
+ if ( ! page ) {
24
+ throw "First page not found" ;
25
+ }
26
+ // Create a canvas to render the image
27
+ const canvas = createCanvas ( page . getWidth ( ) , page . getHeight ( ) ) ;
28
+ const context = canvas . getContext ( "2d" ) ;
29
+
30
+ // Use pdfjs-dist to render the page
31
+ const pdfjsDoc = await getDocument ( { data : await file . arrayBuffer ( ) } )
32
+ . promise ;
33
+ const pdfPage = await pdfjsDoc . getPage ( 1 ) ;
34
+
35
+ // Render page to canvas
36
+ const viewport = pdfPage . getViewport ( { scale : 1 } ) ;
37
+ await pdfPage . render ( { canvasContext : context , viewport } ) . promise ;
38
+
39
+ // Convert the canvas to the desired output (Buffer, base64, etc.)
40
+ return canvas . toDataURL ( ) ; // Returns a Base64 string
41
+ }
23
42
24
43
const Page = ( ) => {
25
- const [ slot , setSlot ] = useState ( "" ) ;
26
- const [ subject , setSubject ] = useState ( "" ) ;
27
- const [ exam , setExam ] = useState ( "" ) ;
28
- const [ year , setYear ] = useState ( "" ) ;
29
44
const [ campus , setCampus ] = useState ( "Vellore" ) ;
30
- const [ semester , setSemester ] = useState ( "" ) ;
45
+
46
+ const [ files , setFiles ] = useState < File [ ] > ( [ ] ) ;
47
+
48
+ const [ isUploading , setIsUploading ] = useState ( false ) ;
49
+ const [ , setResetSearch ] = useState ( false ) ;
31
50
function fileCheckAndSelect < T extends File > ( acceptedFiles : T [ ] ) {
32
51
const maxFileSize = 5 * 1024 * 1024 ;
33
52
const allowedFileTypes = [
@@ -77,91 +96,31 @@ const Page = () => {
77
96
} ) ;
78
97
return ;
79
98
}
80
-
81
- const orderedFiles = files . sort ( ( a , b ) => {
99
+ const orderedFiles = acceptedFiles . sort ( ( a , b ) => {
82
100
return a . lastModified - b . lastModified ;
83
101
} ) ;
84
102
setFiles ( orderedFiles ) ;
85
103
toast . success ( `${ orderedFiles . length } files selected!` , {
86
104
id : toastId ,
87
105
} ) ;
88
106
}
89
- const [ files , setFiles ] = useState < File [ ] > ( [ ] ) ;
90
- const [ isUploading , setIsUploading ] = useState ( false ) ;
91
- const [ resetSearch , setResetSearch ] = useState ( false ) ;
92
-
93
107
const handlePrint = async ( ) => {
94
- const maxFileSize = 5 * 1024 * 1024 ;
95
- const allowedFileTypes = [
96
- "application/pdf" ,
97
- "image/jpeg" ,
98
- "image/png" ,
99
- "image/gif" ,
100
- ] ;
101
-
102
- if ( ! slot ) {
103
- toast . error ( "Slot is required" ) ;
104
- return ;
105
- }
106
- if ( ! subject ) {
107
- toast . error ( "Subject is required" ) ;
108
- return ;
109
- }
110
- if ( ! exam ) {
111
- toast . error ( "Exam is required" ) ;
112
- return ;
113
- }
114
- if ( ! year ) {
115
- toast . error ( "Year is required" ) ;
116
- return ;
117
- }
118
108
if ( ! campus ) {
119
109
setCampus ( "Vellore" ) ;
120
110
}
121
111
122
- if ( ! semester ) {
123
- toast . error ( "Semester is required" ) ;
124
- return ;
125
- }
126
- if ( ! files || files . length === 0 ) {
127
- toast . error ( "No files selected" ) ;
128
- return ;
129
- }
130
-
131
- if ( files . length > 5 ) {
132
- toast . error ( "More than 5 files selected" ) ;
133
- return ;
134
- }
135
-
136
- // File validations
137
- const invalidFiles = files . filter (
138
- ( file ) =>
139
- file . size > maxFileSize || ! allowedFileTypes . includes ( file . type ) ,
140
- ) ;
141
-
142
- if ( invalidFiles . length > 0 ) {
143
- toast . error (
144
- `Some files are invalid. Ensure each file is below 5MB and of an allowed type (PDF, JPEG, PNG, GIF).` ,
145
- ) ;
146
- return ;
147
- }
148
-
149
112
const isPdf = files . length === 1 && files [ 0 ] ?. type === "application/pdf" ;
150
- if ( isPdf && files . length > 1 ) {
151
- toast . error ( "PDFs must be uploaded separately" ) ;
152
- return ;
153
- }
154
113
155
114
// Prepare FormData
156
115
const formData = new FormData ( ) ;
157
116
files . forEach ( ( file ) => {
158
117
formData . append ( "files" , file ) ;
159
118
} ) ;
160
- formData . append ( "subject" , subject ) ;
161
- formData . append ( "slot" , slot ) ;
162
- formData . append ( "year " , year ) ;
163
- formData . append ( "exam" , exam ) ;
164
- formData . append ( "semester " , semester ) ;
119
+
120
+ if ( isPdf && files [ 0 ] ) {
121
+ formData . append ( "image " , await pdfToImage ( files [ 0 ] ) ) ;
122
+ }
123
+ // formData.append("exam ", exam );
165
124
formData . append ( "campus" , campus ) ;
166
125
167
126
formData . append ( "isPdf" , String ( isPdf ) ) ;
@@ -170,18 +129,18 @@ const Page = () => {
170
129
171
130
try {
172
131
await toast . promise (
173
- axios . post < PostPDFToCloudinary > ( "/api/upload" , formData ) ,
132
+ axios . post < PostPDFToCloudinary > ( "/api/ai- upload" , formData ) ,
174
133
{
175
134
loading : "Uploading papers..." ,
176
135
success : "Papers uploaded successfully!" ,
177
136
error : "Failed to upload papers. Please try again." ,
178
137
} ,
179
138
) ;
180
139
181
- setSlot ( "" ) ;
182
- setSubject ( "" ) ;
183
- setExam ( "" ) ;
184
- setYear ( "" ) ;
140
+ // setSlot("");
141
+ // setSubject("");
142
+ // setExam("");
143
+ // setYear("");
185
144
setFiles ( [ ] ) ;
186
145
setResetSearch ( true ) ;
187
146
setTimeout ( ( ) => setResetSearch ( false ) , 100 ) ;
@@ -199,104 +158,14 @@ const Page = () => {
199
158
</ div >
200
159
< div className = "2xl:my-15 flex flex-col items-center" >
201
160
< fieldset className = "mb-4 w-[350px] rounded-lg border-2 border-gray-300 p-4 pr-8" >
202
- < legend className = "text-lg font-bold" > Select paper parameters </ legend >
161
+ { /* <legend className="text-lg font-bold">Upload papers </legend> */ }
203
162
204
163
< div className = "flex w-full flex-col 2xl:gap-y-4" >
205
- { /* Slot Selection */ }
206
- < div >
207
- < label > Slot:</ label >
208
- < Select value = { slot } onValueChange = { setSlot } >
209
- < SelectTrigger className = "m-2 rounded-md border p-2" >
210
- < SelectValue placeholder = "Select slot" />
211
- </ SelectTrigger >
212
- < SelectContent >
213
- < SelectGroup >
214
- < SelectLabel > Slots</ SelectLabel >
215
- { slots . map ( ( slot ) => (
216
- < SelectItem key = { slot } value = { slot } >
217
- { slot }
218
- </ SelectItem >
219
- ) ) }
220
- </ SelectGroup >
221
- </ SelectContent >
222
- </ Select >
223
- </ div >
224
-
225
- { /* Exam Selection */ }
226
- < div >
227
- < label > Exam:</ label >
228
- < Select value = { exam } onValueChange = { setExam } >
229
- < SelectTrigger className = "m-2 rounded-md border p-2" >
230
- < SelectValue placeholder = "Select exam" />
231
- </ SelectTrigger >
232
- < SelectContent >
233
- < SelectGroup >
234
- < SelectLabel > Exams</ SelectLabel >
235
- { exams . map ( ( exam ) => (
236
- < SelectItem key = { exam } value = { String ( exam ) } >
237
- { exam }
238
- </ SelectItem >
239
- ) ) } { " " }
240
- </ SelectGroup >
241
- </ SelectContent >
242
- </ Select >
243
- </ div >
244
-
245
- { /* Subject Selection */ }
246
- < div >
247
- < label > Subject:</ label >
248
- < SearchBar setSubject = { setSubject } resetSearch = { resetSearch } />
249
- </ div >
250
-
251
- { /* Year Selection */ }
252
- < div >
253
- < label > Year:</ label >
254
- < Select value = { year } onValueChange = { setYear } >
255
- < SelectTrigger className = "m-2 rounded-md border p-2" >
256
- < SelectValue placeholder = "Select year" />
257
- </ SelectTrigger >
258
- < SelectContent >
259
- < SelectGroup >
260
- < SelectLabel > Years</ SelectLabel >
261
- { years . map ( ( year ) => (
262
- < SelectItem key = { year } value = { String ( year ) } >
263
- { year }
264
- </ SelectItem >
265
- ) ) }
266
- </ SelectGroup >
267
- </ SelectContent >
268
- </ Select >
269
- </ div >
270
-
271
- { /* Year Selection */ }
272
-
273
- < div >
274
- < label > Semester Selection:</ label >
275
- < Select value = { semester } onValueChange = { setSemester } >
276
- < SelectTrigger className = "m-2 rounded-md border p-2" >
277
- < SelectValue placeholder = "Select semester" />
278
- </ SelectTrigger >
279
- < SelectContent >
280
- < SelectGroup >
281
- < SelectLabel > Semester</ SelectLabel >
282
- { semesters . map ( ( semester ) => (
283
- < SelectItem key = { semester } value = { String ( semester ) } >
284
- { semester }
285
- </ SelectItem >
286
- ) ) }
287
- </ SelectGroup >
288
- </ SelectContent >
289
- </ Select >
290
- </ div >
291
-
292
164
{ /* File Dropzone */ }
293
165
< div >
294
- < Dropzone
295
- onDrop = { ( acceptedFiles ) => setFiles ( acceptedFiles ) }
296
- accept = { { "image/*" : [ ] , "application/pdf" : [ ] } }
297
- >
166
+ < Dropzone onDrop = { fileCheckAndSelect } >
298
167
{ ( { getRootProps, getInputProps } ) => (
299
- < section className = "my-2 -mr-2 rounded-2xl border-2 border-dashed p-8 text-center" >
168
+ < section className = "my-2 -mr-2 cursor-pointer rounded-2xl border-2 border-dashed p-8 text-center" >
300
169
< div { ...getRootProps ( ) } >
301
170
< input { ...getInputProps ( ) } />
302
171
< p >
0 commit comments