This commit is contained in:
omkieit 2024-09-26 19:56:23 +05:30
parent 252e91fc77
commit d54bcdb9c5
6 changed files with 222 additions and 64 deletions

View File

@ -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

View File

@ -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>

View File

@ -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">

View File

@ -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 />
</>

View File

@ -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;