done
This commit is contained in:
parent
252e91fc77
commit
d54bcdb9c5
|
@ -103,11 +103,37 @@ export const updatePropertyById = async (req, res) => {
|
|||
}
|
||||
};
|
||||
|
||||
// export const getProperties = async (req, res) => {
|
||||
// try {
|
||||
// const properties = await PropertyModal.find(); // Fetch all properties from MongoDB
|
||||
// res.status(200).json(properties);
|
||||
// } catch (error) {
|
||||
// res.status(500).json({ message: "Server error" });
|
||||
// }
|
||||
// };
|
||||
|
||||
|
||||
// controllers/propertyController.js
|
||||
export const getProperties = async (req, res) => {
|
||||
try {
|
||||
const properties = await PropertyModal.find(); // Fetch all properties from MongoDB
|
||||
res.status(200).json(properties);
|
||||
} catch (error) {
|
||||
res.status(500).json({ message: "Server error" });
|
||||
const { page = 1, limit = 10 } = req.query;
|
||||
const skip = (page - 1) * limit;
|
||||
const totalProperties = await PropertyModal.countDocuments();
|
||||
const properties = await PropertyModal.find()
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(skip)
|
||||
.limit(parseInt(limit));
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: properties,
|
||||
totalPages: Math.ceil(totalProperties / limit),
|
||||
currentPage: parseInt(page), // Include the currentPage in the response
|
||||
});
|
||||
} catch (err) {
|
||||
res.status(500).json({ success: false, message: 'Server error' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -45,7 +45,7 @@
|
|||
|
||||
|
||||
|
||||
<script type="module" crossorigin src="/assets/index-D1RcI06_.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-DJmr6ji6.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-DepkKhoc.css">
|
||||
</head>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import { useEffect, useState } from "react";
|
|||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { useParams } from "react-router-dom";
|
||||
import { fetchPropertyById } from "../redux/features/propertySlice";
|
||||
import propertydummy from "../img/propertydummy.jpg";
|
||||
import propertydummy from "../img/propertydummy.jpg"
|
||||
import Navbar from "./Navbar";
|
||||
import Footer from "./Footer";
|
||||
|
||||
|
@ -48,16 +48,37 @@ const PropertyView = () => {
|
|||
<div className="row">
|
||||
<div className="col-md-5 mt-3">
|
||||
<div className="bg-white border">
|
||||
{/* {selectedProperty.images && selectedProperty.images[0] && (
|
||||
<img
|
||||
src={propertydummy}
|
||||
className="w-70"
|
||||
alt="Img"
|
||||
src={selectedProperty.images[0].file || propertydummy}
|
||||
alt="Property Thumbnail"
|
||||
style={{ width: "100px", height: "auto" }}
|
||||
/>
|
||||
)} */}
|
||||
|
||||
{selectedProperty.images && selectedProperty.images[0] ? (
|
||||
<img
|
||||
src={selectedProperty.images[0].file || propertydummy}
|
||||
alt="Property Thumbnail"
|
||||
style={{
|
||||
marginTop: "0px",
|
||||
maxWidth: "450px",
|
||||
maxHeight: "450px",
|
||||
maxWidth: "500px",
|
||||
maxHeight: "500px",
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={propertydummy}
|
||||
alt="Default Property Thumbnail"
|
||||
style={{
|
||||
marginTop: "0px",
|
||||
maxWidth: "500px",
|
||||
maxHeight: "500px",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-md-7 mt-3">
|
||||
|
|
|
@ -1,39 +1,52 @@
|
|||
import { useEffect, useState } from "react";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { getProperties } from "../redux/features/propertySlice"; // Redux action to fetch properties
|
||||
import profilepic from "../img/propertydummy.jpg";
|
||||
import { NavLink } from "react-router-dom";
|
||||
import Navbar from "./Navbar";
|
||||
import Footer from "./Footer";
|
||||
import "../searchmysqlresults.css";
|
||||
|
||||
const SearchProperties = () => {
|
||||
const dispatch = useDispatch();
|
||||
const { properties, loading } = useSelector((state) => state.property); // Get loading and properties state from Redux
|
||||
const [searchTerm, setSearchTerm] = useState(""); // For storing search keyword
|
||||
const { properties, loading, totalPages, currentPage } = useSelector(
|
||||
(state) => state.property
|
||||
);
|
||||
const [keyword, setKeyword] = useState("");
|
||||
const [filteredProperties, setFilteredProperties] = useState([]);
|
||||
|
||||
// Dispatch getProperties to load properties on mount
|
||||
useEffect(() => {
|
||||
dispatch(getProperties());
|
||||
}, [dispatch]);
|
||||
// Set pagination state
|
||||
const [page, setPage] = useState(1);
|
||||
const limit = 10; // Number of results per page
|
||||
|
||||
console.log("properties", properties);
|
||||
|
||||
// Filter properties based on search term
|
||||
// Dispatch getProperties to load properties on page change
|
||||
useEffect(() => {
|
||||
if (searchTerm) {
|
||||
const filtered = properties.filter((property) =>
|
||||
property.details.toLowerCase().includes(searchTerm.toLowerCase())
|
||||
dispatch(getProperties({ page, limit }));
|
||||
}, [dispatch, page]);
|
||||
|
||||
// Filter properties based on the keyword entered
|
||||
useEffect(() => {
|
||||
if (keyword.trim()) {
|
||||
setFilteredProperties(
|
||||
properties.filter((property) =>
|
||||
property.address.toLowerCase().includes(keyword.toLowerCase())
|
||||
)
|
||||
);
|
||||
setFilteredProperties(filtered);
|
||||
} else {
|
||||
setFilteredProperties(properties); // Show all properties if no search term
|
||||
setFilteredProperties(properties); // Show all properties when no keyword
|
||||
}
|
||||
}, [searchTerm, properties]);
|
||||
}, [keyword, properties]);
|
||||
|
||||
const handleSearch = (e) => {
|
||||
if (e.key === "Enter") {
|
||||
setSearchTerm(e.target.value);
|
||||
}
|
||||
const handleSearchChange = (e) => {
|
||||
setKeyword(e.target.value);
|
||||
};
|
||||
|
||||
const handleSearchSubmit = (e) => {
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const handlePageChange = (newPage) => {
|
||||
setPage(newPage); // Update the current page when user clicks pagination
|
||||
};
|
||||
|
||||
return (
|
||||
|
@ -50,16 +63,17 @@ const SearchProperties = () => {
|
|||
<div className="col-lg-12 card-margin col-12">
|
||||
<div className="card search-form col-12">
|
||||
<div className="card-body p-0">
|
||||
<form id="search-form">
|
||||
<form id="search-form" onSubmit={handleSearchSubmit}>
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<div className="row no-gutters">
|
||||
<div className="col-lg-8 col-md-6 col-sm-12 p-0">
|
||||
<input
|
||||
type="text"
|
||||
value={keyword}
|
||||
onChange={handleSearchChange}
|
||||
placeholder="Enter the keyword and hit ENTER button..."
|
||||
className="form-control"
|
||||
onKeyDown={handleSearch}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -83,6 +97,7 @@ const SearchProperties = () => {
|
|||
<table className="table widget-26">
|
||||
<thead style={{ color: "#fda417", fontSize: "15px" }}>
|
||||
<tr>
|
||||
<th>Image</th>
|
||||
<th>Details</th>
|
||||
<th>Total Living Square Foot</th>
|
||||
<th>Year Built</th>
|
||||
|
@ -93,15 +108,59 @@ const SearchProperties = () => {
|
|||
{filteredProperties.length > 0 ? (
|
||||
filteredProperties.map((property) => (
|
||||
<tr key={property.id}>
|
||||
{/* <td>{property.details}</td> */}
|
||||
<td>{property.address}</td>
|
||||
{/* <td>{property.yearBuilt}</td>
|
||||
<td>{property.costPerSqFt}</td> */}
|
||||
<td>
|
||||
|
||||
{property.images && property.images[0] ? (
|
||||
<img
|
||||
src={property.images[0].file || profilepic}
|
||||
alt="Property Thumbnail"
|
||||
style={{ width: "100px", height: "auto" }}
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src={profilepic}
|
||||
alt="Default Property Thumbnail"
|
||||
style={{ width: "100px", height: "auto" }}
|
||||
/>
|
||||
)}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</td>
|
||||
<td>
|
||||
<div className="widget-26-job-title">
|
||||
<NavLink
|
||||
to={`/property/${property.propertyId}`}
|
||||
className="link-primary text-decoration-none"
|
||||
target="_blank"
|
||||
>
|
||||
{property.address}
|
||||
</NavLink>
|
||||
<p className="m-0">
|
||||
<span className="employer-name">
|
||||
<i
|
||||
className="fa fa-map-marker"
|
||||
style={{ color: "#F74B02" }}
|
||||
/>
|
||||
{property.city}, {property.county},{" "}
|
||||
{property.state}
|
||||
</span>
|
||||
<p className="text-muted m-0">
|
||||
House Id: {property.propertyId}
|
||||
</p>
|
||||
</p>
|
||||
</div>
|
||||
</td>
|
||||
<td>{property.totallivingsqft}</td>
|
||||
<td>{property.yearBuild}</td>
|
||||
<td>{property.costpersqft}</td>
|
||||
</tr>
|
||||
))
|
||||
) : (
|
||||
<tr>
|
||||
<td colSpan="4">No properties found.</td>
|
||||
<td colSpan="5">No properties found.</td>
|
||||
</tr>
|
||||
)}
|
||||
</tbody>
|
||||
|
@ -112,6 +171,48 @@ const SearchProperties = () => {
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Pagination Controls */}
|
||||
{/* Pagination */}
|
||||
<nav aria-label="Page navigation">
|
||||
<ul className="pagination justify-content-center">
|
||||
<li className={`page-item ${currentPage === 1 ? "disabled" : ""}`}>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => handlePageChange(currentPage - 1)}
|
||||
>
|
||||
Previous
|
||||
</button>
|
||||
</li>
|
||||
{Array.from({ length: totalPages }, (_, index) => (
|
||||
<li
|
||||
key={index + 1}
|
||||
className={`page-item ${
|
||||
currentPage === index + 1 ? "active" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => handlePageChange(index + 1)}
|
||||
>
|
||||
{index + 1}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
<li
|
||||
className={`page-item ${
|
||||
currentPage === totalPages ? "disabled" : ""
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
className="page-link"
|
||||
onClick={() => handlePageChange(currentPage + 1)}
|
||||
>
|
||||
Next
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
<Footer />
|
||||
</>
|
||||
|
|
|
@ -64,10 +64,18 @@ export const updateProperty = createAsyncThunk(
|
|||
}
|
||||
);
|
||||
|
||||
export const getProperties = createAsyncThunk("property/getProperties", async () => {
|
||||
const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties`); // Backend endpoint
|
||||
// export const getProperties = createAsyncThunk("property/getProperties", async () => {
|
||||
// const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties`); // Backend endpoint
|
||||
// return response.data;
|
||||
// });
|
||||
|
||||
export const getProperties = createAsyncThunk(
|
||||
'properties/getProperties',
|
||||
async ({ page, limit, keyword = "" }) => {
|
||||
const response = await axios.get(`${import.meta.env.VITE_REACT_APP_SECRET}/properties?page=${page}&limit=${limit}&keyword=${keyword}`);
|
||||
return response.data;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
const propertySlice = createSlice({
|
||||
name: "property",
|
||||
|
@ -139,7 +147,9 @@ const propertySlice = createSlice({
|
|||
})
|
||||
.addCase(getProperties.fulfilled, (state, action) => {
|
||||
state.loading = false;
|
||||
state.properties = action.payload;
|
||||
state.properties = action.payload.data;
|
||||
state.totalPages = action.payload.totalPages;
|
||||
state.currentPage = action.payload.currentPage;
|
||||
})
|
||||
.addCase(getProperties.rejected, (state, action) => {
|
||||
state.loading = false;
|
||||
|
|
Loading…
Reference in New Issue