From 0b792b751c680e04e22d222f4d2fd4e28c69194c Mon Sep 17 00:00:00 2001 From: Juthatip McDevitt Date: Thu, 14 Mar 2024 12:45:33 -0500 Subject: [PATCH] create update page functionality --- real_estate/client/src/App.jsx | 2 + real_estate/client/src/pages/Profile.jsx | 21 +- .../client/src/pages/UpdateListing.jsx | 215 ++++++++++++++++++ .../server/controllers/listing.controller.js | 49 ++++ real_estate/server/routes/listing.route.js | 7 +- 5 files changed, 290 insertions(+), 4 deletions(-) create mode 100644 real_estate/client/src/pages/UpdateListing.jsx diff --git a/real_estate/client/src/App.jsx b/real_estate/client/src/App.jsx index 5bc02a6..4377412 100644 --- a/real_estate/client/src/App.jsx +++ b/real_estate/client/src/App.jsx @@ -7,6 +7,7 @@ import {Profile} from './pages/Profile' import Navbar from './components/Navbar' import PrivateRoute from './components/PrivateRoute' import CreatListing from './pages/CreatListing' +import UpdateListing from './pages/UpdateListing' const App = () => { @@ -18,6 +19,7 @@ const App = () => { }> }/> }/> + }/> }/> }/> diff --git a/real_estate/client/src/pages/Profile.jsx b/real_estate/client/src/pages/Profile.jsx index de9858f..7df5977 100644 --- a/real_estate/client/src/pages/Profile.jsx +++ b/real_estate/client/src/pages/Profile.jsx @@ -122,7 +122,24 @@ export const Profile = () => { setUserListingsError(true); } }; + //delete user listing functionality + const handleListingDelete = async (listingId) => { + try { + const res = await fetch(`/server/listing/delete/${listingId}`, { + method: 'DELETE' + }); + const data = await res.json(); + if(data.success === false){ + return; + } + setUserListings((prev) => + prev.filter((listing) => listing._id !== listingId) + ) + } catch (error) { + console.log(error.message) + } + }; return ( @@ -165,8 +182,8 @@ export const Profile = () => {

{listing.name}

- - + +
))} diff --git a/real_estate/client/src/pages/UpdateListing.jsx b/real_estate/client/src/pages/UpdateListing.jsx new file mode 100644 index 0000000..3ced4e6 --- /dev/null +++ b/real_estate/client/src/pages/UpdateListing.jsx @@ -0,0 +1,215 @@ +import { useEffect, useState } from "react" +import {getDownloadURL, getStorage, ref, uploadBytesResumable} from 'firebase/storage' +import {app} from '../firebase' +import {useSelector} from 'react-redux' +import {useNavigate, useParams} from 'react-router-dom' + + +const UpdateListing = () => { + const {currentUser} = useSelector((state) => state.user) + const navigate =useNavigate(); + const params = useParams(); + const [files, setFiles] = useState([]); + const [formData, setFormData] = useState({ + imageUrls: [], + name: '', + description: '', + address: '', + type: 'rent', + bed: 1, + bath: 1, + currentPrice: 100, + discountPrice: 0, + offer: false, + parking: false, + furnished: false, + }); + const [imageUploadError, setImageUploadError] = useState(false); + const [upload, setUpload] = useState(false); + const [error, setError] = useState(false); + const [loading, setLoading] = useState(false); + useEffect(() => { + const fetchListing = async() => { + const listingId = params.listingId; + const res = await fetch(`/server/listing/get/${listingId}`); + const data = await res.json(); + if(data.success === false){ + setError(data.message); + return; + } + setFormData(data); + }; + fetchListing(); + }, []); + + const handleImageSubmit = (e) => { + if(files.length > 0 && files.length + formData.imageUrls.length < 11){ + setUpload(true); + setImageUploadError(false); + + const promises = []; + for(let i = 0; i < files.length; i++){ + promises.push(storeImage(files[i])); + } + Promise.all(promises).then((urls) => { + setFormData({...formData, imageUrls: formData.imageUrls.concat(urls), + }); + setImageUploadError(false); + setUpload(false); + }).catch((error) => { + setImageUploadError('Image upload failed (2mb max per image)'); + setUpload(false); + }); + }else{ + setImageUploadError('You can upload maximum 10 images'); + setUpload(false); + } + }; + const storeImage = async(file) => { + return new Promise((resolve, reject) => { + const storage = getStorage(app); + const fileName = new Date().getTime() + file.name + const storageRef = ref(storage, fileName); + const uploadTask = uploadBytesResumable(storageRef, file); + uploadTask.on( + "state_changed",(snapshot) => { + const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; + console.log(`Upload is ${progress}% done`) + }, + (error) => { + reject(error); + }, + () => { + getDownloadURL(uploadTask.snapshot.ref).then((downloadURL) => { + resolve(downloadURL) + }); + } + ); + }); + }; + const handleDeleteImage = (index) => { + setFormData({...formData, imageUrls: formData.imageUrls.filter((_, i) => i !== index), + }); + }; + const handleChange = (e) => { + if (e.target.id === 'sale' || e.target.id === 'rent') { + setFormData({...formData, type: e.target.id, }); + } + if(e.target.id === 'parking' || e.target.id === 'furnished' || e.target.id === 'offer'){ + setFormData({...formData, [e.target.id]: e.target.checked, }); + } + if(e.target.type === 'number' || e.target.type === 'text' || e.target.type === 'textarea'){ + setFormData({...formData, [e.target.id]: e.target.value, }); + } + }; + const handleSubmit = async (e) => { + e.preventDefault(); + try { + if(formData.imageUrls.length < 1) + return setError('You need to upload at least one image'); + if (+formData.currentPrice < +formData.discountPrice) + return setError('Discount must be lower than your current price'); + + setLoading(true); + setError(false); + const res = await fetch(`/server/listing/update/${params.listingId}`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({...formData, userRef: currentUser._id,}), + }); + const data = await res.json(); + setLoading(false); + if(data.success === false){ + setError(data.message) + } + navigate(`/listing/${data._id}`) + } catch (error) { + setError(error.message); + setLoading(false); + + } + } + + return ( +
+

Update a listing

+
+
+ +