import React, { useEffect, useState, useMemo } from "react"; // PropertySearch.jsx // Full-advanced search page component for condo.my // TailwindCSS assumed available. This component is UI + front-end logic // Connect it to your backend API (WordPress REST API or custom) at fetchListings(). export default function PropertySearch() { // Filters state const [listingType, setListingType] = useState([]); // multi-select: e.g. ["sale","rent","auction","new"] const [location, setLocation] = useState({ state: "", city: "", project: "" }); const [priceMin, setPriceMin] = useState(0); const [priceMax, setPriceMax] = useState(5000000); const [quickPrice, setQuickPrice] = useState(null); // e.g. 300000 const [builtUpMin, setBuiltUpMin] = useState(0); const [builtUpMax, setBuiltUpMax] = useState(5000); const [propertyType, setPropertyType] = useState([]); const [beds, setBeds] = useState(null); const [bathrooms, setBathrooms] = useState(null); const [tenure, setTenure] = useState([]); const [furnishing, setFurnishing] = useState([]); const [parking, setParking] = useState(null); const [facilities, setFacilities] = useState([]); const [yearFrom, setYearFrom] = useState(1900); const [yearTo, setYearTo] = useState(new Date().getFullYear()); const [developer, setDeveloper] = useState(""); const [station, setStation] = useState(""); const [floorLevel, setFloorLevel] = useState(""); const [facing, setFacing] = useState(""); const [keyword, setKeyword] = useState(""); // UI state const [results, setResults] = useState([]); const [loading, setLoading] = useState(false); const [sortBy, setSortBy] = useState("relevance"); const [page, setPage] = useState(1); const [perPage] = useState(12); const [mapMode, setMapMode] = useState(false); // Mock / demo data - remove in production const mockListings = useMemo(() => { const arr = []; for (let i = 1; i <= 30; i++) { arr.push({ id: i, title: `Condo Example ${i}`, price: 250000 + i * 10000, location: "KLCC, Kuala Lumpur", built_up: 800 + i * 10, beds: 2 + (i % 3), baths: 1 + (i % 2), tenure: i % 2 === 0 ? "Freehold" : "Leasehold", type: "Condo", listing_type: i % 5 === 0 ? "Auction" : i % 4 === 0 ? "New Launch" : "For Sale", img: `https://picsum.photos/seed/${i}/400/300`, lat: 3.1578 + (i * 0.001), lng: 101.7124 + (i * 0.0015), }); } return arr; }, []); useEffect(() => { // initial load fetchListings(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); // Build query params from filter state function buildQueryParams() { const params = {}; if (listingType.length) params.listing_type = listingType.join(","); if (location.state) params.state = location.state; if (location.city) params.city = location.city; if (location.project) params.project = location.project; if (quickPrice) { params.price_max = quickPrice; } else { params.price_min = priceMin; params.price_max = priceMax; } params.builtup_min = builtUpMin; params.builtup_max = builtUpMax; if (propertyType.length) params.property_type = propertyType.join(","); if (beds) params.beds = beds; if (bathrooms) params.bathrooms = bathrooms; if (tenure.length) params.tenure = tenure.join(","); if (furnishing.length) params.furnishing = furnishing.join(","); if (parking) params.parking = parking; if (facilities.length) params.facilities = facilities.join(","); if (yearFrom) params.year_from = yearFrom; if (yearTo) params.year_to = yearTo; if (developer) params.developer = developer; if (station) params.station = station; if (keyword) params.keyword = keyword; params.page = page; params.per_page = perPage; params.sort = sortBy; return params; } // Replace this function to call your real API endpoint. async function fetchListings(overrides = {}) { setLoading(true); try { const params = { ...buildQueryParams(), ...overrides }; // --- Demo: local filter on mock data --- // In production, call your backend API and return JSON. let filtered = [...mockListings]; if (params.listing_type) { const arr = params.listing_type.split(","); filtered = filtered.filter((l) => arr.includes(l.listing_type.toLowerCase()) || arr.map(a => a.toLowerCase()).includes(l.listing_type.toLowerCase())); } if (params.price_max) filtered = filtered.filter((l) => l.price <= Number(params.price_max)); if (params.price_min) filtered = filtered.filter((l) => l.price >= Number(params.price_min)); if (params.builtup_min) filtered = filtered.filter((l) => l.built_up >= Number(params.builtup_min)); if (params.builtup_max) filtered = filtered.filter((l) => l.built_up <= Number(params.builtup_max)); if (params.keyword) filtered = filtered.filter((l) => l.title.toLowerCase().includes(params.keyword.toLowerCase()) || l.location.toLowerCase().includes(params.keyword.toLowerCase())); // sort if (params.sort === "price_asc") filtered.sort((a, b) => a.price - b.price); else if (params.sort === "price_desc") filtered.sort((a, b) => b.price - a.price); else if (params.sort === "newest") filtered.reverse(); // pagination const start = (params.page - 1) * params.per_page; const paged = filtered.slice(start, start + params.per_page); // simulate latency await new Promise((r) => setTimeout(r, 200)); setResults(paged); } catch (err) { console.error(err); } finally { setLoading(false); } } function toggleArrayState(setter, stateArr, value) { if (stateArr.includes(value)) setter(stateArr.filter((v) => v !== value)); else setter([...stateArr, value]); } function handleQuickPrice(val) { setQuickPrice(val); if (val) { setPriceMax(val); setPriceMin(0); } // fetch immediately fetchListings({ page: 1 }); } function handleApplyFilters() { setPage(1); fetchListings({ page: 1 }); } function handleClearAll() { setListingType([]); setLocation({ state: "", city: "", project: "" }); setPriceMin(0); setPriceMax(5000000); setQuickPrice(null); setBuiltUpMin(0); setBuiltUpMax(5000); setPropertyType([]); setBeds(null); setBathrooms(null); setTenure([]); setFurnishing([]); setParking(null); setFacilities([]); setYearFrom(1900); setYearTo(new Date().getFullYear()); setDeveloper(""); setStation(""); setKeyword(""); setPage(1); fetchListings({ page: 1 }); } return (

Property Search — condo.my

{/* Filters column */} {/* Results + Map column */}
Showing {results.length} results
{mapMode ? (
{/* Replace with Google Maps JS + markers for production. This is a placeholder. */}
) : null}
{loading ? (
Loading...
) : results.length === 0 ? (
No listings match your filters.
) : results.map(listing => (
{listing.title}

{listing.title}

{listing.listing_type}
RM {listing.price.toLocaleString()}
{listing.location} • {listing.built_up} sq.ft • {listing.beds} beds
))}
{/* Pagination */}
Page {page}
); } /* Integration notes (copy into your project): - This is a front-end React component (single-file). It assumes Tailwind is configured. - Replace the mockListings + fetchListings demo logic with your real API: Example endpoint: GET /wp-json/condomy/v1/listings?price_min=...&price_max=...&listing_type=sale,rent - For map markers, use Google Maps JS API or Leaflet with your listing coordinates. - For server-side filtering and performance, implement the same filter param names in your backend. - Add authentication endpoints if you want Save Search / Favourites. */