This commit is contained in:
omkieit 2024-09-19 21:17:01 +05:30
parent 1549c32eb6
commit 3750a089f4
6 changed files with 275 additions and 156 deletions

View File

@ -29,7 +29,7 @@ db.connect((err) => {
console.log("Connected to the MYSQL database.");
});
// Controller function
// Controller function to get the data from the table from MYSQL with no pagination and huge data cant be getting
// export const searchMySQL = (req, res) => {
// const q = "SELECT * FROM client_information";
// // const q = "SELECT * FROM home_information";
@ -42,21 +42,60 @@ db.connect((err) => {
// });
// };
// Controller function to get all data from MYSQL table with pagination
// export const searchMySQL = (req, res) => {
// const limit = parseInt(req.query.limit) || 10; // Default to 10 items per page
// const offset = parseInt(req.query.offset) || 0; // Default to the first page
// const q = `SELECT * FROM home_information LIMIT ${limit} OFFSET ${offset}`;
// db.query(q, (err, data) => {
// if (err) {
// console.log(err);
// return res.status(500).json({ error: "Database query failed" });
// }
// // Set cache-control headers to prevent caching
// res.set('Cache-Control', 'no-store');
// return res.json(data);
// });
// };
// Controller function to get all data from MYSQL table with pagination and total records
export const searchMySQL = (req, res) => {
const limit = parseInt(req.query.limit) || 10; // Default to 10 items per page
const offset = parseInt(req.query.offset) || 0; // Default to the first page
const q = `SELECT * FROM home_information LIMIT ${limit} OFFSET ${offset}`;
const searchQuery = req.query.search || ''; // Get search query if provided
db.query(q, (err, data) => {
// Query to get total count of records
const countQuery = `SELECT COUNT(*) as total FROM home_information WHERE address LIKE ?`;
// Query to fetch paginated data
const dataQuery = `SELECT * FROM home_information WHERE address LIKE ? LIMIT ? OFFSET ?`;
// Perform count query
db.query(countQuery, [`%${searchQuery}%`], (err, countResult) => {
if (err) {
console.log(err);
return res.status(500).json({ error: "Database query failed" });
}
// Get the total count from the query result
const totalRecords = countResult[0].total;
// Perform data query
db.query(dataQuery, [`%${searchQuery}%`, limit, offset], (err, data) => {
if (err) {
console.log(err);
return res.status(500).json({ error: "Database query failed" });
}
// Set cache-control headers to prevent caching
res.set('Cache-Control', 'no-store');
return res.json(data);
// Return both count and paginated data in the response
return res.json({
data,
totalRecords
});
});
});
};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -42,8 +42,8 @@
<!-- <script src="https://stackpath.bootstrapcdn.com/bootstrap/5.1.3/js/bootstrap.bundle.min.js"></script> -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0/dist/js/bootstrap.bundle.min.js"></script>
<script type="module" crossorigin src="/assets/index-vceAjfBL.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DPr78kNB.css">
<script type="module" crossorigin src="/assets/index-Br5i4FR3.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DlbKQED5.css">
</head>

View File

@ -1,4 +1,5 @@
import { useEffect, useState } from "react";
import { useEffect, useState, useCallback } from "react";
import { NavLink } from "react-router-dom";
import axios from "axios";
import Navbar from "./Navbar";
import Footer from "./Footer";
@ -9,26 +10,82 @@ const SearchMysql = () => {
const [totalRecords, setTotalRecords] = useState(0);
const [page, setPage] = useState(0); // Page number
const [limit] = useState(10); // Items per page
const [search, setSearch] = useState(""); // Search query state
const [loading, setLoading] = useState(false); // Loader state
// Fetch properties from API
const fetchProperties = async () => {
setLoading(true);
try {
const res = await axios.get(
`${import.meta.env.VITE_REACT_APP_SECRET}/mysql/searchmysql`,
{
params: { limit, offset: page * limit },
params: { limit, offset: page * limit, search },
headers: { "Cache-Control": "no-cache" }, // Disable caching
}
);
setProperties(res.data);
setTotalRecords(res.data.total); // Get total records from backend
setProperties(res.data.data); // Set properties
setTotalRecords(res.data.totalRecords); // Set total records
} catch (err) {
console.log("Error fetching data:", err);
} finally {
setLoading(false);
}
};
// Debounce the search input
const debounce = (func, delay) => {
let timer;
return (...args) => {
clearTimeout(timer);
timer = setTimeout(() => func(...args), delay);
};
};
// Debounced fetch properties
const debouncedFetchProperties = useCallback(
debounce(() => {
if (search.trim() === "") {
fetchProperties(); // Fetch default properties when search is empty
} else {
fetchProperties(); // Fetch properties with new search term
}
}, 3000), // 3 seconds delay
[search, page]
);
// Handle search input change
const handleSearchChange = (e) => {
setSearch(e.target.value);
// Trigger search only if input is non-empty
if (e.target.value.trim() === "") {
setPage(0); // Reset to first page
fetchProperties(); // Fetch default properties immediately
}
};
// Handle key press events (Enter)
const handleKeyPress = (e) => {
if (e.key === "Enter") {
e.preventDefault();
if (search.trim()) {
debouncedFetchProperties(); // Fetch properties on Enter key
}
}
};
// Handle input blur to fetch results after typing
const handleBlur = () => {
if (search.trim() !== "") {
debouncedFetchProperties(); // Fetch properties after typing is complete
}
};
// Fetch data when page changes
useEffect(() => {
fetchProperties();
// Fetch default properties when the component mounts or page changes
if (search.trim() === "") {
fetchProperties(); // Fetch default properties
}
}, [page]);
const totalPages = Math.ceil(totalRecords / limit);
@ -38,7 +95,6 @@ const SearchMysql = () => {
<Navbar />
<br /> <br /> <br /> <br /> <br /> <br />
{/* Display properties */}
{properties.length > 0 ? (
<div className="container col-12">
<div className="row">
<div className="col-lg-12 card-margin col-12">
@ -55,6 +111,10 @@ const SearchMysql = () => {
className="form-control"
id="search"
name="search"
value={search}
onChange={handleSearchChange}
onKeyDown={handleKeyPress}
onBlur={handleBlur} // Trigger search on blur
/>
</div>
<div className="col-lg-1 col-md-3 col-sm-12 p-0"></div>
@ -70,6 +130,9 @@ const SearchMysql = () => {
<div className="col-12">
<div className="card card-margin">
<div className="card-body">
{loading ? (
<div className="loader">Loading...</div> // Loader component
) : (
<div className="row search-body">
<div className="col-lg-12">
<div className="search-result col-12">
@ -82,6 +145,10 @@ const SearchMysql = () => {
<button
onClick={() => setPage(page - 1)}
disabled={page === 0}
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
Previous
</button>
@ -92,54 +159,68 @@ const SearchMysql = () => {
<button
onClick={() => setPage(page + 1)}
disabled={page + 1 >= totalPages}
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
Next
</button>
</div>
</div>
</div>
</div>
</div>
<div className="result-body">
<div className="table-responsive">
<table className="table widget-26">
<tbody>
{properties.map((property, index) => (
<div key={index} className="property">
{/* Add table headers */}
<thead>
<tr>
<td>
<div className="widget-26-job-emp-img">
<img
src="https://bootdey.com/img/Content/avatar/avatar2.png"
alt="Company"
/>
</div>
</td>
<th>Details</th>
<th>Total Living Square Foot</th>
<th>Year Built</th>
<th>Cost per Square Foot</th>
</tr>
</thead>
<tbody>
{properties.length > 0 ? (
properties.map((property, index) => (
<tr key={index}>
<td>
<div className="widget-26-job-title">
<a href="#">{property.address}</a>
<p className="m-0">
<span
className="employer-name"
<NavLink
to={`/property/${property.house_id}`}
className="link-primary text-decoration-none"
>
{property.city}, {property.county}, {property.state}
{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.house_id}
</p>
</p>
</div>
</td>
<td>
<div className="widget-26-job-info">
<p className="type m-0">Total Living Square foot</p>
<p className="text-muted m-0">
is{" "}
<span className="location">
<p className="m-0">
{property.total_living_sqft}
</span>
</p>
</div>
</td>
<td>
<div className="widget-26-job-info">
<p className="m-0">
{property.year_built}
</p>
</div>
</td>
@ -148,51 +229,26 @@ const SearchMysql = () => {
$ {property.cost_per_sqft}/sqft
</div>
</td>
<td>
<div className="widget-26-job-info">
<p className="type m-0">Year built</p>
<p className="text-muted m-0">
<span className="location">
{property.year_built}
</span>
</p>
</div>
</td>
{/* <td>
<div className="widget-26-job-starred">
<a href="#">
<svg
xmlns="http://www.w3.org/2000/svg"
width={24}
height={24}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth={2}
strokeLinecap="round"
strokeLinejoin="round"
className="feather feather-star"
>
<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
</svg>
</a>
</div>
</td> */}
</tr>
<hr style={{color: "#fda417"}} />
))
) : (
<tr>
<td colSpan="4">No results found</td>
</tr>
)}
</tbody>
</table>
</div>
</div>
))}
{/* Pagination Controls */}
<div>
<button
onClick={() => setPage(page - 1)}
disabled={page === 0}
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
Previous
</button>
@ -203,26 +259,23 @@ const SearchMysql = () => {
<button
onClick={() => setPage(page + 1)}
disabled={page + 1 >= totalPages}
style={{
backgroundColor: "#fda417",
border: "#fda417",
}}
>
Next
</button>
</div>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
) : (
<p>No properties found.</p>
)}
{/* Pagination Controls */}
</div>
</div>
</div>
</div>
</div>
<Footer />
</>
);

View File

@ -37,7 +37,7 @@ body{
margin: 0;
line-height: 1.5;
font-weight: 400;
color: #3c4142;
color: #000000;
font-size: 0.9125rem;
color: #3c4142;
}
@ -59,7 +59,7 @@ body{
.widget-26 .widget-26-job-info p {
line-height: 1.5;
color: #3c4142;
color: #000000;
font-size: 0.9125rem;
}
@ -70,7 +70,7 @@ body{
.widget-26 .widget-26-job-salary {
min-width: 70px;
font-weight: 400;
color: #3c4142;
color: #000000;
font-size: 0.9125rem;
}
@ -91,7 +91,7 @@ body{
.widget-26 .widget-26-job-category span {
font-size: 0.8125rem;
color: #3c4142;
color: #000000;
font-weight: 600;
}
@ -170,7 +170,7 @@ body{
}
.search-body .search-filters .filter-list .title {
color: #3c4142;
color: #000000;
margin-bottom: 1rem;
}
@ -183,7 +183,7 @@ body{
}
.search-body .search-result .result-header .records {
color: #3c4142;
color: #000000;
}
.search-body .search-result .result-header .result-actions {
@ -208,7 +208,7 @@ body{
}
.search-body .search-result .result-header .result-actions .result-sorting select option {
color: #3c4142;
color: #000000;
}
@media (min-width: 768px) and (max-width: 991.98px) {
@ -253,5 +253,32 @@ body{
border-radius: 8px;
}
.loader {
position: fixed;
left: 0;
top: 0;
width: 100%;
height: 100%;
background: rgba(255, 255, 255, 0.8);
display: flex;
justify-content: center;
align-items: center;
z-index: 9999;
}
.spinner {
border: 8px solid #f3f3f3;
border-top: 8px solid #3498db;
border-radius: 50%;
width: 60px;
height: 60px;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}