having a similar issue with req.file being undefined. It looks like the image file is available up until the hook useFormSubmit
wraps it in the formData
object and sends the formData
request to the router/controller
.
However even just sending the image using the body, nothing comes through from the hook to the controller. I've included images of the console logs for the status of the data from the component to the controller below, would appreciate any guidance on this:
Things I've tried:
-Sending the form in incognito to avoid cookies or caching
-Sending reviewImage
data in the body itself without wrapping it in formData.append
-including the multer
middleWare directly in the router
and controller
-pulling the image from req.body instead of req.file
CreateReview.tsx
//hooks
import {useFormSubmit} from '../../Hooks/useFormSubmit'
//dependencies
import { useForm, SubmitHandler } from "react-hook-form";
export const CreateReview = () => {
const { register, handleSubmit, formState: { errors } } = useForm<ReviewInputs>();
const {createReview, error, isLoading} = useFormSubmit()
const onSubmit: SubmitHandler<ReviewInputs> = async (data) => {
const userID = user
const title: string = data.title
const review: string = data.review
const artist: string = data.artist
const author: string = data.author
const authorBand: string = data.authorBand
const banner: string = data.banner
const reviewImage: any = data.reviewImage[0]
await createReview(title, review, artist, userID, author, authorBand, banner, reviewImage)
navigate('/adminReviews')
}
return (
<>
<Form onSubmit={handleSubmit(onSubmit)} encType="multipart/form-data">
<Form.Label>Create A Review</Form.Label>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Title</Form.Label>
<Form.Control type="text" placeholder="Title" {...register('title', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Artist</Form.Label>
<Form.Control type="text" placeholder="Artist" {...register('artist', {required: true })} {...register} />
</Form.Group>
<Form.Group className="mb-3" controlId="exampleForm.ControlInput1">
<Form.Label>Author</Form.Label>
<Form.Control type="text" placeholder="Author" {...register('author', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Author Band</Form.Label>
<Form.Control type="text" placeholder="Author Band" {...register('authorBand', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Upload An Image</Form.Label>
<Form.Control type="file" placeholder="Upload" {...register('reviewImage', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Banner</Form.Label>
<Form.Control type="text" placeholder="Banner" {...register('banner', {required: true })} {...register} />
</Form.Group>
<Form.Group>
<Form.Label>Review</Form.Label>
<Form.Control as="textarea" rows={12} {...register('review', {required: true })} {...register} />
<>{errors.review?.message}</>
</Form.Group>
<Row>
<Col xs={12}>
<Button type='submit'>Submit</Button>
</Col>
</Row>
</Form>
useFormSubmit
export const useFormSubmit = () => {
const {dispatch} = useReviewsContext()
const [error, setError] = useState(null)
const [isLoading, setIsLoading] = useState(false)
const createReview = async (title, review, artist, userID, author, authorBand, banner, reviewImage) => {
const formData = new FormData();
formData.append("reviewImage", reviewImage);
setIsLoading(true)
setError(null)
const response = await fetch('http://localhost:8080/api/admin/', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({title, review, artist, userID, author, authorBand, banner, formData })
})
const jsonResponse = await response.json()
if(!response.ok) {
setIsLoading(false)
setError(jsonResponse.error)
}
if(response.ok) {
setIsLoading(false)
dispatch({type: 'CREATE_REVIEW', payload: jsonResponse})
}
}
adminMiddleware.js
const multer = require('multer')
const storage = multer.diskStorage({
destination: (req, file, callback) => {
callback(null, '../../client/public/images')
},
filename: (req, file, callback) => {
callback(null, file.originalname)
}
})
const upload = multer({storage: storage})
module.exports = upload;
adminRoutes.js
const express = require('express')
const router = express.Router();
const upload = require('../middleware/adminMiddleware')
//controllers
const { createReview } = require('../controllers/reviewsController')
//CRUD reviews routes
router.post('/', upload.single('reviewImage'), createReview)
module.exports = router;
reviewsController.js
const createReview = async (req, res) => {
const {title, review, artist, userID, author, authorBand, banner} = req.body
const reviewImage = req.file.reviewImage
let emptyFields = []
if(!title) {
emptyFields.push('title')
}
if(!review) {
emptyFields.push('review')
}
if(!artist) {
emptyFields.push('artist')
}
if(!userID) {
emptyFields.push('userID')
}
if(!author) {
emptyFields.push('author')
}
if(!authorBand) {
emptyFields.push('authorBand')
}
if(!banner) {
emptyFields.push('banner')
}
if(!reviewImage) {
emptyFields.push('reviewImage')
}
if(emptyFields.length > 0) {
return res.status(400).json({ error: 'Please fill in all the fields', emptyFields })
}
// add doc to db
try {
const createdReview = await Review.create({title, review, artist, userID, author, authorBand, banner, reviewImage})
res.status(200).json(createdReview)
} catch (error) {
res.status(400).json({error: error.message})
}
}
Error Messages / Console logs
