96 lines
3.5 KiB
TypeScript
96 lines
3.5 KiB
TypeScript
import HeroImage from "@/components/HeroImage";
|
||
import Pagination from "@/components/Pagination";
|
||
import CardProperty from "@/components/properties/CardProperty";
|
||
import FilterProperty from "@/components/properties/FilterProperty";
|
||
import { FetchPropertyParams } from "@/schema/services/property";
|
||
import { fetchProperty } from "@/services/payload/property";
|
||
import { getDefaultMetadata } from "@/utils/metadata";
|
||
import { sanitizeNumber, sanitizePageNumber } from "@/utils/sanitize";
|
||
import { Metadata } from "next";
|
||
|
||
const metaDesc = "Explore the latest properties on the Dynamic Realty.";
|
||
|
||
export async function generateMetadata(): Promise<Metadata> {
|
||
const metadata = await getDefaultMetadata();
|
||
metadata.title = `Listings For Sale - ${metadata.openGraph?.siteName}`;
|
||
metadata.description = metaDesc;
|
||
|
||
return metadata;
|
||
}
|
||
|
||
export default async function ListingsForRent(props: {
|
||
searchParams?: Promise<{ [P in keyof FetchPropertyParams]: string }>;
|
||
}) {
|
||
const searchParams = await props?.searchParams;
|
||
const page = sanitizePageNumber(searchParams?.page);
|
||
const minPrice = sanitizeNumber(searchParams?.min_price);
|
||
const maxPrice = sanitizeNumber(searchParams?.max_price);
|
||
const minArea = sanitizeNumber(searchParams?.min_area);
|
||
const maxArea = sanitizeNumber(searchParams?.max_area);
|
||
|
||
const propertiesData = await fetchProperty({
|
||
property_type: "sell",
|
||
page,
|
||
name: searchParams?.name,
|
||
min_price: minPrice,
|
||
max_price: maxPrice,
|
||
min_area: minArea,
|
||
max_area: maxArea,
|
||
location: searchParams?.location,
|
||
});
|
||
const isEmpty = propertiesData.formattedData.length <= 0;
|
||
|
||
return (
|
||
<>
|
||
<HeroImage title="Listings For Sale" />
|
||
|
||
<section className="section section-md bg-gray-12">
|
||
<div className="container">
|
||
<div className="row row-50">
|
||
<div className="col-lg-7 col-xl-8">
|
||
<div className="row row-30">
|
||
<div className="col-12">
|
||
{isEmpty && (
|
||
<div className="text-center mt-40">
|
||
<h3 className="text-spacing-20">No Properties Found</h3>
|
||
<p className="heading-5 mt-3">Looks like we couldn’t find any listings that match your search.</p>
|
||
</div>
|
||
)}
|
||
{!isEmpty && (
|
||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||
{propertiesData.formattedData.map((p, idx) => (
|
||
<CardProperty key={idx} data={p} />
|
||
))}
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{/* Pagination */}
|
||
{propertiesData.totalPages > 1 && (
|
||
<div className="col-12">
|
||
<Pagination
|
||
page={propertiesData.page ?? 1}
|
||
hasNextPage={propertiesData.hasNextPage}
|
||
hasPreviousPage={propertiesData.hasPrevPage}
|
||
totalPages={propertiesData.totalPages}
|
||
/>
|
||
</div>
|
||
)}
|
||
{/* End Pagination */}
|
||
</div>
|
||
</div>
|
||
|
||
<div className="col-lg-5 col-xl-4">
|
||
<div className="row row-50">
|
||
<div className="col-md-6 col-lg-12">
|
||
<FilterProperty propertyType="rent" searchParams={searchParams} />
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</section>
|
||
</>
|
||
);
|
||
}
|