This has been giving me a lot of headache: In my FileUploader component, I am facing this issue.
import React, { useState } from 'react';
import { Accept, useDropzone } from 'react-dropzone';
import { UploadCloud } from 'lucide-react';
import { cn } from '@/lib/utils';
interface FileUploaderProps {
onUpload: (file: File) => void,
acceptedFileType: Accept,
restrictionText: string,
buttonTextTitle: string,
}
const FileUploader = ({
onUpload,
acceptedFileType,
restrictionText,
buttonTextTitle
}: FileUploaderProps) => {
const [fileChange, setFileChange] = useState(false)
const [isValidFileType, setIsValidFileType] = useState(false)
const { getRootProps, getInputProps, acceptedFiles} = useDropzone({
accept: acceptedFileType,
maxFiles:1,
onDrop: (acceptedFiles) => {
setFileChange(true)
if(acceptedFiles.length > 0){
setIsValidFileType(true)
}else{
setIsValidFileType(false)
}
},
validator: fileSizeValidator
});
function bytesToMegabytes(bytes: number) {
const megabytes = bytes / (1024 * 1024);
return parseFloat(megabytes.toFixed(2)); // Truncate to two decimal places
}
function fileSizeValidator(file: File) {
let fileInMB = bytesToMegabytes(file.size)
if (fileInMB > 2048) {
return {
code: "size-to-long",
message: `Your file size has exceeded the max size of 2 GB.`
};
}
return null
}
const keysAsString = Object.keys(acceptedFileType).join(', ');
const files = () => {
if(acceptedFiles.length > 0){
const tt = acceptedFiles.map((file) => {
return (
<div key={file.name}>
<div className='flex flex-col justify-center'>
<p className='text-xs text-slate-500 text-center truncate-custom'>{file.name}</p>
<p className='text-xs text-slate-500 text-center'>{bytesToMegabytes(file.size)} MB</p>
</div>
</div>
)
});
return tt
}else{
return (
<div className='flex flex-col justify-center'>
<p className="text-xs text-red-500">{`Invalid file type, Only ${keysAsString} are accepted`}</p>
</div>
)
}
}
const handleFile = async () => {
const formData = new FormData();
formData.append('file', acceptedFiles[0]);
try {
const response = await fetch('/api/courses/0549c28d', {
method: 'POST',
body: formData,
});
if (response.ok) {
alert('File uploaded successfully');
} else {
alert('Error uploading file');
}
} catch (error) {
alert(error);
}
}
return (
<div className="border-2 border-slate-400 border-dotted rounded-md flex flex-col items-center justify-center h-60">
<div>
<div {...getRootProps({ className: 'dropzone' })}>
<input {...getInputProps()} />
<div className='flex justify-center'>
<UploadCloud height={35} width={35} className='text-gray-500'/>
</div>
<div className={cn(
"flex justify-center",
fileChange && "my-4"
)}>
<p className='text-sky-500 font-bold cursor-pointer'>Choose files or drag and drop</p>
</div>
{fileChange ? <div>{files()}</div> : <p className='text-xs text-slate-500 text-center'>{restrictionText}</p>}
</div>
</div>
<div>
{fileChange && (
<div className="flex justify-center">
<button type="button"
onClick={handleFile}
className={cn(
"rounded-lg bg-sky-500 py-2 px-4 m-4 text-white",
!isValidFileType && "disabled:opacity-50"
)}
disabled={!isValidFileType}
>
{buttonTextTitle}
</button>
</div>
)}
</div>
</div>
);
};
export default FileUploader;
At this level I think something is wrong with the way I am passing the data.
Actually I am expecting the user to drop or select a valid valid file first.
Then I show a button that says upload your iamge. Once clicked I want to upload the file now to the server and save in the "/public/uploads"
directory.
Now on the server side of my nextjs app I have this:
import { NextResponse } from 'next/server'
import { IncomingForm } from 'formidable';
import fs from 'fs';
import path from 'path';
import { NextApiRequest, NextApiResponse } from 'next';
export async function POST(
req: NextApiRequest,
res: NextApiResponse,
){
try {
const form = new IncomingForm();
form.parse(req, async (err, fields, files) => {
if (err) {
console.log('Error parsing form:', err)
return new NextResponse("Internal errror",{ status: 500 })
}
console.log(files);
return NextResponse.json({ success: true })
const file = files.file;
if (!file) {
return new NextResponse("No file provided",{ status: 400 })
}
// Move the uploaded file to the desired directory (/public/uploads)
const oldPath = file.path;
const newPath = path.join(process.cwd(), 'public/uploads', file.name);
fs.renameSync(oldPath, newPath);
// Handle the file, e.g., save it to disk or process it
return NextResponse.json({ success: true })
});
} catch (error) {
console.log("[DATA_ID]", error)
return new NextResponse("Internal errror",{ status: 500 })
}
}
As from here I have been trying for almost a day. I cannot succeed to file uploaded.
I event try using the multer package
. it seams the file is not getting at the server side successfully.
PLease I will really appreciate any assistance you can help me achiving this goal, which is to upload files in a nextjs13 app either using a free package or not
.
Thanks in advance