This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
This post is part of a new series where we build a clone of Airbnb with Next.js. See the first post here.
One thing we miss now in the new house form, and when editing an existing house, is being able to upload images.
We are currently limited by uploading an image somewhere, and pasting the URL in the form. Not very practical for our users!
Let’s add this functionality.
Before we start, we must add an npm package, called express-fileupload
:
npm install express-fileupload
and we add it as a middleware to Express, in server.js
:
const fileupload = require('express-fileupload')
server.use(
//...
fileupload()
)
This is needed because otherwise the server can’t parse file uploads.
Next, in components/HouseForm.js
, change the current input field that we used:
<p>
<label>House picture URL</label>
<input required onChange={event => setPicture(event.target.value)} type='text'
placeholder='House picture URL' value={picture} />
</p>
to this combo of a file upload and an image visualizer:
<p>
<label>House picture</label>
<input type="file" id="fileUpload" />
{picture ? <img src="{picture}" width="200" alt="House image" /> : ''}
</p>
If you try to reload the page, the file picker should be there! Let’s add input[type=file]
to the CSS styling for forms we already have at the bottom:
<style jsx > {
` input[type='number'],
input[type='file'],
select,
textarea {
/*... */
}
}
Let’s also limit the file input to only accept images:
<input type="file" id="fileUpload" accept="image/*" />
See https://flaviocopes.com/how-to-accept-images-file-input/
Now we must handle the change
event on this input field:
<input
type='file'
id='fileUpload'
accept='image/*'
onChange={async (event) => {
const files = event.target.files
const formData = new FormData()
formData.append('image', files[0])
const response = await axios.post('/api/host/image', formData)
setPicture('http://localhost:3000' + response.data.path)
}}
/>
This is invoked when the file input changes (an image had been selected). In there, we get the image from event.target.files
and we POST it to /host/image
, a new endpoint we’re going to make next.
We expect a path
property coming back, which will be the URL of our image, and we assign it using the setPicture
hook update function.
Let’s now make the POST /api/host/image
endpoint in server.js
.
We first check if the user is logged in, and we get the image from the request:
server.js
server.post('/api/host/image', (req, res) => {
if (!req.session.passport) {
res.writeHead(403, {
'Content-Type': 'application/json',
})
res.end(
JSON.stringify({
status: 'error',
message: 'Unauthorized',
})
)
return
}
const image = req.files.image
})
Next we run npm install randomstring
and we import that module:
const randomstring = require('randomstring')
we need it to generate a random string for our image, since users might submit images with the same name. I’m just going to prepend a random string to the image original name, but in the real world you might want to completely randomize it, and also check if you don’t already have that name before overwriting the file:
const fileName = randomstring.generate(7) + image.name.replace(/\s/g, '')
const path = __dirname + '/public/img/' + fileName
Then we call the mv
property of the uploaded image. That is provided to us by the express-fileupload
module. We move it to path
and then we communicate the success (or an error!) back to the client:
image.mv(path, (error) => {
if (error) {
console.error(error)
res.writeHead(500, {
'Content-Type': 'application/json',
})
res.end(JSON.stringify({ status: 'error', message: error }))
return
}
res.writeHead(200, {
'Content-Type': 'application/json',
})
res.end(JSON.stringify({ status: 'success', path: '/img/' + fileName }))
})
This is the complete code for our /api/host/image
endpoint:
server.post('/api/host/image', (req, res) => {
if (!req.session.passport) {
res.writeHead(403, {
'Content-Type': 'application/json',
})
res.end(
JSON.stringify({
status: 'error',
message: 'Unauthorized',
})
)
return
}
const image = req.files.image
const fileName = randomstring.generate(7) + image.name.replace(/\s/g, '')
const path = __dirname + '/public/img/' + fileName
image.mv(path, (error) => {
if (error) {
console.error(error)
res.writeHead(500, {
'Content-Type': 'application/json',
})
res.end(JSON.stringify({ status: 'error', message: error }))
return
}
res.writeHead(200, {
'Content-Type': 'application/json',
})
res.end(JSON.stringify({ status: 'success', path: '/img/' + fileName }))
})
})
Now you should be able to successfully submit a new image for the house, and also update existing houses images!
Awesome, we reached the end of the project!
On an application like this, we had a lot of things to build.
We also have lots of things we still miss, just to provide a basic house booking marketplace to our users.
On the top of my mind, we currently miss adding communication between host and guests, allowing to add multiple images and manage the gallery, managing superhosts, allowing different prices for different dates, blocking out days..
We’d need one year to complete all that.
Maybe in a future sequel!
This content originally appeared on flaviocopes.com and was authored by flaviocopes.com
flaviocopes.com | Sciencx (2022-01-09T05:00:00+00:00) Airbnb clone, upload the house image. Retrieved from https://www.scien.cx/2022/01/09/airbnb-clone-upload-the-house-image/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.