feat: listings for sale, and move detail property url
This commit is contained in:
parent
f5c5f3fd78
commit
73de3fd07d
95
src/app/(main)/listings-for-sale/page.tsx
Normal file
95
src/app/(main)/listings-for-sale/page.tsx
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
@ -61,7 +61,7 @@ export async function generateMetadata(props: { params: Promise<{ slug: string }
|
|||||||
return metadata;
|
return metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default async function ListingsForRentDetail({ params }: { params: Promise<{ slug: string }> }) {
|
export default async function PropertyDetail({ params }: { params: Promise<{ slug: string }> }) {
|
||||||
const slug = (await params).slug;
|
const slug = (await params).slug;
|
||||||
const propertyDetail = await fetchPropertyDetail({ slug });
|
const propertyDetail = await fetchPropertyDetail({ slug });
|
||||||
if (!propertyDetail) return notFound();
|
if (!propertyDetail) return notFound();
|
@ -113,7 +113,7 @@ export default function Header() {
|
|||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li className="rd-nav-item">
|
<li className="rd-nav-item">
|
||||||
<a className="rd-nav-link rd-nav-link-custom" href="/">
|
<a className="rd-nav-link rd-nav-link-custom" href="/listings-for-sale">
|
||||||
LISTINGS FOR SALE
|
LISTINGS FOR SALE
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -8,7 +8,7 @@ type CardPropertyProps = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export default function CardProperty({ data }: CardPropertyProps) {
|
export default function CardProperty({ data }: CardPropertyProps) {
|
||||||
const href = data?.propertyType === "rent" ? `/listings-for-rent/${data.slug}` : `/listings-for-sell/${data.slug}`;
|
const href = data?.propertyType === "rent" ? `/property/${data.slug}` : `/property/${data.slug}`;
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<article className="product-classic">
|
<article className="product-classic">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user