fix: property list and detail UI slicing

This commit is contained in:
RizqiSyahrendra 2025-04-22 18:03:54 +07:00
parent 12e7941f6c
commit f574fdc66d
9 changed files with 1109 additions and 4 deletions

View File

@ -588,9 +588,9 @@ a:hover {
color: #967244;
}
a[href*='tel'], a[href*='mailto'] {
/* a[href*='tel'], a[href*='mailto'] {
white-space: nowrap;
}
} */
.link-default, .link-default:active, .link-default:focus {
color: #424445;
@ -1177,7 +1177,7 @@ a.privacy-link {
padding: 12px 11px;
color: #9cc1ff;
letter-spacing: 0;
background-color: #31323c;
background-color: var(--color-colorContactForm);
}
.block-callboard a, .block-callboard a:focus, .block-callboard a:active {

View File

@ -34,6 +34,7 @@
--color-colorText1: var(--color-colorExt10);
--color-colorText2: var(--color-colorExt20);
--color-colorLoaderBackground: var(--color-colorExt20);
--color-colorPriceTag: var(--color-colorExt30);
}
@layer components {

View File

@ -0,0 +1,594 @@
import CardProperty from "@/components/CardProperty";
import HeroImage from "@/components/HeroImage";
import { CardPropertyData } from "@/schema/property";
import { formatCurrency } from "@/utils/general";
const similarPropertiesData: CardPropertyData[] = [
{
id: 1,
title: "401 Biscayne Boulevard, Miami",
slug: "401-biscayne-boulevard",
images: [
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
{
id: 2,
title: "402 Biscayne Boulevard, Miami",
slug: "402-biscayne-boulevard",
images: [{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" }],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
];
export default function ListingsForRentDetail() {
return (
<>
<HeroImage title="Lorem Ipsum, Dolor" />
<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="slick-slider-1">
<div className="slick-slider-price">$5000\mo</div>
<div
className="slick-slider carousel-parent"
id="parent-carousel"
data-arrows="true"
data-loop="true"
data-dots="false"
data-swipe="true"
data-fade="true"
data-items="1"
data-child="#child-carousel"
data-for="#child-carousel"
>
<div className="item">
<img src="/images/single-property-1-763x443.jpg" alt="" width="763" height="443" />
</div>
<div className="item">
<img src="/images/single-property-2-763x443.jpg" alt="" width="763" height="443" />
</div>
<div className="item">
<img src="/images/single-property-3-763x443.jpg" alt="" width="763" height="443" />
</div>
<div className="item">
<img src="/images/single-property-4-763x443.jpg" alt="" width="763" height="443" />
</div>
<div className="item">
<img src="/images/single-property-5-763x443.jpg" alt="" width="763" height="443" />
</div>
<div className="item">
<img src="/images/single-property-6-763x443.jpg" alt="" width="763" height="443" />
</div>
</div>
<div
className="slick-slider carousel-child"
id="child-carousel"
data-arrows="true"
data-loop="true"
data-dots="false"
data-swipe="true"
data-items="1"
data-sm-items="3"
data-md-items="4"
data-lg-items="4"
data-xl-items="5"
data-slide-to-scroll="1"
data-for="#parent-carousel"
>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
<div>
<div className="slick-slide-inner bg-[url(/images/single-property-1-763x443.jpg)]"></div>
</div>
</div>
</div>
<div className="features-block">
<div className="features-block-inner">
<div className="features-block-item">
<ul className="features-block-list">
<li>
<span className="icon hotel-icon-10"></span>
<span>2 Bathrooms</span>
</li>
<li>
<span className="icon hotel-icon-05"></span>
<span>2 Bedrooms</span>
</li>
<li>
<span className="icon mdi mdi-vector-square"></span>
<span>480 Sq Ft</span>
</li>
</ul>
</div>
<div className="features-block-item">
<a className="link link-1" href="#">
<span className="icon mdi mdi-heart-outline"></span>Add to Favorites
</a>
</div>
</div>
</div>
<p>
Choose this property if you are looking for a modern house near the ocean shore. With 2 bathrooms and 2
bedrooms as well as a single garage, it is a perfect option for a small family.
</p>
<p>
This home has been completely renovated within the past year and features amazing views and sunsets of
the local lake, solid wood cabinets (and loads of them), granite counters with colored glass backsplash,
sliding glass doors across the entire family room allowing beautiful views of the lake etc. Its
affordable price serves as a great bonus for a family looking for an opportunity to save money on Miami
MyHome.
</p>
<div
className="card-group-custom card-group-corporate"
id="accordion1"
role="tablist"
aria-multiselectable="false"
>
<article className="card card-custom card-corporate">
<div className="card-header" id="accordion1-heading-1" role="tab">
<div className="card-title">
<a
className="card-link"
role="button"
data-toggle="collapse"
href="#accordion1-collapse-1"
aria-controls="accordion1-collapse-1"
aria-expanded="true"
>
<span>Address</span>
<div className="card-arrow"></div>
</a>
</div>
</div>
<div
className="show visible!"
id="accordion1-collapse-1"
role="tabpanel"
aria-labelledby="accordion1-heading-1"
data-parent="#accordion1"
>
<div className="card-body">
<div className="layout-1">
<dl className="list-terms-inline">
<dt>Address:</dt>
<dd>Biscayne Blvd</dd>
</dl>
<dl className="list-terms-inline">
<dt>State/County:</dt>
<dd>Florida</dd>
</dl>
<dl className="list-terms-inline">
<dt>City:</dt>
<dd>Miami</dd>
</dl>
<dl className="list-terms-inline">
<dt>Zip:</dt>
<dd>8322</dd>
</dl>
<dl className="list-terms-inline">
<dt>Country:</dt>
<dd>United States</dd>
</dl>
<dl className="list-terms-inline">
<dt>Area:</dt>
<dd>Lake Worth</dd>
</dl>
</div>
</div>
</div>
</article>
</div>
<div
className="card-group-custom card-group-corporate"
id="accordion2"
role="tablist"
aria-multiselectable="false"
>
<article className="card card-custom card-corporate">
<div className="card-header" id="accordion2-heading-1" role="tab">
<div className="card-title">
<a
className="card-link"
role="button"
data-toggle="collapse"
href="#accordion2-collapse-1"
aria-controls="accordion2-collapse-1"
aria-expanded="true"
>
<span>Features</span>
<div className="card-arrow"></div>
</a>
</div>
</div>
<div
className="show visible!"
id="accordion2-collapse-1"
role="tabpanel"
aria-labelledby="accordion2-heading-1"
data-parent="#accordion2"
>
<div className="card-body">
<ul className="list-marked-2 layout-2">
<li>2 Stories</li>
<li>Basketball Court</li>
<li>Lawn</li>
<li>Gym</li>
<li>Fireplace</li>
<li>Sprinklers</li>
<li>Private Space</li>
<li>Balcony</li>
<li>Laundry</li>
<li>Ocean View</li>
</ul>
</div>
</div>
</article>
</div>
<div
className="card-group-custom card-group-corporate"
id="accordion0"
role="tablist"
aria-multiselectable="false"
>
<article className="card card-custom card-corporate">
<div className="card-header" id="accordion0-heading-0" role="tab">
<div className="card-title">
<a
className="card-link"
role="button"
data-toggle="collapse"
href="#accordion0-collapse-0"
aria-controls="accordion0-collapse-0"
aria-expanded="true"
>
<span>Pricing Detail</span>
<div className="card-arrow"></div>
</a>
</div>
</div>
<div
className="show visible!"
id="accordion0-collapse-0"
role="tabpanel"
aria-labelledby="accordion0-heading-0"
data-parent="#accordion0"
>
<div className="card-body">
<div className="layout-1 columns-1!">
<dl className="list-terms-inline w-full flex justify-between">
<dt>Base Rent</dt>
<dd>{formatCurrency(2700)}</dd>
</dl>
</div>
<div className="layout-1 columns-1!">
<dl className="list-terms-inline w-full flex justify-between">
<dt>Smart Home</dt>
<dd>{formatCurrency(20)}</dd>
</dl>
</div>
<div className="layout-1 columns-1!">
<dl className="list-terms-inline w-full flex justify-between">
<dt>Utility Service</dt>
<dd>{formatCurrency(5)}</dd>
</dl>
</div>
<div className="layout-1 columns-1! mt-2">
<dl className="list-terms-inline w-full flex justify-between">
<dd className="font-semibold!">Est. total monthly*</dd>
<dd className="font-semibold!">{formatCurrency(2900)}</dd>
</dl>
</div>
</div>
</div>
</article>
</div>
<div className="block-group-item">
<h3>Property Map</h3>
<div className="row row-30">
<div className="col-12">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3360.4823498818855!2d-83.68565822483802!3d32.61997607372962!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x88f3e6ce99781991%3A0xabfd803ad30f6d12!2s100%20N%20Houston%20Lake%20Blvd%2C%20Centerville%2C%20GA%2031028%2C%20USA!5e0!3m2!1sen!2sid!4v1744883077476!5m2!1sen!2sid"
width={"100%"}
height={450}
style={{ border: 0 }}
loading="lazy"
referrerPolicy="no-referrer-when-downgrade"
/>
</div>
</div>
</div>
<div className="blog-post-solo-footer mt-20">
<div className="blog-post-solo-footer-left">
<ul className="blog-post-solo-footer-list">
<li>
<span className="icon mdi mdi-clock"></span>
<a href="#">February 10, 2021</a>
</li>
</ul>
</div>
<div className="blog-post-solo-footer-right">
<ul className="blog-post-solo-footer-list-1">
<li>
<span>Share this post</span>
</li>
<li>
<ul className="list-inline-1">
<li>
<a className="icon link-default fa-facebook" href="#"></a>
</li>
<li>
<a className="icon link-default fa-twitter" href="#"></a>
</li>
<li>
<a className="icon link-default fa-google-plus" href="#"></a>
</li>
<li>
<a className="icon link-default fa-pinterest-p" href="#"></a>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div className="block-group-item">
<h3>Similar Properties</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{similarPropertiesData.map((p) => (
<CardProperty key={p.id} data={p} />
))}
</div>
</div>
</div>
<div className="col-lg-5 col-xl-4">
<div className="row row-50">
<div className="col-md-6 col-lg-12">
<div className="block-info">
<h3>Find Your Property</h3>
<form
className="rd-mailform form-select"
data-form-output="form-output-global"
data-form-type="contact"
method="post"
action="bat/rd-mailform.php"
>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Choose Location"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Alaska</option>
<option value="3">Arizona</option>
<option value="4">Arkansas</option>
<option value="5">California</option>
<option value="6">Colorado</option>
<option value="7">Connecticut</option>
<option value="8">Delaware</option>
<option value="9">Florida</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Property Status"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Low</option>
<option value="3">Middle</option>
<option value="4">Primary</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Property Type"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Low</option>
<option value="3">Middle</option>
<option value="4">Primary</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap-group">
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Min Price"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">100 $</option>
<option value="3">200 $</option>
<option value="4">300 $</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Max Price"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">1000 $</option>
<option value="3">2000 $</option>
<option value="4">3000 $</option>
</select>
<span className="select-arrow"></span>
</div>
</div>
<div className="form-wrap-group">
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Min Area"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">100 Sq Ft</option>
<option value="3">200 Sq Ft</option>
<option value="4">300 Sq Ft</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Max Area"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">1000 Sq Ft</option>
<option value="3">2000 Sq Ft</option>
<option value="4">3000 Sq Ft</option>
</select>
<span className="select-arrow"></span>
</div>
</div>
<div className="form-button">
<button className="button button-block button-primary" type="submit">
Search
</button>
</div>
</form>
</div>
</div>
<div className="col-md-6 col-lg-12">
<article className="block-callboard">
<div className="block-callboard-body">
<h3 className="block-callboard-title">Request a Showing</h3>
<form
className="rd-form rd-mailform"
data-form-output="form-output-global"
data-form-type="contact"
method="post"
action="bat/rd-mailform.php"
>
<div className="row row-20">
<div className="col-12">
<div className="form-wrap">
<input
className="form-input"
id="contact-name"
type="text"
name="name"
data-constraints="@Required"
/>
<label className="form-label" htmlFor="contact-name">
Your Name
</label>
</div>
</div>
<div className="col-12">
<div className="form-wrap">
<input
className="form-input"
id="contact-email"
type="email"
name="email"
data-constraints="@Email @Required"
/>
<label className="form-label" htmlFor="contact-email">
E-mail
</label>
</div>
</div>
<div className="col-12">
<div className="form-wrap">
<input
className="form-input"
id="contact-phone"
type="text"
name="phone"
data-constraints="@PhoneNumber"
/>
<label className="form-label" htmlFor="contact-phone">
Phone
</label>
</div>
</div>
<div className="col-12">
<div className="form-wrap">
<label className="form-label" htmlFor="contact-message">
Message
</label>
<textarea
className="form-input"
id="contact-message"
name="message"
data-constraints="@Required"
></textarea>
</div>
</div>
<div className="col-12">
<button className="button button-block button-secondary" type="submit">
Send message
</button>
</div>
</div>
</form>
</div>
</article>
</div>
</div>
</div>
</div>
</div>
</section>
</>
);
}

View File

@ -0,0 +1,292 @@
import CardProperty from "@/components/CardProperty";
import HeroImage from "@/components/HeroImage";
import Pagination from "@/components/Pagination";
import { CardPropertyData } from "@/schema/property";
import { getDefaultMetadata } from "@/utils/metadata";
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 Rent - ${metadata.openGraph?.siteName}`;
metadata.description = metaDesc;
return metadata;
}
const propertiesData: CardPropertyData[] = [
{
id: 1,
title: "401 Biscayne Boulevard, Miami",
slug: "401-biscayne-boulevard",
images: [
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" },
],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
{
id: 2,
title: "402 Biscayne Boulevard, Miami",
slug: "402-biscayne-boulevard",
images: [{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" }],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
{
id: 3,
title: "403 Biscayne Boulevard, Miami",
slug: "403-biscayne-boulevard",
images: [{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" }],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
{
id: 4,
title: "404 Biscayne Boulevard, Miami",
slug: "404-biscayne-boulevard",
images: [{ url: "/images/featured-properties-01-480x287.jpg", alt: "biscayne boulevard" }],
price: 5000,
propertyType: "rent",
posted_at: "",
area: 480,
bathrooms_count: 2,
bedrooms_count: 2,
is_available: true,
},
];
export default function ListingsForRent() {
return (
<>
<HeroImage title="Listings For Rent" />
<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">
<ul className="block-info-1">
<li>
<div className="form-wrap-group-1">
<div className="form-wrap">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Publication Date"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Monday</option>
<option value="3">Tuesday</option>
<option value="4">Wednesday</option>
<option value="5">Thursday</option>
<option value="6">Friday</option>
<option value="7">Saturday</option>
<option value="8">Sunday</option>
</select>
</div>
<div className="form-wrap">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Price Low to High"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="1">Price Low to High</option>
<option value="2">Price High to Low</option>
<option value="3">Most Popular</option>
<option value="4">Top Rated</option>
<option value="5">Best Sellers</option>
</select>
</div>
</div>
</li>
</ul>
</div>
<div className="col-12">
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{propertiesData.map((p) => (
<CardProperty key={p.id} data={p} />
))}
</div>
</div>
<div className="col-12">
{/* <ul className="pagination-custom">
<li>
<a className="active" href="#">
1
</a>
</li>
<li>
<a href="#">2</a>
</li>
</ul> */}
<Pagination hasNextPage={true} hasPreviousPage={true} totalPages={10} page={3} />
</div>
</div>
</div>
<div className="col-lg-5 col-xl-4">
<div className="row row-50">
<div className="col-md-6 col-lg-12">
<div className="block-info">
<h3>Find Your Property</h3>
<form
className="rd-mailform form-select"
data-form-output="form-output-global"
data-form-type="contact"
method="post"
action="bat/rd-mailform.php"
>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Choose Location"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Alaska</option>
<option value="3">Arizona</option>
<option value="4">Arkansas</option>
<option value="5">California</option>
<option value="6">Colorado</option>
<option value="7">Connecticut</option>
<option value="8">Delaware</option>
<option value="9">Florida</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Property Status"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Low</option>
<option value="3">Middle</option>
<option value="4">Primary</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Property Type"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">Low</option>
<option value="3">Middle</option>
<option value="4">Primary</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap-group">
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Min Price"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">100 $</option>
<option value="3">200 $</option>
<option value="4">300 $</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Max Price"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">1000 $</option>
<option value="3">2000 $</option>
<option value="4">3000 $</option>
</select>
<span className="select-arrow"></span>
</div>
</div>
<div className="form-wrap-group">
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Min Area"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">100 Sq Ft</option>
<option value="3">200 Sq Ft</option>
<option value="4">300 Sq Ft</option>
</select>
<span className="select-arrow"></span>
</div>
<div className="form-wrap form-wrap-validation">
<select
className="form-input select-filter"
data-style="modern"
data-placeholder="Max Area"
data-minimum-results-for-search="Infinity"
data-constraints="@Required"
>
<option label="placeholder"></option>
<option value="2">1000 Sq Ft</option>
<option value="3">2000 Sq Ft</option>
<option value="4">3000 Sq Ft</option>
</select>
<span className="select-arrow"></span>
</div>
</div>
<div className="form-button">
<button className="button button-block button-primary" type="submit">
Search
</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</>
);
}

View File

@ -0,0 +1,63 @@
import { CardPropertyData } from "@/schema/property";
import { formatCurrency } from "@/utils/general";
import Image from "next/image";
import Link from "next/link";
type CardPropertyProps = {
data: CardPropertyData;
};
export default function CardProperty({ data }: CardPropertyProps) {
return (
<>
<div>
<article className="product-classic">
<div className="product-classic-media">
<div
className="owl-carousel"
data-items="1"
data-nav="true"
data-stage-padding="0"
data-loop="false"
data-margin="0"
data-mouse-drag="false"
>
{Array.isArray(data.images) &&
data.images.map((img, idx) => (
<Image key={idx} src={img.url} alt={img.alt ?? ""} width="480" height="287" />
))}
</div>
<div className="product-classic-price bg-colorPriceTag/80!">
<span>
{formatCurrency(data.price)}
{data.propertyType === "rent" && `/mo`}
</span>
</div>
</div>
<h4 className="product-classic-title">
<Link href="/listings-for-rent/slug">{data.title}</Link>
</h4>
<div className="product-classic-divider"></div>
<ul className="product-classic-list">
<li>
<span className="icon mdi mdi-vector-square"></span>
<span>{data.area} Sq Ft</span>
</li>
{data.bathrooms_count && (
<li>
<span className="icon hotel-icon-10"></span>
<span>{data.bathrooms_count} Bathrooms</span>
</li>
)}
{data.bedrooms_count && (
<li>
<span className="icon hotel-icon-05"></span>
<span>{data.bedrooms_count} Bedrooms</span>
</li>
)}
</ul>
</article>
</div>
</>
);
}

View File

@ -0,0 +1,120 @@
"use client";
import { usePathname } from "next/navigation";
interface PaginationProps {
page: number;
hasPreviousPage: boolean;
hasNextPage: boolean;
totalPages: number;
usePathParams?: boolean;
}
export default function Pagination({
page,
hasPreviousPage,
hasNextPage,
totalPages,
usePathParams = false,
}: PaginationProps) {
const activePage = page;
const pathName = usePathname();
// Function to handle page change
const handlePageChange = (page: string | number) => {
if (typeof page === "string") return;
if (typeof window === "undefined") return;
const url = new URL(window.location.href);
const searchParams = new URLSearchParams(url.search);
if (usePathParams) {
let updatedPath = "";
if (pathName.includes("/page")) {
updatedPath = pathName.replace(/\/page\/\d+/, `/page/${page}`);
} else {
updatedPath = `${pathName}/page/${page}`;
}
window.location.href = `${updatedPath}?${searchParams}`;
} else {
searchParams.set("page", `${page}`);
window.location.href = `${pathName}/?${searchParams}`;
}
};
const getPageNumbers = () => {
const pages = [];
const showEllipsisStart = activePage > 4;
const showEllipsisEnd = activePage < totalPages - 3;
if (totalPages <= 7) {
// Show all pages if total is 7 or less
for (let i = 1; i <= totalPages; i++) {
pages.push(i);
}
} else {
// Always show first page
pages.push(1);
if (showEllipsisStart) {
pages.push("...");
}
// Show pages around current page
const start = showEllipsisStart ? Math.max(2, activePage - 1) : 2;
const end = showEllipsisEnd ? Math.min(totalPages - 1, activePage + 1) : totalPages - 1;
for (let i = start; i <= end; i++) {
pages.push(i);
}
if (showEllipsisEnd) {
pages.push("...");
}
// Always show last page
pages.push(totalPages);
}
return pages;
};
return (
<ul className={"pagination-custom"}>
{/* Previous Page Button */}
{hasPreviousPage && (
<>
<li className="cursor-pointer">
<a
onClick={() => activePage > 1 && handlePageChange(activePage - 1)}
className={activePage === 1 ? "disabled" : ""}
>
{"<"}
</a>
</li>
</>
)}
{getPageNumbers().map((page, key) => (
<li key={key} className="cursor-pointer">
<a onClick={() => handlePageChange(page)} className={activePage === page ? "active" : ""}>
{page}
</a>
</li>
))}
{/* Next Page Button */}
{hasNextPage && (
<>
<li className="cursor-pointer">
<a
onClick={() => activePage < totalPages && handlePageChange(activePage + 1)}
className={activePage === totalPages ? "disabled" : ""}
>
{">"}
</a>
</li>
</>
)}
</ul>
);
}

View File

@ -118,7 +118,7 @@ export default function Header() {
</a>
</li>
<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-rent">
LISTINGS FOR RENT
</a>
</li>

16
src/schema/property.ts Normal file
View File

@ -0,0 +1,16 @@
export type CardPropertyData = {
id: number;
slug?: string | null;
title: string;
price: number;
images?: { url: string; alt?: string }[];
/**
* in sqft
*/
area: number;
bedrooms_count?: number;
bathrooms_count?: number;
posted_at: string;
propertyType: "rent" | "sell";
is_available: boolean;
};

View File

@ -5,3 +5,22 @@ export function limitString(text: string) {
export function getRandomNumber(range: number): number {
return Math.floor(Math.random() * range) + 1;
}
export function formatCurrency(num: number): string {
return Intl.NumberFormat("en-US", {
style: "currency",
currency: "USD",
// These options can be used to round to whole numbers.
trailingZeroDisplay: "stripIfInteger", // This is probably what most people
// want. It will only stop printing
// the fraction when the input
// amount is a round number (int)
// already. If that's not what you
// need, have a look at the options
// below.
//minimumFractionDigits: 0, // This suffices for whole numbers, but will
// print 2500.10 as $2,500.1
//maximumFractionDigits: 0, // Causes 2500.99 to be printed as $2,501
}).format(num);
}