Properties Page
Last updated
Last updated
// properties.json
[
{
"_id": "1",
"owner": "1",
"name": "Boston Commons Retreat",
"type": "Apartment",
"description": "This is a beautiful apartment located near the commons. It is a 2 bedroom apartment with a full kitchen and bathroom. It is available for weekly or monthly rentals.",
"location": {
"street": "120 Tremont Street",
"city": "Boston",
"state": "MA",
"zipcode": "02108"
},
"beds": 2,
"baths": 1,
"square_feet": 1500,
"amenities": [
"Wifi",
"Full kitchen",
"Washer & Dryer",
"Free Parking",
"Hot Tub",
"24/7 Security",
"Wheelchair Accessible",
"Elevator Access",
"Dishwasher",
"Gym/Fitness Center",
"Air Conditioning",
"Balcony/Patio",
"Smart TV",
"Coffee Maker"
],
"rates": {
"weekly": 1100,
"monthly": 4200
},
"seller_info": {
"name": "John Doe",
"email": "john@gmail.com",
"phone": "617-555-5555"
},
"images": ["a1.jpg", "a2.jpg", "a3.jpg"],
"is_featured": false,
"createdAt": "2024-01-01T00:00:00.000Z",
"updatedAt": "2024-01-01T00:00:00.000Z"
},
{
"_id": "2",
"owner": "1",
"name": "Cozy Downtown Loft",
"type": "Apartment",
"description": "A cozy downtown loft with great city views.",
"location": {
"street": "45 Main Street",
"city": "New York",
"state": "NY",
"zipcode": "10001"
},
"beds": 1,
"baths": 1,
"square_feet": 1800,
"amenities": [
"Wifi",
"Full kitchen",
"Washer & Dryer",
"Free Parking",
"Hot Tub",
"24/7 Security",
"Wheelchair Accessible",
"Elevator Access",
"Dishwasher",
"High-Speed Internet",
"Air Conditioning",
"Smart TV",
"Outdoor Grill/BBQ"
],
"rates": {
"weekly": 1000,
"monthly": 4000
},
"seller_info": {
"name": "Jane Smith",
"email": "jane@gmail.com",
"phone": "212-555-5555"
},
"images": ["b1.jpg", "b2.jpg", "b3.jpg"],
"is_featured": false,
"createdAt": "2024-01-02T00:00:00.000Z",
"updatedAt": "2024-01-02T00:00:00.000Z"
},
{
"_id": "3",
"owner": "2",
"name": "Luxury Condo with a View",
"type": "Condo",
"description": "Experience luxury in this stunning condo with breathtaking views.",
"location": {
"street": "500 Lux Lane",
"city": "Los Angeles",
"state": "CA",
"zipcode": "90001"
},
"beds": 3,
"baths": 2,
"square_feet": 2200,
"amenities": [
"Wifi",
"Full kitchen",
"Washer & Dryer",
"Free Parking",
"Hot Tub",
"24/7 Security",
"Wheelchair Accessible",
"Elevator Access",
"Dishwasher",
"Swimming Pool",
"Gym/Fitness Center",
"Air Conditioning",
"Smart TV",
"Coffee Maker"
],
"rates": {
"nightly": 200,
"weekly": 750,
"monthly": 3300
},
"seller_info": {
"name": "David Johnson",
"email": "david@gmail.com",
"phone": "213-555-5555"
},
"images": ["c1.jpg", "c2.jpg", "c3.jpg"],
"is_featured": false,
"createdAt": "2024-01-03T00:00:00.000Z",
"updatedAt": "2024-01-03T00:00:00.000Z"
},
{
"_id": "4",
"owner": "2",
"name": "Charming Cottage Getaway",
"type": "Cottage Or Cabin",
"description": "Escape to this charming cottage for a peaceful retreat.",
"location": {
"street": "123 Countryside Lane",
"city": "Austin",
"state": "TX",
"zipcode": "78701"
},
"beds": 1,
"baths": 1,
"square_feet": 900,
"amenities": [
"Fireplace",
"Outdoor Grill/BBQ",
"Balcony/Patio",
"Coffee Maker"
],
"rates": {
"weekly": 2000
},
"seller_info": {
"name": "Emily Davis",
"email": "emily@gmail.com",
"phone": "512-555-5555"
},
"images": ["d1.jpg", "d2.jpg", "d3.jpg"],
"is_featured": false,
"createdAt": "2024-01-04T00:00:00.000Z",
"updatedAt": "2024-01-04T00:00:00.000Z"
},
{
"_id": "5",
"owner": "3",
"name": "Modern Downtown Studio",
"type": "Studio",
"description": "Stay in style in this modern downtown studio apartment.",
"location": {
"street": "75 Urban Avenue",
"city": "Chicago",
"state": "IL",
"zipcode": "60601"
},
"beds": 1,
"baths": 1,
"square_feet": 900,
"amenities": [
"High-Speed Internet",
"Smart TV",
"Air Conditioning",
"Gym/Fitness Center",
"Outdoor Grill/BBQ"
],
"rates": {
"weekly": 1100,
"monthly": 4200
},
"seller_info": {
"name": "Michael Brown",
"email": "michael@gmail.com",
"phone": "312-555-5555"
},
"images": ["e1.jpg", "e2.jpg", "e3.jpg"],
"is_featured": true,
"createdAt": "2024-01-05T00:00:00.000Z",
"updatedAt": "2024-01-05T00:00:00.000Z"
},
{
"_id": "6",
"owner": "3",
"name": "Seaside Retreat",
"type": "House",
"description": "Escape to this seaside house for a relaxing getaway.",
"location": {
"street": "456 Oceanfront Drive",
"city": "Miami",
"state": "FL",
"zipcode": "33101"
},
"beds": 4,
"baths": 3,
"square_feet": 2800,
"amenities": [
"Beach Access",
"Swimming Pool",
"Balcony/Patio",
"Smart TV",
"Outdoor Grill/BBQ"
],
"rates": {
"nightly": 500,
"weekly": 2500
},
"seller_info": {
"name": "Sarah Wilson",
"email": "sarah@gmail.com",
"phone": "305-555-5555"
},
"images": ["f1.jpg", "f2.jpg", "f3.jpg"],
"is_featured": true,
"createdAt": "2024-01-06T00:00:00.000Z",
"updatedAt": "2024-01-06T00:00:00.000Z"
},
{
"_id": "7",
"owner": "4",
"name": "Rustic Cabin in the Woods",
"type": "Cottage Or Cabin",
"description": "Experience nature in this cozy rustic cabin.",
"location": {
"street": "789 Forest Lane",
"city": "Denver",
"state": "CO",
"zipcode": "80201"
},
"beds": 2,
"baths": 1,
"square_feet": 1100,
"amenities": [
"Fireplace",
"Outdoor Grill/BBQ",
"Hiking Trails Access",
"Pet-Friendly"
],
"rates": {
"nightly": 475,
"weekly": 2000
},
"seller_info": {
"name": "Robert Anderson",
"email": "robert@gmail.com",
"phone": "303-555-5555"
},
"images": ["g1.jpg", "g2.jpg", "g3.jpg"],
"is_featured": false,
"createdAt": "2024-01-07T00:00:00.000Z",
"updatedAt": "2024-01-07T00:00:00.000Z"
},
{
"_id": "8",
"owner": "5",
"name": "Ski-In/Ski-Out Chalet",
"type": "Chalet",
"description": "Hit the slopes from this cozy ski-in/ski-out chalet.",
"location": {
"street": "321 Mountain Road",
"city": "Aspen",
"state": "CO",
"zipcode": "81611"
},
"beds": 3,
"baths": 2,
"square_feet": 1800,
"amenities": [
"Ski Equipment Storage",
"Fireplace",
"Balcony/Patio",
"Smart TV"
],
"rates": {
"nightly": 300,
"weekly": 1100
},
"seller_info": {
"name": "Jennifer Martin",
"email": "jennifer@gmail.com",
"phone": "970-555-5555"
},
"images": ["h1.jpg", "h2.jpg", "h3.jpg"],
"is_featured": false,
"createdAt": "2024-01-08T00:00:00.000Z",
"updatedAt": "2024-01-08T00:00:00.000Z"
},
{
"_id": "9",
"owner": "6",
"name": "Mountain View Retreat",
"type": "House",
"description": "Enjoy stunning mountain views from this spacious retreat.",
"location": {
"street": "600 Summit Drive",
"city": "Boulder",
"state": "CO",
"zipcode": "80301"
},
"beds": 4,
"baths": 3,
"square_feet": 2400,
"amenities": [
"Mountain View",
"Hiking Trails Access",
"Air Conditioning",
"Smart TV",
"Outdoor Grill/BBQ"
],
"rates": {
"weekly": 1000,
"monthly": 3800
},
"seller_info": {
"name": "Lisa Taylor",
"email": "lisa@gmail.com",
"phone": "303-555-5555"
},
"images": ["i1.jpg", "i2.jpg", "i3.jpg"],
"is_featured": false,
"createdAt": "2024-01-09T00:00:00.000Z",
"updatedAt": "2024-01-09T00:00:00.000Z"
},
{
"_id": "10",
"owner": "7",
"name": "Historic Downtown Loft",
"type": "Apartment",
"description": "Step back in time with a stay in this historic downtown loft.",
"location": {
"street": "123 History Lane",
"city": "Philadelphia",
"state": "PA",
"zipcode": "19101"
},
"beds": 2,
"baths": 1,
"square_feet": 1200,
"amenities": [
"High-Speed Internet",
"Air Conditioning",
"Smart TV",
"Coffee Maker"
],
"rates": {
"weekly": 550,
"monthly": 2100
},
"seller_info": {
"name": "Matthew Harris",
"email": "matthew@gmail.com",
"phone": "215-555-5555"
},
"images": ["j1.jpg", "j2.jpg", "j3.jpg"],
"is_featured": false,
"createdAt": "2024-01-10T00:00:00.000Z",
"updatedAt": "2024-01-10T00:00:00.000Z"
}
]
Create properties images folder in public folder as follows: public>images>properties and then add all images in images>properties folder
a. Update the Properties Page File
In your Next.js project, update a Page.jsx file for the properties page. For example:
app/properties/page.jsx
This file will serve as the main page where all property listings are displayed.
Place your properties.json
file in an accessible location (e.g., in the project root or in a /data
folder).
In your page.jsx
file, import the JSON data:
//app/properties/page.jsx
//import Link from 'next/link'
import properties from '@/properties.json'; // Adjust the path as needed
function Properties() {
return (
<>
{/* <h1 className="text-3xl"> Welcome to Property Page </h1>
<Link href="/"> Go to Home </Link> */}
</>
)
}
export default Properties
find <!— All Listings --> comment section and just copy first three lines of code and past them to page,jsx
// properties.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css"
integrity="sha512-DTOQO9RWCH3ppGqcWaEA1BIZOC6xxalwEsw9c2QQeAIftl+Vegovlnee1c9QX4TctnWMn13TZye+giMm8e2LwA=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<link rel="stylesheet" href="css/styles.css" />
<link rel="icon" type="image/png" href="favicon.ico" />
<title>Property Pulse | Find local rental properties</title>
</head>
<body>
<nav class="bg-blue-700 border-b border-blue-500">
<div class="mx-auto max-w-7xl px-2 sm:px-6 lg:px-8">
<div class="relative flex h-20 items-center justify-between">
<div class="absolute inset-y-0 left-0 flex items-center md:hidden">
<!-- Mobile menu button-->
<button
type="button"
id="mobile-dropdown-button"
class="relative inline-flex items-center justify-center rounded-md p-2 text-gray-400 hover:bg-gray-700 hover:text-white focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white"
aria-controls="mobile-menu"
aria-expanded="false"
>
<span class="absolute -inset-0.5"></span>
<span class="sr-only">Open main menu</span>
<svg
class="block h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5"
/>
</svg>
</button>
</div>
<div
class="flex flex-1 items-center justify-center md:items-stretch md:justify-start"
>
<!-- Logo -->
<a class="flex flex-shrink-0 items-center" href="/index.html">
<img
class="h-10 w-auto"
src="/images/logo-white.png"
alt="PropertyPulse"
/>
<span class="hidden md:block text-white text-2xl font-bold ml-2"
>PropertyPulse</span
>
</a>
<!-- Desktop Menu Hidden below md screens -->
<div class="hidden md:ml-6 md:block">
<div class="flex space-x-2">
<a
href="/index.html"
class="text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2"
>Home</a
>
<a
href="/properties.html"
class="text-white bg-black hover:bg-gray-900 hover:text-white rounded-md px-3 py-2"
>Properties</a
>
<a
href="/add-property.html"
class="text-white hover:bg-gray-900 hover:text-white rounded-md px-3 py-2"
>Add Property</a
>
</div>
</div>
</div>
<!-- Right Side Menu (Logged Out) -->
<div class="hidden md:block md:ml-6">
<div class="flex items-center">
<button
class="flex items-center text-white bg-gray-700 hover:bg-gray-900 hover:text-white rounded-md px-3 py-2"
>
<i class="fa-brands fa-google text-white mr-2"></i>
<span>Login or Register</span>
</button>
</div>
</div>
<!-- Right Side Menu (Logged In) -->
<div
class="absolute inset-y-0 right-0 flex items-center pr-2 md:static md:inset-auto md:ml-6 md:pr-0"
>
<a href="messages.html" class="relative group">
<button
type="button"
class="relative rounded-full bg-gray-800 p-1 text-gray-400 hover:text-white focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
>
<span class="absolute -inset-1.5"></span>
<span class="sr-only">View notifications</span>
<svg
class="h-6 w-6"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
aria-hidden="true"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0"
/>
</svg>
</button>
<span
class="absolute top-0 right-0 inline-flex items-center justify-center px-2 py-1 text-xs font-bold leading-none text-white transform translate-x-1/2 -translate-y-1/2 bg-red-600 rounded-full"
>
2
<!-- Replace with the actual number of notifications -->
</span>
</a>
<!-- Profile dropdown button -->
<div class="relative ml-3">
<div>
<button
type="button"
class="relative flex rounded-full bg-gray-800 text-sm focus:outline-none focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-800"
id="user-menu-button"
aria-expanded="false"
aria-haspopup="true"
>
<span class="absolute -inset-1.5"></span>
<span class="sr-only">Open user menu</span>
<img
class="h-8 w-8 rounded-full"
src="/images/profile.png"
alt=""
/>
</button>
</div>
<!-- Profile dropdown -->
<div
id="user-menu"
class="hidden absolute right-0 z-10 mt-2 w-48 origin-top-right rounded-md bg-white py-1 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
role="menu"
aria-orientation="vertical"
aria-labelledby="user-menu-button"
tabindex="-1"
>
<a
href="/profile.html"
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem"
tabindex="-1"
id="user-menu-item-0"
>Your Profile</a
>
<a
href="saved-properties.html"
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem"
tabindex="-1"
id="user-menu-item-2"
>Saved Properties</a
>
<a
href="#"
class="block px-4 py-2 text-sm text-gray-700"
role="menuitem"
tabindex="-1"
id="user-menu-item-2"
>Sign Out</a
>
</div>
</div>
</div>
</div>
</div>
<!-- Mobile menu, show/hide based on menu state. -->
<div class="hidden" id="mobile-menu">
<div class="space-y-1 px-2 pb-3 pt-2">
<a
href="/index.html"
class="text-gray-300 block rounded-md px-3 py-2 text-base font-medium"
>Home</a
>
<a
href="/properties.html"
class="bg-gray-900 text-white hover:bg-gray-700 hover:text-white block rounded-md px-3 py-2 text-base font-medium"
>Properties</a
>
<a
href="/add-property.html"
class="text-gray-300 hover:bg-gray-700 hover:text-white block rounded-md px-3 py-2 text-base font-medium"
>Add Property</a
>
<button
class="flex items-center text-white bg-gray-700 hover:bg-gray-900 hover:text-white rounded-md px-3 py-2 my-4"
>
<i class="fa-brands fa-google mr-2"></i>
<span>Login or Register</span>
</button>
</div>
</div>
</nav>
<!-- Search -->
<section class="bg-blue-700 py-4">
<div
class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col items-start"
>
<!-- Form Component -->
<form
class="mt-3 mx-auto max-w-2xl w-full flex flex-col md:flex-row items-center"
>
<div class="w-full md:w-3/5 md:pr-2 mb-4 md:mb-0">
<label for="location" class="sr-only">Location</label>
<input
type="text"
id="location"
placeholder="Enter Location (City, State, Zip, etc"
class="w-full px-4 py-3 rounded-lg bg-white text-gray-800 focus:outline-none focus:ring focus:ring-blue-500"
/>
</div>
<div class="w-full md:w-2/5 md:pl-2">
<label for="property-type" class="sr-only">Property Type</label>
<select
id="property-type"
class="w-full px-4 py-3 rounded-lg bg-white text-gray-800 focus:outline-none focus:ring focus:ring-blue-500"
>
<option value="All">All</option>
<option value="Apartment">Apartment</option>
<option value="Studio">Studio</option>
<option value="Condo">Condo</option>
<option value="House">House</option>
<option value="Cabin Or Cottage">Cabin or Cottage</option>
<option value="Loft">Loft</option>
<option value="Room">Room</option>
<option value="Other">Other</option>
</select>
</div>
<button
type="submit"
class="md:ml-4 mt-4 md:mt-0 w-full md:w-auto px-6 py-3 rounded-lg bg-blue-500 text-white hover:bg-blue-600 focus:outline-none focus:ring focus:ring-blue-500"
>
Search
</button>
</form>
</div>
</section>
<!-- All Listings -->
<section class="px-4 py-6">
<div class="container-xl lg:container m-auto px-4 py-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
<!-- Listing 1 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/a1.jpg"
alt=""
class='w-full h-auto rounded-t-xl'
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">Apartment</div>
<h3 class="text-xl font-bold">Boston Commons Retreat</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$4,200/mo
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 3
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 2
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
1,500 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
<p><i class="fa-solid fa-money-bill"></i> Monthly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between mb-4">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> Boston MA </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
<!-- Listing 2 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/b1.jpg"
alt=""
class="object-cover rounded-t-xl"
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">Loft</div>
<h3 class="text-xl font-bold">Cozy Downtown Loft</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$4,000/mo
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 2
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 2
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
1,800 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
<p><i class="fa-solid fa-money-bill"></i> Monthly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between mb-4">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> New York NY </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
<!-- Listing 3 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/c1.jpg"
alt=""
class="object-cover rounded-t-xl"
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">Condo</div>
<h3 class="text-xl font-bold">Luxury Condo</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$3,300/mo
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 3
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 2
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
2,200 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Nightly</p>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
<p><i class="fa-solid fa-money-bill"></i> Monthly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between mb-4">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> Los Angeles CA </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
<!-- Listing 4 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/d1.jpg"
alt=""
class="object-cover rounded-t-xl"
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">Cottage or Cabin</div>
<h3 class="text-xl font-bold">Charming Cottage Getaway</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$2,000/wk
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 2
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 1
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
900 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> Austin TX </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
<!-- Listing 5 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/e1.jpg"
alt=""
class="object-cover rounded-t-xl"
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">Studio</div>
<h3 class="text-xl font-bold">Modern Downtown Studio</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$4,200/mo
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 1
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 1
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
900 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
<p><i class="fa-solid fa-money-bill"></i> Monthly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between mb-4">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> Chicago IL </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
<!-- Listing 6 -->
<div class="rounded-xl shadow-md relative">
<img
src="images/properties/f1.jpg"
alt=""
class="object-cover rounded-t-xl"
/>
<div class="p-4">
<div class="text-left md:text-center lg:text-left mb-6">
<div class="text-gray-600">House</div>
<h3 class="text-xl font-bold">Seaside Retreat</h3>
</div>
<h3
class="absolute top-[10px] right-[10px] bg-white px-4 py-2 rounded-lg text-blue-500 font-bold text-right md:text-center lg:text-right"
>
$2,500/wk
</h3>
<div class="flex justify-center gap-4 text-gray-500 mb-4">
<p>
<i class="fa-solid fa-bed"></i> 4
<span class="md:hidden lg:inline">Beds</span>
</p>
<p>
<i class="fa-solid fa-bath"></i> 3
<span class="md:hidden lg:inline">Baths</span>
</p>
<p>
<i class="fa-solid fa-ruler-combined"></i>
2,800 <span class="md:hidden lg:inline">sqft</span>
</p>
</div>
<div
class="flex justify-center gap-4 text-green-900 text-sm mb-4"
>
<p><i class="fa-solid fa-money-bill"></i> Weekly</p>
<p><i class="fa-solid fa-money-bill"></i> Monthly</p>
</div>
<div class="border border-gray-100 mb-5"></div>
<div class="flex flex-col lg:flex-row justify-between mb-4">
<div class="flex align-middle gap-2 mb-4 lg:mb-0">
<i
class="fa-solid fa-location-dot text-lg text-orange-700"
></i>
<span class="text-orange-700"> Miami FL </span>
</div>
<a
href="property.html"
class="h-[36px] bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-center text-sm"
>
Details
</a>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Pagination -->
<section class="container mx-auto flex justify-center items-center my-8">
<button class="mr-2 px-2 py-1 border border-gray-300 rounded">
Previous
</button>
<span class='mx-2'>
Page 1 of 10
</span>
<button
class='ml-2 px-2 py-1 border border-gray-300 rounded'>
Next
</button>
</section>
<!-- Footer -->
<footer class="bg-gray-200 py-4 mt-auto">
<div
class="container mx-auto flex flex-col md:flex-row items-center justify-between px-4"
>
<div class="mb-4 md:mb-0">
<img src="/images/logo.png" alt="Logo" class="h-8 w-auto" />
</div>
<div
class="flex flex-wrap justify-center md:justify-start mb-4 md:mb-0"
>
<ul class="flex space-x-4">
<li><a href="/properties.html">Properties</a></li>
<li><a href="/terms.html">Terms of Service</a></li>
</ul>
</div>
<div>
<p class="text-sm text-gray-500 mt-2 md:mt-0">
© 2024 PropertyPulse. All rights reserved.
</p>
</div>
</div>
</footer>
<script src="js/main.js"></script>
</body>
</html>
//app/properties/page.jsx
//import Link from 'next/link'
import properties from '@/properties.json'; // Adjust the path as needed
function Properties() {
return (
<>
<section class="px-4 py-6">
<div class="container-xl lg:container m-auto px-4 py-6">
<div class="grid grid-cols-1 md:grid-cols-3 gap-6">
</div>
</div>
</section>
</>
)
}
export default Properties
Start by creating a section element that holds your property listings. You can copy the outer container markup from your theme file:
import properties from '@/properties.json'; // Adjust the path as needed
function Properties() {
return (
<section className="container mx-auto px-4 py-6">
<h2 className="text-3xl font-bold text-blue-500 mb-6 text-center">All Listings</h2>
{/* Listings grid will go here */}
{properties.map((property) => (
<div> {property.name} </div>
))}
</section>
);
}
export default Properties
Before rendering the listings, check if the properties array is empty and display a message if so:
import properties from '@/properties.json'; // Adjust the path as needed
function Properties() {
return (
<section className="container mx-auto px-4 py-6">
<h2 className="text-3xl font-bold text-blue-500 mb-6 text-center">All Listings</h2>
{properties.length === 0 ? (
<p>No properties found.</p>
) : (
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
{properties.map((property) => (
<p key={property._id}> {property.name} </p>
))}
</div>
)}
</section>
);
}
export default Properties
Use JavaScript’s .map()
to iterate through the properties array and render each listing as a card:
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
Insert this code inside the grid container from the previous step.
In the components/
folder, create a new file named PropertyCard.jsx
:
components/PropertyCard.jsx
Copy the relevant HTML markup for a property listing from your theme’s properties.html
(the markup between the listing divs) into PropertyCard.jsx
.
Modify the static content to dynamically display property data using the property
prop.
Example:
function PropertyCard({ property }) {
return (
<div className="bg-white rounded-xl shadow-md relative flex flex-col md:flex-row">
<img
src={`/images/properties/${property.images[0]}`} // Assuming the first image exists
alt={property.name}
className="object-cover rounded-t-xl md:rounded-tr-none md:rounded-l-xl w-full md:w-2/5"
/>
<div className="p-6">
<h3 className="text-xl font-bold">{property.name}</h3>
<div className="text-gray-600 mb-4">{property.type}</div>
{/* Display rates if available */}
{property.rates && (
<h3 className="absolute top-2 left-2 bg-white px-4 py-2 rounded-lg text-blue-500 font-bold">
{property.rates.nightly ? `$${property.rates.nightly}/wk` : 'Contact for rates'}
</h3>
)}
<div className="flex justify-between items-center">
<div className="flex gap-2 text-gray-500">
<p>
<i className="fa-solid fa-bed"></i> {property.beds}
</p>
<p>
<i className="fa-solid fa-bath"></i> {property.baths}
</p>
<p>
<i className="fa-solid fa-ruler-combined"></i> {property.squareFeet} sqft
</p>
</div>
<Link href={`/property/${property._id}`}>
<a className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg text-sm">
Details
</a>
</Link>
</div>
</div>
</div>
);
}
export default PropertyCard
Note: Adjust the paths and markup as needed to match your actual JSON structure and theme design.
In your app/properties/page.jsx
file, import the component at the top:
import PropertyCard from '@/components/PropertyCard';
Replace the placeholder div in your .map()
loop with the <PropertyCard />
component, passing the property data as props:
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{properties.map((property) => (
<PropertyCard key={property._id} property={property} />
))}
</div>
Since the properties data is coming from a static JSON file, you can leverage Next.js’s server components or static generation to render this page.
In Next.js 13+ with the app directory, pages are server components by default, which means the data is fetched at build time or request time and the page is rendered on the server.
Once you integrate an API or database, you can modify the data fetching strategy (e.g., using getStaticProps
or fetch
inside server components) without affecting your component structure.
Start your Next.js server:
npm run dev
Navigate to http://localhost:3000/properties and verify that:
The container displays a heading and the grid.
If there are no properties, the “No properties found” message appears.
Each property from your JSON data is rendered as a PropertyCard with dynamic content.
Refine the Tailwind CSS classes and layout to match your desired design.
Verify responsiveness on different screen sizes.
Properties Page Setup: Create a dedicated page that imports data from a JSON file and conditionally renders a grid of property listings.
Dynamic Rendering:
Use .map()
to iterate over the properties and render each one with a reusable PropertyCard component.
Component Reusability: Build a PropertyCard component that dynamically displays property details, leveraging the structure provided in your theme files.
Next.js Rendering: Leverage Next.js server components (default in the app folder) for efficient, server-side rendering of static data, with room for future API integration.