From 4b0a86b0dc3155f7fe079d5c7fe4064251a805fd Mon Sep 17 00:00:00 2001 From: Juthatip McDevitt Date: Fri, 15 Mar 2024 20:19:28 -0500 Subject: [PATCH] completed search funtionality --- real_estate/client/src/App.jsx | 2 + .../client/src/components/ListingCard.jsx | 26 +++ real_estate/client/src/components/Search.jsx | 32 ++++ real_estate/client/src/pages/Home.jsx | 7 +- .../client/src/pages/SearchProperties.jsx | 153 ++++++++++++++++++ 5 files changed, 215 insertions(+), 5 deletions(-) create mode 100644 real_estate/client/src/components/ListingCard.jsx create mode 100644 real_estate/client/src/components/Search.jsx create mode 100644 real_estate/client/src/pages/SearchProperties.jsx diff --git a/real_estate/client/src/App.jsx b/real_estate/client/src/App.jsx index 2b2cd9a..abf25d3 100644 --- a/real_estate/client/src/App.jsx +++ b/real_estate/client/src/App.jsx @@ -9,6 +9,7 @@ import PrivateRoute from './components/PrivateRoute' import CreatListing from './pages/CreatListing' import UpdateListing from './pages/UpdateListing' import Listing from './pages/Listing' +import SearchProperties from './pages/SearchProperties' const App = () => { @@ -23,6 +24,7 @@ const App = () => { }/> }/> + }/> }/> }/> }/> diff --git a/real_estate/client/src/components/ListingCard.jsx b/real_estate/client/src/components/ListingCard.jsx new file mode 100644 index 0000000..ce9efe2 --- /dev/null +++ b/real_estate/client/src/components/ListingCard.jsx @@ -0,0 +1,26 @@ +import {Link} from 'react-router-dom' + +const ListingCard = ({listing}) => { + return ( +
+ + +
+

+ ${listing.offer ? listing.discountPrice.toLocaleString('en-Us') : listing.currentPrice.toLocaleString('en-Us')} + {listing.type === 'rent' && '/month'} +

+
+

{listing.bed} bds |

+

{listing.bath} ba

+
+
+

{listing.address}

+
+
+ +
+ ) +} + +export default ListingCard \ No newline at end of file diff --git a/real_estate/client/src/components/Search.jsx b/real_estate/client/src/components/Search.jsx new file mode 100644 index 0000000..c21714a --- /dev/null +++ b/real_estate/client/src/components/Search.jsx @@ -0,0 +1,32 @@ +import { IoIosSearch } from "react-icons/io"; +import { useNavigate } from "react-router-dom"; +import { useEffect, useState } from "react"; + +const Search = () => { + const navigate = useNavigate(); + const [searchTerm, setSearchTerm] = useState(''); + const handleSubmit = (e) => { + e.preventDefault(); + const urlParams = new URLSearchParams(window.location.search); + urlParams.set('searchTerm', searchTerm); + const searchQuery = urlParams.toString(); + navigate(`/search?${searchQuery}`); + }; + useEffect(() => { + const urlParams = new URLSearchParams(location.search); + const searchTermFormUrl = urlParams.get('searchTerm'); + if(searchTermFormUrl){ + setSearchTerm(searchTermFormUrl); + } + }, [location.search]) + return ( +
+ setSearchTerm(e.target.value)} className="px-4 py-3 focus:outline-none bg-transparent text-sm w-60 sm:w-80"/> + +
+ ) +} + +export default Search \ No newline at end of file diff --git a/real_estate/client/src/pages/Home.jsx b/real_estate/client/src/pages/Home.jsx index 75f9a53..d278ef7 100644 --- a/real_estate/client/src/pages/Home.jsx +++ b/real_estate/client/src/pages/Home.jsx @@ -1,4 +1,4 @@ -import { IoIosSearch } from "react-icons/io"; +import Search from "../components/Search" const Home = () => { return ( @@ -8,10 +8,7 @@ const Home = () => {

Chicago properties for sale

Lorem ipsum dolor sit, amet consectetur adipisicing elit.
Alias dolorem error atque aut, asperiores et tempore iste quaerat pariatur maxime?

-
- - - +
diff --git a/real_estate/client/src/pages/SearchProperties.jsx b/real_estate/client/src/pages/SearchProperties.jsx new file mode 100644 index 0000000..b0b2f78 --- /dev/null +++ b/real_estate/client/src/pages/SearchProperties.jsx @@ -0,0 +1,153 @@ +import { useEffect, useState } from "react" +import { useNavigate } from "react-router-dom"; +import ListingCard from "../components/ListingCard"; + + +const SearchProperties = () => { + const navigate = useNavigate(); + const [loading, setLoading] = useState(false); + const [listings, setListings] = useState([]); + const [sidebarSearch, setSidebarSearch] = useState({ + searchTerm: '', + type: 'all', + parking: false, + offer: false, + furnished: false, + sort: 'created_at', + order: 'desc', + }); + useEffect(() => { + const urlParams = new URLSearchParams(location.search); + const searchTermFromUrl = urlParams.get('searchTerm'); + const typeFromUrl = urlParams.get('type'); + const parkingFromUrl = urlParams.get('parking'); + const furnishedFromUrl = urlParams.get('furnished'); + const offerFromUrl = urlParams.get('offer'); + const sortFromUrl = urlParams.get('sort'); + const orderFromUrl = urlParams.get('order'); + if(searchTermFromUrl || typeFromUrl || parkingFromUrl || furnishedFromUrl || offerFromUrl || sortFromUrl || orderFromUrl){ + setSidebarSearch({ + searchTerm: searchTermFromUrl || '', + type: typeFromUrl || 'all', + parking: parkingFromUrl === 'true' ? true : false, + furnished: furnishedFromUrl === 'true' ? true : false, + offer: offerFromUrl === 'true' ? true : false, + sort: sortFromUrl || 'created_at', + order: orderFromUrl || 'desc', + }); + } + const fetchListings = async () => { + setLoading(true); + const searchQuery = urlParams.toString(); + const res = await fetch(`/server/listing/get?${searchQuery}`); + const data = await res.json(); + setListings(data); + setLoading(false); + }; + fetchListings(); + + }, [location.search]) + + //Search by... + const handleChange = (e) => { + if(e.target.id === 'all' || e.target.id === 'rent' || e.target.id === 'sale'){ + setSidebarSearch({...sidebarSearch, type: e.target.id}); + } + if(e.target.id === 'searchTerm'){ + setSidebarSearch({...sidebarSearch, searchTerm: e.target.value}); + } + if(e.target.id === 'parking' || e.target.id === 'furnished' || e.target.id === 'offer'){ + setSidebarSearch({...sidebarSearch, [e.target.id]: e.target.checked || e.target.checked === 'true' ? true : false,}); + } + if(e.target.id === 'sort_order') { + const sort = e.target.value.split('_')[0] || 'created_at'; + const order = e.target.value.split('_')[1] || 'desc'; + setSidebarSearch({ ...sidebarSearch, sort, order }); + } + }; + + //Submit form + const handleSubmit = (e) => { + e.preventDefault(); + const urlParams = new URLSearchParams(); + urlParams.set('searchTerm', sidebarSearch.searchTerm); + urlParams.set('type', sidebarSearch.type); + urlParams.set('parking', sidebarSearch.parking); + urlParams.set('furnished', sidebarSearch.furnished); + urlParams.set('offer', sidebarSearch.offer); + urlParams.set('sort', sidebarSearch.sort); + urlParams.set('order', sidebarSearch.order); + const searchQuery = urlParams.toString(); + navigate(`/search?${searchQuery}`); + }; + + + return ( +
+
+
+
+ + +
+
+ +
+ + Rent & Sale +
+
+ + Rent +
+
+ + Sale +
+
+ + Offer +
+
+ +
+ +
+ + Garage +
+
+ + Furnished +
+
+ +
+ + +
+ +
+
+
+

Listing results

+
+ {!loading && listings.length === 0 &&( +

No listing found

+ )} + {loading && ( +

loading...

+ )} + {!loading && listings && listings.map((listing) => ())} +
+
+
+ ) +} + +export default SearchProperties \ No newline at end of file